/**
 *
 * Copyright 2010 Paul Scherrer Institute. All rights reserved.
 *
 * This code is free software: you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any
 * later version.
 *
 * This code is distributed in the hope that it will be useful, but without any
 * warranty; without even the implied warranty of merchantability or fitness for
 * a particular purpose. See the GNU Lesser General Public License for more
 * details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this code. If not, see <http://www.gnu.org/licenses/>.
 *
 */
package ch.psi.plot.xy;

import ch.psi.plot.LinePlot;
import ch.psi.plot.LinePlotSeries;
import ch.psi.plot.utils.SwingUtils;
import ch.psi.plot.xy.generator.Sinus;
import ch.psi.plot.xy.generator.XYGenerator;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.LineNumberReader;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

/**
 * Test for the LinePlot class
 *
 */
public class LinePlotTest {

    private final File file = new File("../ch.psi.sls.xasec/testfiles/text/beamCurrent.txt");
    private final long timeToClose = 7200000; // 2 hours
    static LinePlot linePlot;

    @Before
    public void setUp() throws Exception {
        linePlot = new ch.psi.plot.jfree.LinePlot();
        //linePlot = new ch.psi.plot.jlchart.LinePlot() ;
        linePlot.setTitle("Title");
    }

    @After
    public void tearDown() throws Exception {
    }

    /**
     * Test LinePlot rendering point by point (getting data from a generator)
     *
     * @throws IOException
     * @throws InterruptedException
     */
    @Test
    public void testLinePlotGeneratorPerformance() throws IOException, InterruptedException {
        linePlot.clear();
        //for(int i=0;i<10;i++)
        {
            LinePlotSeries[] series = getDataFromGenerator(0, linePlot);
            //linePlot.addSeries(series);

//addDataFromGenerator(0, 10, 1000, linePlot);            
            JFrame frame = new JFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setContentPane(linePlot.getChartPanel());
            frame.pack();
            SwingUtils.centerOnScreen(frame);
            frame.setVisible(true);
        }

        Thread.sleep(timeToClose);
    }

    /**
     * Test LinePlot rendering point by point (getting data from a generator)
     *
     * @throws IOException
     * @throws InterruptedException
     */
    @Test
    public void testLinePlotAllDataAvailable() throws IOException, InterruptedException {
        linePlot.clear();
        for (int i = 0; i < 1; i++) {
            LinePlotSeries[] d = loadDataFromGenerator(linePlot);
            //linePlot.addSeries(d);
            JPanel chartPanel = linePlot.getChartPanel();
            JFrame frame = new JFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setContentPane(chartPanel);
            frame.pack();
            SwingUtils.centerOnScreen(frame);
            frame.setVisible(true);
            frame.setContentPane(chartPanel);
        }

        Thread.sleep(timeToClose);
    }

    /**
     * Test LinePlot rendering point by point (getting data from a generator)
     *
     * @throws IOException
     * @throws InterruptedException
     */
    @Test
    public void testLinePlotGenerator() throws IOException, InterruptedException {
        linePlot.clear();
        for (int i = 0; i < 1; i++) {
            linePlot.addSeries(getDataFromGenerator(1, linePlot));
            JFrame frame = new JFrame();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setContentPane(linePlot.getChartPanel());
            frame.pack();
            SwingUtils.centerOnScreen(frame);
            frame.setVisible(true);
        }

        Thread.sleep(timeToClose);
    }

    @Test
    public void testLinePlotGeneratorOne() throws IOException, InterruptedException {

        XYGenerator generator = new XYGenerator(new Sinus(0.01), 0, 1, 1000, false);

        generator.reset();

        String seriesName = "test";
        LinePlotSeries series = new LinePlotSeries(seriesName);

        double[] xy;
        while ((xy = generator.getNewPoint()) != null) {
            series.appendData(xy[0], xy[1]); // Add t to the y value to see the plotted line
        }

        linePlot.clear();
        linePlot.addSeries(series);

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setContentPane(linePlot.getChartPanel());
        frame.pack();
        SwingUtils.centerOnScreen(frame);
        frame.setVisible(true);

        Thread.sleep(timeToClose);
    }

