import java.awt.*;
import java.awt.event.*;

public class TimeCanvas extends NodesCanvas {
    private FourierSeries fourierSeries;
    private boolean plot;
    private boolean interactive;
    private Image buffer;

    public TimeCanvas() {
        fourierSeries = new FourierSeries();
        plot = false;
        interactive = true;
        buffer = null;
    }

    public void setN(int n) {
        int nodeCount;
        Node node;
        double[] x;
        double[] y;

        fourierSeries.setN(n);
        nodeCount = getNodeCount();
        if (nodeCount > 1) {
            x = new double[nodeCount];
            y = new double[nodeCount];
            for (int i = 0; i < nodeCount; ++i) {
                node = getNode(i);
                x[i] = node.x;
                y[i] = node.y;
            }
            fourierSeries.setF(x, y);
        }
        if (plot) {
            plot = false;
        }
        repaint();
    }

    public int getN() {
        return fourierSeries.getN();
    }

    public double getT() {
        return fourierSeries.getT();
    }

    public double[] getA() {
        return fourierSeries.getA();
    }

    public double[] getB() {
        return fourierSeries.getB();
    }

    public double[] getC() {
        return fourierSeries.getC();
    }

    public void removeNodes() {
        if (plot) {
            plot = false;
        }
        super.removeNodes();
    }

    public void plot() {
        plot = true;
        repaint();
    }

    public void setInteractive(boolean interactive) {
        this.interactive = interactive;
        repaint();
    }

    public boolean getInteractive() {
        return interactive;
    }

    public void invalidate() {
        buffer = null;
    }

    public void paint(Graphics graphics) {
        Dimension size = getSize();
        Graphics bufferGraphics;
        int nodeCount = getNodeCount();
        double[] x;
        double[] y;
        Node node;
        double t;
        double[] a;
        double[] b;
        double x0;
        double y0;
        double x1;
        double y1;

        if (buffer == null) {
            buffer = createImage(size.width, size.height);
        }
        bufferGraphics = buffer.getGraphics();
        bufferGraphics.setColor(getBackground());
        bufferGraphics.fillRect(0, 0, size.width, size.height);
        super.paint(bufferGraphics);
        if (nodeCount > 1 && (plot || interactive)) {
            x = new double[nodeCount];
            y = new double[nodeCount];
            for (int i = 0; i < nodeCount; ++i) {
                node = getNode(i);
                x[i] = node.x;
                y[i] = node.y;
            }
            fourierSeries.setF(x, y);
            t = getT();
            a = getA();
            b = getB();
            bufferGraphics.setColor(Color.red);
            x0 = 2 * Math.PI * getX(0) / t;
            y0 = a[0];
            for (int j = 1; j < a.length; ++j) {
                y0 += a[j] * Math.cos(j * x0) + b[j] * Math.sin(j * x0);
            }
            for (int i = 1; i < size.width; ++i) {
                x1 = 2 * Math.PI * getX(i) / t;
                y1 = a[0];
                for (int j = 1; j < a.length; ++j) {
                    y1 += a[j] * Math.cos(j * x1) + b[j] * Math.sin(j * x1);
                }
                bufferGraphics.drawLine(i - 1, getY(y0), i, getY(y1));
                x0 = x1;
                y0 = y1;
            }
        }
        graphics.drawImage(buffer, 0, 0, null);
    }

    public void update(Graphics graphics) {
        paint(graphics);
    }

    protected void processMouseEvent(MouseEvent event) {
        if (event.getID() == MouseEvent.MOUSE_PRESSED && plot) {
            plot = false;
            repaint();
        }
        super.processMouseEvent(event);
    }

    protected void processNodeEvent(NodeEvent event) {
        int nodeIndex = event.getNodeIndex();
        double deltax = getContentWidth() / getSize().width;
        Node previousNode;
        Node node = event.getNode();
        Node nextNode;
        double contentWidth = getContentWidth();
        double contentHeight = getContentHeight();

        if (nodeIndex > 0) {
            previousNode = getNode(nodeIndex - 1);
            if (previousNode.x >= node.x) {
                node.x = previousNode.x + deltax;
            }
        } else {
            node.x = 0;
        }
        if (nodeIndex < getNodeCount() - 1) {
            nextNode = getNode(nodeIndex + 1);
            if (nextNode.x <= node.x) {
                node.x = nextNode.x - deltax;
            }
        } else if (node.x > contentWidth) {
            node.x = contentWidth;
        }
        if (node.y < 0) {
            node.y = 0;
        } else if (node.y > contentHeight) {
            node.y = contentHeight;
        }
        super.processNodeEvent(event);
    }
}