content: package ru.dimension.ui.component.chart;
  
  import java.awt.BorderLayout;
  import java.awt.Color;
  import java.util.Collection;
  import java.util.LinkedHashSet;
  import java.util.List;
  import java.util.Map;
  import java.util.Set;
  import javax.swing.JPanel;
  import lombok.Getter;
  import lombok.Setter;
  import lombok.extern.log4j.Log4j2;
  import org.jfree.chart.ChartFactory;
  import org.jfree.chart.ChartPanel;
  import org.jfree.chart.JFreeChart;
  import org.jfree.chart.axis.DateAxis;
  import org.jfree.chart.plot.PlotOrientation;
  import ru.dimension.db.core.DStore;
  import ru.dimension.db.model.output.StackedColumn;
  import ru.dimension.ui.Application;
  import ru.dimension.ui.component.chart.holder.DetailAndAnalyzeHolder;
  import ru.dimension.ui.exception.NotFoundException;
  import ru.dimension.ui.helper.ColorHelper;
  import ru.dimension.ui.laf.LaF;
  import ru.dimension.ui.laf.LafColorGroup;
  import ru.dimension.ui.model.ProfileTaskQueryKey;
  import ru.dimension.ui.model.config.Metric;
  import ru.dimension.ui.model.data.CategoryTableXYDatasetRealTime;
  import ru.dimension.ui.model.function.GroupFunction;
  import ru.dimension.ui.model.view.SeriesType;
  import ru.dimension.ui.state.SqlQueryState;
  
  @Log4j2
  public abstract class SCP extends JPanel implements HelperChart, DetailChart {
  
    @Getter
    protected final ChartConfig config;
  
    protected final CategoryTableXYDatasetRealTime chartDataset;
    protected final ProfileTaskQueryKey profileTaskQueryKey;
  
    protected StackedChart stackedChart;
    private JFreeChart jFreeChart;
  
    protected Set<String> series;
  
    @Setter
    protected SqlQueryState sqlQueryState;
    @Setter
    protected DStore dStore;
    @Getter
    protected SeriesType seriesType = SeriesType.COMMON;
  
    protected DetailAndAnalyzeHolder detailAndAnalyzeHolder;
  
    public SCP(ChartConfig config,
               ProfileTaskQueryKey profileTaskQueryKey) {
      this.config = config;
      this.profileTaskQueryKey = profileTaskQueryKey;
      this.chartDataset = new CategoryTableXYDatasetRealTime();
  
      if (config.getMetric().getYAxis().getCsType() == null) {
        throw new NotFoundException("Column storage type undefined: " + config.getMetric().getYAxis());
      }
  
      this.series = new LinkedHashSet<>();
  
      ColorHelper colorHelper = Application.getInstance().getColorHelper();
  
      createStackedChart(colorHelper);
      createColor(colorHelper);
    }
  
    protected void createStackedChart(ColorHelper colorHelper ) {
      this.stackedChart = new StackedChart(getChartPanel(this.chartDataset), colorHelper);
      this.stackedChart.setLegendFontSize(config.getLegendFontSize());
      this.stackedChart.initialize();
  
      LaF.setBackgroundAndTextColorForStackedChartPanel(LafColorGroup.CHART_PANEL, this.stackedChart);
    }
  
    protected void createColor(ColorHelper colorHelper) {
      GroupFunction groupFunction = config.getMetric().getGroupFunction();
      if (groupFunction == GroupFunction.SUM || groupFunction == GroupFunction.AVG) {
        String columnName = config.getMetric().getYAxis().getColName();
        Color color = colorHelper.getColor(profileTaskQueryKey.getColorProfileName(), columnName);
  
        loadSeriesColorExternal(Map.of(columnName, color));
        loadSeriesColorInternal(columnName);
      }
    }
  
    protected ChartPanel getChartPanel(CategoryTableXYDatasetRealTime dataset) {
      DateAxis dateAxis = new DateAxis();
      jFreeChart = ChartFactory.createStackedXYAreaChart(config.getTitle(),
                                                         config.getXAxisLabel(),
                                                         config.getYAxisLabel(),
                                                         dataset,
                                                         PlotOrientation.VERTICAL,
                                                         dateAxis,
                                                         config.isLegend(),
                                                         config.isTooltips(),
                                                         config.isUrls());
  
      return new ChartPanel(jFreeChart, true, true, true, false, true);
    }
  
    public abstract void initialize();
  
    public abstract void loadData();
  
    public void loadSeriesColor(Metric metric, Map<String, Color> seriesColorMap) {
      if (GroupFunction.COUNT.equals(metric.getGroupFunction())) {
        log.info("Try to load series color from the main chart");
  
        if (seriesColorMap == null || seriesColorMap.isEmpty()) {
          log.info("Empty series color map");
        } else {
          loadSeriesColorExternal(seriesColorMap);
        }
      }
    }
  
    public void loadSeriesColorExternal(Map<String, Color> seriesColorMap) {
      seriesColorMap.forEach((seriesName, color) -> this.stackedChart.loadExternalSeriesColor(seriesName, color));
    }
  
    public void loadSeriesColorInternal(String seriesName) {
      this.stackedChart.loadSeriesColorInternal(profileTaskQueryKey.getColorProfileName(), seriesName);
    }
  
    protected void initializeGUI() {
      this.setLayout(new BorderLayout());
      this.add(stackedChart.getChartPanel(), BorderLayout.CENTER);
    }
  
    protected void initializeDateAxis(long begin, long end ) {
      this.stackedChart.setDateAxis(begin, end);
    }
  
    public Map<String, Color> getSeriesColorMap() {
      return stackedChart.getSeriesColorMap();
    }
  
    public CategoryTableXYDatasetRealTime getChartDataset() {
      return chartDataset;
    }
  
    protected void fillSeriesAnalyze(List<StackedColumn> sColumnList) {
      if (GroupFunction.COUNT.equals(config.getMetric().getGroupFunction())) {
        sColumnList.stream()
            .map(StackedColumn::getKeyCount)
            .map(Map::keySet)
            .flatMap(Collection::stream)
            .forEach(series::add);
      } else if (GroupFunction.SUM.equals(config.getMetric().getGroupFunction())) {
        sColumnList.stream()
            .map(StackedColumn::getKeySum)
            .map(Map::keySet)
            .flatMap(Collection::stream)
            .forEach(series::add);
      } else if (GroupFunction.AVG.equals(config.getMetric().getGroupFunction())) {
        sColumnList.stream()
            .map(StackedColumn::getKeyAvg)
            .map(Map::keySet)
            .flatMap(Collection::stream)
            .forEach(series::add);
      } else {
        sColumnList.stream()
            .map(StackedColumn::getKeyCount)
            .map(Map::keySet)
            .flatMap(Collection::stream)
            .forEach(series::add);
      }
    }
  
    public boolean hasNonEmptyKeyCount(List<StackedColumn> sColumnList) {
      return sColumnList.stream()
          .anyMatch(sColumn -> sColumn != null &&
              sColumn.getKeyCount() != null &&
              !sColumn.getKeyCount().isEmpty());
    }
  
    public JFreeChart getjFreeChart() {
      return jFreeChart;
    }
  
    public void clearSelectionRegion() {
      stackedChart.clearSelectionRegion();
    }
  
    public void setChartTitle(String titleText) {
      this.stackedChart.setChartTitle(titleText);
    }
  
    protected void disablePlotUpdates() {
      stackedChart.setNotifyPlot(false);
    }
  
    protected void enablePlotUpdates() {
      stackedChart.setNotifyPlot(true);
    }
  
    public void clearSeriesColor() {
      this.stackedChart.clearSeriesColor();
    }
  
    public void setHolderDetailsAndAnalyze(DetailAndAnalyzeHolder detailAndAnalyzeHolder) {
      this.detailAndAnalyzeHolder = detailAndAnalyzeHolder;
    }
  }
  