    /**
     * Test LinePlot rendering point by point (getting data from a generator)
     *
     * @throws IOException
     * @throws InterruptedException
     */
    @Test
    public void testLinePlotGenerator65536() throws IOException, InterruptedException {
        linePlot.clear();
        linePlot.addSeries(loadDataFromGenerator65536(0, linePlot));

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setContentPane(linePlot.getChartPanel());
        frame.pack();
        SwingUtils.centerOnScreen(frame);
        frame.setVisible(true);

        int cnt = 1;
        while (true) {
            Thread.sleep(5000);
            linePlot.clear();
            linePlot.addSeries(loadDataFromGenerator65536(cnt, linePlot));
            cnt++;
        }

    }

    /**
     * Test LinePlot rendering point by point (getting data from a file)
     *
     * @throws IOException
     * @throws InterruptedException
     */
    @Test
    public void testLinePlotFile() throws IOException, InterruptedException {
        linePlot.clear();
        linePlot.addSeries(getDataFromFile());
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setContentPane(linePlot.getChartPanel());
        frame.pack();
        SwingUtils.centerOnScreen(frame);
        frame.setVisible(true);

        Thread.sleep(timeToClose);
    }

    /**
     * Get data from file
     *
     * @return
     * @throws IOException
     */
    private LinePlotSeries getDataFromFile() throws IOException {
        String seriesName = "File Data";
        LineNumberReader in = new LineNumberReader(new FileReader(file));

        // Update data
        LinePlotSeries series = new LinePlotSeries(seriesName);

        // Read data
        String s;
        while ((s = in.readLine()) != null) {
            double x = (double) in.getLineNumber();
            double y = Double.parseDouble(s);

            series.appendData(x, y);
        }
        in.close();
        return (series);
    }

    /**
     * Get data from a generator
     *
     * @param sleeptime	Time between data points
     * @return
     */
    private LinePlotSeries[] getDataFromGenerator(final long sleeptime, final LinePlot plot) {
        final String seriesBaseName = "Generator Data";
        final LinePlotSeries[] series = new LinePlotSeries[100];
        for (int i = 0; i < series.length; i++) {
            String seriesName = seriesBaseName + " - " + i;
            series[i] = new LinePlotSeries(seriesName);
        }
        plot.addSeries(series);
        final XYGenerator generator = new XYGenerator(new Sinus(0.01), 0, 1, 1000, false);

        Thread t = new Thread(new Runnable() {

            @Override
            public void run() {
                long start = System.currentTimeMillis();
                for (int i = 0; i < series.length; i++) {
                    // Reset generator
                    generator.reset();
                    double[] xy;
                    while ((xy = generator.getNewPoint()) != null) {
                        series[i].appendData(xy[0], xy[1] + i); // Add t to the y value to see the plotted line

                        try {
                            Thread.sleep(sleeptime);
                        } catch (InterruptedException e) {
                        }
                    }
                }

                System.out.println("DONE:  " + (System.currentTimeMillis() - start));
            }
        });
        t.start();

        return series;
    }

    private LinePlotSeries[] loadDataFromGenerator(final LinePlot plot) {
        final String seriesBaseName = "Generator Data";
        final LinePlotSeries[] series = new LinePlotSeries[10];
        for (int i = 0; i < series.length; i++) {
            String seriesName = seriesBaseName + " - " + i;
            series[i] = new LinePlotSeries(seriesName);
        }
        plot.addSeries(series);

        final XYGenerator generator = new XYGenerator(new Sinus(0.01), 0, 1, 1000, false);

        plot.setUpdatesEnabled(false);
        for (int t = 0; t < 1000; t++) {
            // Reset generator
            generator.reset();
            double[] xy;
            while ((xy = generator.getNewPoint()) != null) {
                series[t].appendData(xy[0], xy[1] + t); // Add t to the y value to see the plotted line
            }
            plot.requestSeriesUpdate(series[t]);
        }
        plot.setUpdatesEnabled(true);

        System.out.println("DONE");

        return series;
    }

    private LinePlotSeries loadDataFromGenerator65536(int count, final LinePlot plot) {
        final String seriesBaseName = "Generator Data";
        LinePlotSeries series = new LinePlotSeries(seriesBaseName);

        final XYGenerator generator = new XYGenerator(new Sinus(0.01), 0, 1, 65536, false);

        plot.setUpdatesEnabled(false);
        double[] xy;
        plot.setUpdatesEnabled(false);
        while ((xy = generator.getNewPoint()) != null) {
            series.appendData(xy[0], xy[1] + count); // No notification send - use this if all data is available before plotting
        }
        plot.setUpdatesEnabled(true);
        plot.update(true);
        System.out.println("DONE");

        return series;
    }

}
