package com.xinyilu.common.utils.jreechart;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartUtils;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.StandardChartTheme;
import org.jfree.chart.axis.CategoryAxis;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.block.BlockBorder;
import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
import org.jfree.chart.plot.CategoryPlot;
import org.jfree.chart.renderer.category.CategoryItemRenderer;
import org.jfree.chart.ui.RectangleEdge;

import java.awt.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.text.NumberFormat;
import java.util.List;
import java.util.Objects;

/**
 * @Description 生成柱状图工具类
 * @Author 纪寒
 * @Date 2022-09-22 16:44:00
 * @Version 1.0
 */
@Slf4j
public class GenerateBarChartUtil {
    /**
     * 生成柱状图(返回byte[])
     *
     * @param chartTitle      图表标题
     * @param legendNameList  图例名称列表
     * @param xAxisNameList   x轴名称列表
     * @param dataList        数据列表
     * @param theme           主题(null代表默认主题)
     * @param yAxisTitle      y轴标题
     * @param xAxisTitle      x轴标题
     * @param width           宽度
     * @param height          高度
     * @param yAxisMinValue   y轴最小值（可以为空）
     * @param yAxisMaxValue   y轴最大值（可以为空）
     * @param legendColorList 图例背景颜色（可以为空）
     * @param barLabelVisible 是否显示柱体标签（可以为空）
     * @param barLabelFormat  柱体标签格式（可以为空）
     * @return 字节数组
     */
    public static byte[] createBarChart(String chartTitle, List<String> legendNameList, List<String> xAxisNameList,
                                        List<List<Object>> dataList, StandardChartTheme theme, String yAxisTitle,
                                        String xAxisTitle, int width, int height, Double yAxisMinValue,
                                        Double yAxisMaxValue, List<Color> legendColorList, Boolean barLabelVisible,
                                        String barLabelFormat) {
        ByteArrayOutputStream bas = new ByteArrayOutputStream();
        createBarChart(bas, chartTitle, legendNameList, xAxisNameList, dataList, theme, yAxisTitle, xAxisTitle, width, height
                , yAxisMinValue, yAxisMaxValue, legendColorList, barLabelVisible, barLabelFormat);
        return bas.toByteArray();
    }

    /**
     * 生成柱状图(返回outputStream)
     *
     * @param chartTitle      图表标题
     * @param legendNameList  图例名称列表
     * @param xAxisNameList   x轴名称列表
     * @param dataList        数据列表
     * @param theme           主题(null代表默认主题)
     * @param yAxisTitle      y轴标题
     * @param xAxisTitle      x轴标题
     * @param outputStream    输出流
     * @param width           宽度
     * @param height          高度
     * @param yAxisMinValue   y轴最小值（可以为空）
     * @param yAxisMaxValue   y轴最大值（可以为空）
     * @param legendColorList 图例背景颜色（可以为空）
     * @param barLabelVisible 是否显示柱体标签（可以为空）
     * @param barLabelFormat  柱体标签格式（可以为空）
     */
    public static void createBarChart(OutputStream outputStream, String chartTitle,
                                      List<String> legendNameList, List<String> xAxisNameList,
                                      List<List<Object>> dataList, StandardChartTheme theme, String yAxisTitle,
                                      String xAxisTitle, int width, int height, Double yAxisMinValue,
                                      Double yAxisMaxValue, List<Color> legendColorList,
                                      Boolean barLabelVisible, String barLabelFormat) {
        //生成柱状图
        JFreeChart chart = createBarChart(chartTitle, legendNameList, xAxisNameList, dataList,
                theme, yAxisTitle, xAxisTitle, yAxisMinValue, yAxisMaxValue,
                legendColorList, barLabelVisible, barLabelFormat);
        try {
            ChartUtils.writeChartAsJPEG(outputStream, 1.0f, chart, width, height, null);
        } catch (IOException e) {
            log.error("生成柱状图异常，异常信息为[{}]", e.getMessage());
        }
    }

