package com.xinyilu.common.utils.jreechart;

import com.itextpdf.text.Document;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Paragraph;
import com.xinyilu.common.utils.document.CreateDocumentUtils;
import lombok.extern.slf4j.Slf4j;
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.CategoryLabelPositions;
import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.labels.ItemLabelAnchor;
import org.jfree.chart.labels.ItemLabelPosition;
import org.jfree.chart.labels.StandardCategoryItemLabelGenerator;
import org.jfree.chart.labels.StandardPieSectionLabelGenerator;
import org.jfree.chart.plot.*;
import org.jfree.chart.renderer.category.LineAndShapeRenderer;
import org.jfree.chart.renderer.category.StandardBarPainter;
import org.jfree.chart.renderer.xy.StandardXYBarPainter;
import org.jfree.chart.ui.RectangleInsets;
import org.jfree.chart.ui.TextAnchor;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.general.DefaultPieDataset;

import java.awt.*;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.math.BigDecimal;
import java.text.NumberFormat;
import java.util.Map;

/**
 * @Description JFreeChart 图形工具类，适用与生成PDF中的图形
 * @Author 纪寒
 * @Date 2022-09-23 10:16:02
 * @Version 1.0
 */
@Slf4j
public class FreeChartDocumentUtil {

    /**
     * 默认的数据加载方式
     */
    private static final String NO_DATA_MSG = "暂无数据";
    private static final Font FONT = new Font("STSongStd-Light", Font.BOLD, 12);
    public static Color[] CHART_COLORS = {
            new Color(146, 29, 34),
            new Color(126, 126, 126),
            new Color(31, 129, 188),
            new Color(92, 92, 97),
            new Color(144, 237, 125),
            new Color(255, 188, 117),
            new Color(153, 158, 255),
            new Color(255, 117, 153),
            new Color(253, 236, 109),
            new Color(128, 133, 232),
            new Color(158, 90, 102),
            new Color(255, 204, 102)};

    static {
        setChartTheme();
    }

    /**
     * 中文主题样式 解决乱码
     */
    public static void setChartTheme() {
        // 设置中文主题样式 解决乱码
        StandardChartTheme chartTheme = new StandardChartTheme("CN");
        // 设置标题字体
        chartTheme.setExtraLargeFont(FONT);
        // 设置图例的字体
        chartTheme.setRegularFont(FONT);
        // 设置轴向的字体
        chartTheme.setLargeFont(FONT);
        chartTheme.setSmallFont(FONT);
        chartTheme.setTitlePaint(new Color(51, 51, 51));
        chartTheme.setSubtitlePaint(new Color(85, 85, 85));
        // 设置标注
        chartTheme.setLegendBackgroundPaint(Color.WHITE);
        chartTheme.setLegendItemPaint(Color.BLACK);
        chartTheme.setChartBackgroundPaint(Color.WHITE);
        // 绘制颜色绘制颜色.轮廓供应商
        Paint[] outlinePaintSequence = new Paint[]{Color.WHITE};
        // 绘制器颜色源
        DefaultDrawingSupplier drawingSupplier = new DefaultDrawingSupplier(CHART_COLORS, CHART_COLORS, outlinePaintSequence,
                DefaultDrawingSupplier.DEFAULT_STROKE_SEQUENCE, DefaultDrawingSupplier.DEFAULT_OUTLINE_STROKE_SEQUENCE,
                DefaultDrawingSupplier.DEFAULT_SHAPE_SEQUENCE);
        chartTheme.setDrawingSupplier(drawingSupplier);
        // 绘制区域
        chartTheme.setPlotBackgroundPaint(Color.WHITE);
        // 绘制区域外边框
        chartTheme.setPlotOutlinePaint(Color.WHITE);
        // 链接标签颜色
        chartTheme.setLabelLinkPaint(new Color(8, 55, 114));
        chartTheme.setLabelLinkStyle(PieLabelLinkStyle.CUBIC_CURVE);
        chartTheme.setAxisOffset(new RectangleInsets(5, 12, 5, 12));
        // X坐标轴垂直网格颜色
        chartTheme.setDomainGridlinePaint(new Color(192, 208, 224));
        // Y坐标轴水平网格颜色
        chartTheme.setRangeGridlinePaint(new Color(192, 192, 192));
        chartTheme.setBaselinePaint(Color.WHITE);
        chartTheme.setCrosshairPaint(Color.BLUE);
        // 坐标轴标题文字颜色
        chartTheme.setAxisLabelPaint(new Color(51, 51, 51));
        // 刻度数字
        chartTheme.setTickLabelPaint(new Color(67, 67, 72));
        // 设置柱状图渲染
        chartTheme.setBarPainter(new StandardBarPainter());
        // XYBar 渲染
        chartTheme.setXYBarPainter(new StandardXYBarPainter());
        chartTheme.setItemLabelPaint(Color.black);
        chartTheme.setThermometerPaint(Color.white);
        ChartFactory.setChartTheme(chartTheme);
    }

