package com.griddynamics.jagger.dbapi.util;
import com.google.common.collect.ImmutableList;
import com.griddynamics.jagger.util.MonitoringIdUtils;
import java.awt.Color;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;
import static java.math.BigDecimal.ONE;
import static java.math.BigDecimal.ZERO;
import static java.util.Collections.singletonList;
import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
public class ColorCodeGenerator {
private static AtomicInteger counter = new AtomicInteger(0);
private static ConcurrentMap<String, Integer> sessionsMap = new ConcurrentHashMap<>();
private static final ImmutableList<String> COLORS_HEX_CODES = ImmutableList.copyOf(generateColors());
public static String getHexColorCode(String metricId, String sessionId) {
return getHexColorCode(singletonList(metricId), sessionId);
}
private static String getHexColorCode(List<String> metricIds, String sessionId) {
List<String> colorIds = new ArrayList<>();
if (isNotEmpty(metricIds)) {
// Search if metricId or its synonyms already has color
for (String metricId : metricIds) {
MonitoringIdUtils.MonitoringId monitoringId = MonitoringIdUtils.splitMonitoringMetricId(metricId);
String colorId = (monitoringId != null) ? (monitoringId.getMonitoringName() + sessionId) : (metricId + sessionId);
colorIds.add(colorId);
// Color found
if (sessionsMap.containsKey(colorId)) {
Integer indexInColorsHexCodes = sessionsMap.get(colorId);
for (String colourId : colorIds) {
sessionsMap.put(colourId, indexInColorsHexCodes);
}
return COLORS_HEX_CODES.get(indexInColorsHexCodes);
}
}
}
// Color was not set before
int indexInColorsHexCodes = counter.getAndIncrement() % COLORS_HEX_CODES.size();
for (String colourId : colorIds) {
sessionsMap.put(colourId, indexInColorsHexCodes);
}
return COLORS_HEX_CODES.get(indexInColorsHexCodes);
}
private static List<String> generateColors() {
List<String> colors = new ArrayList<>();
// These vars are needed for equal distribution of colors
final BigDecimal brightnessSteps = new BigDecimal(2);
final BigDecimal saturationSteps = new BigDecimal(1);
final BigDecimal hueSteps = new BigDecimal(15);
final BigDecimal brightnessStep = new BigDecimal("0.5").divide(brightnessSteps, 2, RoundingMode.HALF_UP);
final BigDecimal saturationStep = new BigDecimal("0.6").divide(saturationSteps, 2, RoundingMode.HALF_UP);
final BigDecimal hueStep = ONE.divide(hueSteps, 8, RoundingMode.HALF_UP);
final BigDecimal brightnessLimit = new BigDecimal("0.5");
final BigDecimal saturationLimit = new BigDecimal("0.4");
for (BigDecimal brightness = ONE; brightness.compareTo(brightnessLimit) == 1; ) {
for (BigDecimal saturation = ONE; saturation.compareTo(saturationLimit) >= 0; ) {
for (BigDecimal hue = ZERO; hue.compareTo(ONE) < 1; ) {
Color hsbColor = Color.getHSBColor(hue.floatValue(), saturation.floatValue(), brightness.floatValue());
colors.add(getHexCodeOfColor(hsbColor));
hue = hue.add(hueStep);
}
saturation = saturation.subtract(saturationStep);
}
brightness = brightness.subtract(brightnessStep);
}
return shuffle(colors);
}
private static List<String> shuffle(List<String> colors) {
List<String> shuffled = new ArrayList<>(colors.size());
int counter = 0;
int localCounter = 0;
while (shuffled.size() < colors.size()) {
String colorToInsert = colors.get(localCounter % colors.size());
if (!shuffled.contains(colorToInsert)) {
shuffled.add(counter, colorToInsert);
counter++;
localCounter += 3;
} else {
localCounter++;
}
}
return shuffled;
}
private static String getHexCodeOfColor(Color color) {
return String.format("#%02x%02x%02x", color.getRed(), color.getGreen(), color.getBlue()).toUpperCase();
}
}