    /**
     * 生成柱状图(返回JFreeChart)
     *
     * @param chartTitle      图表标题
     * @param legendNameList  图例名称列表
     * @param xAxisNameList   x轴名称列表
     * @param dataList        数据列表
     * @param theme           主题(null代表默认主题)
     * @param yAxisTitle      y轴标题
     * @param xAxisTitle      x轴标题
     * @param yAxisMinValue   y轴最小值（可以为空）
     * @param yAxisMaxValue   y轴最大值（可以为空）
     * @param legendColorList 图例背景颜色（可以为空）
     * @param barLabelVisible 是否显示柱体标签（可以为空）
     * @param barLabelFormat  柱体标签格式（可以为空）
     * @return JFreeChart
     */
    public static JFreeChart createBarChart(String chartTitle, List<String> legendNameList,
                                            List<String> xAxisNameList, List<List<Object>> dataList,
                                            StandardChartTheme theme, String yAxisTitle, String xAxisTitle,
                                            Double yAxisMinValue, Double yAxisMaxValue,
                                            List<Color> legendColorList, Boolean barLabelVisible,
                                            String barLabelFormat) {
        //设置主题，防止中文乱码
        theme = Objects.isNull(theme) ? FreeChartUtil.createChartTheme("") : theme;
        ChartFactory.setChartTheme(theme);
        // 创建柱状图
        JFreeChart chart = ChartFactory.createBarChart(chartTitle, xAxisTitle, yAxisTitle,
                FreeChartUtil.createDefaultCategoryDataset(legendNameList, xAxisNameList, dataList));
        // 设置抗锯齿，防止字体显示不清楚
        chart.setTextAntiAlias(false);
        // 对柱子进行渲染
        FreeChartUtil.setBarRenderer(chart.getCategoryPlot(), true);
        CategoryPlot plot = (CategoryPlot) chart.getPlot();
        CategoryAxis categoryAxis = plot.getDomainAxis();
        // 最大换行数
        categoryAxis.setMaximumCategoryLabelLines(10);
        // y轴
        ValueAxis valueAxis = chart.getCategoryPlot().getRangeAxis();
        if (Objects.nonNull(yAxisMinValue)) {
            valueAxis.setLowerBound(yAxisMinValue);
        }
        if (Objects.nonNull(yAxisMaxValue)) {
            valueAxis.setUpperBound(yAxisMaxValue);
        }
        CategoryItemRenderer customBarRenderer = plot.getRenderer();
        //显示每个柱的数值
        if (Objects.nonNull(barLabelVisible)) {
            customBarRenderer.setDefaultItemLabelsVisible(barLabelVisible);
            //柱体数值格式
            if (StringUtils.isNotEmpty(barLabelFormat)) {
                customBarRenderer.setDefaultItemLabelGenerator(new StandardCategoryItemLabelGenerator(barLabelFormat, NumberFormat.getInstance()));
            }
        }
        //设置系列柱体背景颜色
        if (CollectionUtils.isNotEmpty(legendColorList)) {
            for (int i = 0; i < legendNameList.size() && i < legendColorList.size(); i++) {
                Color color = legendColorList.get(i);
                if (Objects.isNull(color)) {
                    continue;
                }
                customBarRenderer.setSeriesPaint(i, color);
            }
        }
        // 设置标注无边框
        chart.getLegend().setFrame(new BlockBorder(Color.WHITE));
        // 标注位于上侧
        chart.getLegend().setPosition(RectangleEdge.TOP);
        return chart;
    }

    /**
     * 生成简单柱状图，每个柱状图中只显示一列数据(返回JFreeChart)
     *
     * @param chartTitle      图表标题
     * @param legendNameList  图例名称列表
     * @param xAxisNameList   x轴名称列表
     * @param dataList        数据列表
     * @param theme           主题(null代表默认主题)
     * @param yAxisTitle      y轴标题
     * @param xAxisTitle      x轴标题
     * @param yAxisMinValue   y轴最小值（可以为空）
     * @param yAxisMaxValue   y轴最大值（可以为空）
     * @param legendColorList 图例背景颜色（可以为空）
     * @param barLabelVisible 是否显示柱体标签（可以为空）
     * @param barLabelFormat  柱体标签格式（可以为空）
     * @return JFreeChart JFreeChart对象
     */
    public static JFreeChart createSimpleBarChart(String chartTitle, List<String> legendNameList,
                                                  List<String> xAxisNameList, List<Object> dataList,
                                                  StandardChartTheme theme, String yAxisTitle, String xAxisTitle,
                                                  Double yAxisMinValue, Double yAxisMaxValue,
                                                  List<Color> legendColorList, Boolean barLabelVisible,
                                                  String barLabelFormat) {
        //设置主题，防止中文乱码
        theme = Objects.isNull(theme) ? FreeChartUtil.createChartTheme("") : theme;
        ChartFactory.setChartTheme(theme);
        // 创建柱状图
        JFreeChart chart = ChartFactory.createBarChart(chartTitle, xAxisTitle, yAxisTitle,
                FreeChartUtil.createSimpleBarDataset(legendNameList, xAxisNameList, dataList));
        // 设置抗锯齿，防止字体显示不清楚
        chart.setTextAntiAlias(false);
        // 对柱子进行渲染
        FreeChartUtil.setBarRenderer(chart.getCategoryPlot(), true);
        CategoryPlot plot = (CategoryPlot) chart.getPlot();
        CategoryAxis categoryAxis = plot.getDomainAxis();
        // 最大换行数
        categoryAxis.setMaximumCategoryLabelLines(10);
        // y轴
        ValueAxis valueAxis = chart.getCategoryPlot().getRangeAxis();
        if (Objects.nonNull(yAxisMinValue)) {
            valueAxis.setLowerBound(yAxisMinValue);
        }
        if (Objects.nonNull(yAxisMaxValue)) {
            valueAxis.setUpperBound(yAxisMaxValue);
        }
        CategoryItemRenderer customBarRenderer = plot.getRenderer();
        //显示每个柱的数值
        if (Objects.nonNull(barLabelVisible)) {
            customBarRenderer.setDefaultItemLabelsVisible(barLabelVisible);
            //柱体数值格式
            if (StringUtils.isNotEmpty(barLabelFormat)) {
                customBarRenderer.setDefaultItemLabelGenerator(new StandardCategoryItemLabelGenerator(barLabelFormat, NumberFormat.getInstance()));
            }
        }
        //设置系列柱体背景颜色
        if (CollectionUtils.isNotEmpty(legendColorList)) {
            for (int i = 0; i < legendNameList.size() && i < legendColorList.size(); i++) {
                Color color = legendColorList.get(i);
                if (Objects.isNull(color)) {
                    continue;
                }
                customBarRenderer.setSeriesPaint(i, color);
            }
        }
        // 设置标注无边框
        chart.getLegend().setFrame(new BlockBorder(Color.WHITE));
        // 标注位于上侧
        chart.getLegend().setPosition(RectangleEdge.TOP);
        return chart;
    }
}
