package net.heartshield.filter;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.XYDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.RefineryUtilities;

import javax.swing.*;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

/**
 * LineChart window displaying a single curve.
 *
 * This is a test meant for PC.
 * It will NOT work on Android, since JFreeChart needs Swing/AWT.
 *
 * @author David Madl (git@abanbytes.eu)
 * @date 2017-03-20
 */
public class LineChart extends JFrame {
    private XYSeries[] mDataSeries;

    private final Object mLock = new Object();

    /**
     * Create a LineChart window displaying a single curve.
     *
     * Making a data series:
     * <pre>
     * final XYSeries series1 = new XYSeries("First");
     * series1.add(1.0, 1.0);
     * series1.add(2.0, 4.0);
     * </pre>
     *
     * @param title
     * @param series
     */
    public LineChart(String title, XYSeries[] series) {
        super(title);

        mDataSeries = series;

        final XYDataset dataset = createDataset();
        final JFreeChart chart = createChart(dataset);
        final ChartPanel chartPanel = new ChartPanel(chart);
        chartPanel.setPreferredSize(new java.awt.Dimension(500, 270));
        setContentPane(chartPanel);

        final JFrame window = this;
        this.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent arg0) {
                //System.out.println("in windowClosing()...");
                window.setVisible(false);
                synchronized(mLock) {
                    mLock.notify();
                }
                window.dispose();
                //System.out.println("windowClosing() notified mLock.");
            }
        });
        //this.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
    }

    public LineChart(String title, XYSeries dataSeries) {
        this(title, new XYSeries[]{dataSeries});
    }

    public void showChart() {
        this.pack();
        RefineryUtilities.centerFrameOnScreen(this);
        this.setVisible(true);
    }

    public void waitChart() {
        //System.out.println("in waitChart()...");
        synchronized(mLock) {
            while(this.isVisible()) {
                try {
                    //System.out.println("mLock.wait()...");
                    mLock.wait();
                    //System.out.println("mLock.wait() returned.");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
        //System.out.println("waitChart() done.");
    }

    private XYDataset createDataset() {
        final XYSeriesCollection dataset = new XYSeriesCollection();
        for(XYSeries series : mDataSeries)
            dataset.addSeries(series);
        return dataset;
    }

    private JFreeChart createChart(final XYDataset dataset) {

        // create the chart...
        final JFreeChart chart = ChartFactory.createXYLineChart(
                getTitle(),      // chart title
                "X",                      // x axis label
                "Y",                      // y axis label
                dataset,                  // data
                PlotOrientation.VERTICAL,
                true,                     // include legend
                true,                     // tooltips
                false                     // urls
        );

        chart.setBackgroundPaint(Color.white);

        final XYPlot plot = chart.getXYPlot();
        plot.setBackgroundPaint(Color.lightGray);
        //    plot.setAxisOffset(new Spacer(Spacer.ABSOLUTE, 5.0, 5.0, 5.0, 5.0));
        plot.setDomainGridlinePaint(Color.white);
        plot.setRangeGridlinePaint(Color.white);

        final XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
        //renderer.setSeriesLinesVisible(0, false);
        for(int i = 0; i < mDataSeries.length; i++)
            renderer.setSeriesShapesVisible(i, false);
        plot.setRenderer(renderer);

        // change the auto tick unit selection to integer units only...
        final NumberAxis rangeAxis = (NumberAxis) plot.getRangeAxis();
        rangeAxis.setStandardTickUnits(NumberAxis.createIntegerTickUnits());

        return chart;
    }

    public static void main(final String[] args) {
        final XYSeries series2 = new XYSeries("Series title");
        series2.add(1.0, 5.0);
        series2.add(2.0, 7.0);
        series2.add(3.0, 6.0);
        series2.add(4.0, 8.0);
        series2.add(5.0, 4.0);
        series2.add(6.0, 4.0);
        series2.add(7.0, 2.0);
        series2.add(8.0, 1.0);

        LineChart lc = new LineChart("Plot title", series2);
        //System.out.println("showChart()");
        lc.showChart();
        //System.out.println("wait()...");
        lc.waitChart();
        System.out.println("finished");

        // exit the Event Dispatch Thread, or EDT
        //System.exit(0);
        // not necessary if window.dispose() is called
    }

    public static LineChart plot(double[] x) {
        final XYSeries series = new XYSeries("data");

        for(int i = 0; i < x.length; i++)
            series.add(i, x[i]);

        return new LineChart("data", series);
    }

    public static LineChart plot(double[] t, double[] x) {
        final XYSeries series = new XYSeries("data");

        if(t.length != x.length)
            throw new IllegalArgumentException("t.length=" + t.length + " != x.length=" + x.length);

        for(int i = 0; i < x.length; i++)
            series.add(t[i], x[i]);

        return new LineChart("data", series);
    }
}