    /**
     * 设置折线图样式
     *
     * @param plot             折线图对象
     * @param isShowDataLabels 是否显示数据标题
     * @param isShapesVisible  是否显示数据点
     */
    public static void setLineRender(CategoryPlot plot, boolean isShowDataLabels, boolean isShapesVisible) {
        plot.setNoDataMessage(NO_DATA_MSG);
        plot.setInsets(new RectangleInsets(10, 10, 0, 10), false);
        LineAndShapeRenderer renderer = (LineAndShapeRenderer) plot.getRenderer();
        renderer.setDefaultStroke(new BasicStroke(1.5F));
        if (isShowDataLabels) {
            renderer.setDefaultItemLabelsVisible(true);
            renderer.setDefaultItemLabelGenerator(new StandardCategoryItemLabelGenerator(StandardCategoryItemLabelGenerator.DEFAULT_LABEL_FORMAT_STRING, NumberFormat.getInstance()));
            renderer.setDefaultPositiveItemLabelPosition(new ItemLabelPosition(ItemLabelAnchor.OUTSIDE1, TextAnchor.BOTTOM_CENTER));
        }
        // 数据点绘制形状
        renderer.setDefaultShapesVisible(isShapesVisible);
        setXAixs(plot);
        setYAixs(plot);
    }

    /**
     * 设置类别图表(CategoryPlot) X坐标轴线条颜色和样式
     *
     * @param plot 类别图表对象
     */
    public static void setXAixs(CategoryPlot plot) {
        Color lineColor = new Color(51, 51, 51);
        plot.getDomainAxis().setCategoryLabelPositions(CategoryLabelPositions.UP_45);
        // X坐标轴颜色
        plot.getDomainAxis().setAxisLinePaint(lineColor);
        // X坐标轴标记|竖线颜色
        plot.getDomainAxis().setTickMarkPaint(lineColor);
        plot.getDomainAxis().setTickLabelFont(new Font("STSongStd-Light", Font.BOLD, 12));
    }

    /**
     * 设置类别图表(CategoryPlot) Y坐标轴线条颜色和样式 同时防止数据无法显示
     *
     * @param plot 类别图表对象
     */
    public static void setYAixs(CategoryPlot plot) {
        Color axisColor = new Color(51, 51, 51);
        Color tickColor = new Color(219, 218, 218);
        ValueAxis axis = plot.getRangeAxis();
        // Y坐标轴颜色
        axis.setAxisLinePaint(axisColor);
        // Y坐标轴标记|竖线颜色
        axis.setTickMarkPaint(tickColor);
        // false隐藏Y刻度
        axis.setAxisLineVisible(true);
        axis.setTickMarksVisible(true);
        // Y轴网格线条
        plot.setRangeGridlinePaint(new Color(229, 229, 229));
        plot.setRangeGridlineStroke(new BasicStroke(1));
        // 设置顶部Y坐标轴间距,防止数据无法显示
        plot.getRangeAxis().setUpperMargin(0.1);
        // 设置底部Y坐标轴间距
        plot.getRangeAxis().setLowerMargin(0.1);
        plot.getRangeAxis().setTickLabelFont(new Font("STSongStd-Light", Font.BOLD, 12));
    }

