/*
 * Copyright (c) 2014 Paul Scherrer Institute. All rights reserved.
 */
package ch.psi.plot;

import ch.psi.plot.utils.SwingUtils;
import java.awt.Color;

/**
 * Data representation for LinePlot.
 */
public class LinePlotSeries extends PlotSeries<LinePlot> {

    public interface LinePlotSeriesListener {

        void onSeriesSetData(LinePlotSeries series, double[] x, double[] y);

        void onSeriesAppendData(LinePlotSeries series, double x, double y);
    }

    public LinePlotSeries(String name) {
        this(name, SwingUtils.generateRandomColor());
    }

    public LinePlotSeries(String name, Color color) {
        super(name);
        setColor(color);
    }

    private Color color;

    void setColor(Color color) {
        this.color = color;
    }

    public Color getColor() {
        return color;
    }

    private int axisY = 1;

    void setAxisY(int axis) {
        this.axisY = axisY;
    }

    public int getAxisY() {
        return axisY;
    }

    public void setData(double[] x, double[] y) {
        if (getPlot() != null) {
            ((LinePlotBase) getPlot()).seriesListener.onSeriesSetData(this, x, y);
        }
    }

    public void appendData(double x, double y) {
        if (getPlot() != null) {
            ((LinePlotBase) getPlot()).seriesListener.onSeriesAppendData(this, x, y);
        }
    }

    @Override
    public void clear() {
        setData(new double[0], new double[0]);
    }

    public double[] getX() {
        if (getPlot() == null) {
            return new double[0];
        }
        return getPlot().getSeriesData(this)[0];
    }

    public double[] getY() {
        if (getPlot() == null) {
            return new double[0];
        }
        return getPlot().getSeriesData(this)[1];
    }

    public int getCount() {
        if (getPlot() == null) {
            return 0;
        }
        return getPlot().getSeriesData(this)[0].length;
    }

    //Tools
    public double getAverage() {
        double average = 0.0;
        for (double y : getY()) {
            average = average + y;
        }
        return average / getCount();
    }

    public double[] getMinimum() {
        double min = Double.NaN;
        double xmin = Double.NaN;
        double[][] data = getPlot().getSeriesData(this);
        double[] x = data[0];
        double[] y = data[1];

        for (int i = 0; i < x.length; i++) {
            if (Double.isNaN(min) || (y[i] < min)) {
                min = y[i];
                xmin = x[i];
            }
        }
        return new double[]{xmin, min};
    }

    public double[] getMaximum() {
        double max = Double.NaN;
        double xmax = Double.NaN;
        double[][] data = getPlot().getSeriesData(this);
        double[] x = data[0];
        double[] y = data[1];

        for (int i = 0; i < x.length; i++) {
            if (Double.isNaN(max) || (y[i] > max)) {
                max = y[i];
                xmax = x[i];
            }
        }
        return new double[]{xmax, max};
    }

    public double[][] getDerivative() {
        if (getCount() <= 2) {
            return new double[][]{new double[0], new double[0]};
        }
        double[][] data = getPlot().getSeriesData(this);
        double[] x = data[0];
        double[] y = data[1];

        double[] dx = new double[getCount() - 2];
        double[] dy = new double[getCount() - 2];

        for (int i = 1; i < getCount() - 1; i++) { // do not start at 0 but 1 - stop 1 before end
            double xi = x[i];
            double ximinus1 = x[i - 1];
            double xiplus1 = x[i + 1];
            double yiminus1 = y[i - 1];
            double yiplus1 = y[i + 1];

            if (xiplus1 - ximinus1 != 0.0) {
                double di = (yiplus1 - yiminus1) / (xiplus1 - ximinus1);
                dx[i - 1] = xi;
                dy[i - 1] = di;
            } else {
                dx[i - 1] = xi;
                dy[i - 1] = Double.NaN;
            }
        }

        return new double[][]{dx, dy};
    }

    public double[][] getIntegral() {
        if (getCount() <= 1) {
            return new double[][]{new double[0], new double[0]};
        }
        double[][] data = getPlot().getSeriesData(this);
        double[] x = data[0];
        double[] y = data[1];

        double[] ix = new double[getCount() - 1];
        double[] iy = new double[getCount() - 1];
        double value = 0.0;

        for (int i = 1; i < getCount(); i++) { // Leave out 1. point 
            value += (x[i] - x[i - 1]) * (y[i] + y[i - 1]) / 2.0;
            ix[i - 1] = x[i];
            iy[i - 1] = value;
        }
        return new double[][]{ix, iy};
    }

}
