class DefaultStateChartReducer implements StateChartReducer<T> {

  @Override
  public void reduce(@NotNull List<Rectangle2D.Float> rectangles, @NotNull List<T> values) {
    int index = 0, keepIndex = 0;
    Map<T, Float> occurrenceWidth = new HashMap<>();

    while (index < rectangles.size()) {
      T value = values.get(index);
      Rectangle2D.Float rect = rectangles.get(index);

      // Crossing several pixels, let's just keep it
      if (Math.floor(rect.x) < Math.floor(rect.x + rect.width)) {
        rectangles.set(keepIndex, rect);
        values.set(keepIndex, value);
        ++keepIndex;
        ++index;
        continue;
      }

      occurrenceWidth.clear();

      // Whole rectangle is within the pixel
      float pixelStart = (float)Math.floor(rect.x);
      float pixelEnd = pixelStart + 1.0f;

      float minX = rect.x;
      float maxX = Float.MIN_VALUE;
      float minY = rect.y;
      float height = rect.height;

      while (index < rectangles.size()) {
        rect = rectangles.get(index);

        if (rect.x < pixelStart || rect.x > pixelEnd || rect.x + rect.width > pixelEnd) {
          // Crossed different pixel
          break;
        }
        maxX = rect.x + rect.width;

        value = values.get(index);
        Float width = occurrenceWidth.get(value);
        occurrenceWidth.put(value, (width == null ? 0 : width) + rect.width);
        ++index;
      }

      T mostOccurred = null;
      float mostOccurredWidth = -1;
      for (Map.Entry<T, Float> entry : occurrenceWidth.entrySet()) {
        if (entry.getValue() > mostOccurredWidth) {
          mostOccurredWidth = entry.getValue().floatValue();
          mostOccurred = entry.getKey();
        }
      }

      if (mostOccurred != null) {
        values.set(keepIndex, mostOccurred);
        // As width of the new rectangle smaller than 1px, arcWidth and arcHeight won't make any difference
        // thus, drawing "Rectangle2D" instead of "RoundRectangle2D"
        rectangles.set(keepIndex, new Rectangle2D.Float(minX, minY, maxX - minX, height));
        ++keepIndex;
      }
    }

    rectangles.subList(keepIndex, rectangles.size()).clear();
    values.subList(keepIndex, values.size()).clear();
  }

}