    /**
     * 生成折线图并返回Image数组
     *
     * @param title 标题
     * @param datas 数据
     * @param xName X轴
     * @param yName Y轴
     */
    public static void createLinePortImage(Document document, String title, Map<String, Map<String, BigDecimal>> datas, String xName, String yName) throws Exception {
        //二级标题
        Paragraph paragraphHead = CreateDocumentUtils.createHead2(title);
        //设置段落前后间距
        paragraphHead.setSpacingAfter(5);
        paragraphHead.setSpacingBefore(5);
        document.add(paragraphHead);
        try {
            //种类数据集
            DefaultCategoryDataset dataset = new DefaultCategoryDataset();
            //遍历map
            for (Map.Entry<String, Map<String, BigDecimal>> entry : datas.entrySet()) {
                String key = entry.getKey();
                Map<String, BigDecimal> value = entry.getValue();
                for (Map.Entry<String, BigDecimal> decimalEntry : value.entrySet()) {
                    dataset.setValue(decimalEntry.getValue(), key, decimalEntry.getKey());
                }
            }
            //创建2D折线图,折线图分水平显示和垂直显示两种
            //legend:是否显示图例(对于简单的柱状图必须是false)
            //tooltips:是否生成工具
            //urls:是否生成URL链接
            JFreeChart chart = ChartFactory.createLineChart("", xName, yName, dataset,
                    PlotOrientation.VERTICAL, true, true, true);
            //得到绘图区
            setLineRender((CategoryPlot) chart.getPlot(), true, true);
            ByteArrayOutputStream bas = new ByteArrayOutputStream();
            ChartUtils.writeChartAsJPEG(bas, 1.0f, chart, 800, 500, null);
            com.itextpdf.text.Image image = com.itextpdf.text.Image.getInstance(bas.toByteArray());
            image.setAlignment(com.itextpdf.text.Image.ALIGN_CENTER);
            image.scaleAbsolute(500, 300);
            document.add(image);
        } catch (Exception e) {
            log.error("生成折线图异常，异常信息为：[{}]", e.getMessage());
        }
    }

    /**
     * 生成饼图，并返回byte数组
     *
     * @param title 标题
     * @param datas 数据
     */
    public static void createPiePortImage(Document document, String title, Map<String, BigDecimal> datas) throws DocumentException, IOException {
        //二级标题
        Paragraph paragraphHead = CreateDocumentUtils.createHead2(title);
        //设置段落前后间距
        paragraphHead.setSpacingAfter(5);
        paragraphHead.setSpacingBefore(5);
        document.add(paragraphHead);
        try {
            // 如果不使用Font,中文将显示不出来
            DefaultPieDataset pds = new DefaultPieDataset();
            //遍历map
            for (Map.Entry<String, BigDecimal> entry : datas.entrySet()) {
                pds.setValue(entry.getKey(), entry.getValue());
            }
            //生成一个饼图的图表
            //分别是:显示图表的标题、需要提供对应图表的DateSet对象、是否显示图例、是否生成贴士以及是否生成URL链接
            JFreeChart chart = ChartFactory.createPieChart("", pds, true, true, true);
            setPieRender(chart.getPlot());
            ByteArrayOutputStream bas = new ByteArrayOutputStream();
            ChartUtils.writeChartAsJPEG(bas, 1.0f, chart, 800, 500, null);
            com.itextpdf.text.Image image = com.itextpdf.text.Image.getInstance(bas.toByteArray());
            image.setAlignment(com.itextpdf.text.Image.ALIGN_CENTER);
            image.scaleAbsolute(500, 300);
            document.add(image);
        } catch (Exception e) {
            log.error("生成生成饼图异常，异常信息为：[{}]", e.getMessage());
        }
    }

    /**
     * 设置饼状图渲染
     *
     * @param plot 饼图对象
     */
    public static void setPieRender(Plot plot) {
        plot.setNoDataMessage(NO_DATA_MSG);
        plot.setInsets(new RectangleInsets(10, 10, 5, 10));
        PiePlot piePlot = (PiePlot) plot;
        piePlot.setInsets(new RectangleInsets(0, 0, 0, 0));
        // 圆形
        piePlot.setCircular(true);
        piePlot.setLabelGap(0.01);
        piePlot.setInteriorGap(0.05D);
        // 图例形状
        piePlot.setLegendItemShape(new Rectangle(10, 10));
        piePlot.setIgnoreNullValues(true);
        // 去掉背景色
        piePlot.setLabelBackgroundPaint(null);
        // 去掉阴影
        piePlot.setLabelShadowPaint(null);
        // 去掉边框
        piePlot.setLabelOutlinePaint(null);
        piePlot.setShadowPaint(null);
        // 0:category 1:value:2 :percentage
        // 显示标签数据
        piePlot.setLabelGenerator(new StandardPieSectionLabelGenerator("{0}:{2}"));
    }
}
