import java.awt.*;
import java.util.*;
import java.awt.event.*;

// class SplineTestCanvas
//
// Author:      Alexander Bogomolny, CTK Software, Inc.
// URL:         http://www.cut-the-knot.com
// Date:        November 30, 2000
// Copyright:   A. Bogomolny
//              Permission to use and modify the file is therefore granted
//              as long as this comment remains unchanged. Do this at your
//              own risk.
//
class SplineTestCanvas extends Canvas implements MouseListener, MouseMotionListener
{
    private Image       m_Image;
    private Graphics    m_Graph;
    private SplineTest  m_Parent;

    MMover Mover = new MMover();

    CubicSpline Spline;
    int XMargin = 40;

    boolean ShowDerivative = false;
    public void ShowDerivative(boolean show) { ShowDerivative = show; }
    boolean ShowIntegral = false;
    public void ShowIntegral(boolean show) { ShowIntegral = show; }
    boolean ShowPoints = false;
    public void ShowPoints(boolean show) { ShowPoints = show; }

    // The function drawn is in fact a linear interpolation
    // every LStep's. For rapidly changing functions this must be small.
    //
    int LStep = 4;
    public void SetLStep(int step) { LStep = step; }

    // just a precaution
    //
      private boolean     m_bInitialized = false;

    // constructor
    public SplineTestCanvas(SplineTest applet)
    {
        m_Parent = applet;

        try
        {
            setBackground(new Color(Integer.parseInt(m_Parent.getParameter("BCOLOR"), 16)));
            setForeground(new Color(Integer.parseInt(m_Parent.getParameter("FCOLOR"), 16)));
        }
        catch (Exception e)
        {
            setBackground(Color.lightGray);
            setForeground(Color.black);
        }

        addMouseListener(this);
        addMouseMotionListener(this);
    }

    public void paint(Graphics g)
    {
        update(g);
    }

    public void update(Graphics g)
    {
        if (!m_bInitialized)
            init();

        Dimension d = getSize();

        m_Graph.setColor(getBackground());
        m_Graph.fillRect(0, 0, d.width, d.height);

        m_Graph.setColor(getForeground());
        m_Graph.drawRect(0, 0, d.width-1, d.height-1);

        m_Graph.drawLine(0, d.height/2, d.width, d.height/2);

        Spline.Resolve();
        Spline.Draw(m_Graph, XMargin, d.width - XMargin, LStep);

        if (ShowDerivative)
        {
            m_Graph.setColor(Color.blue);
            Spline.DrawDerivative(m_Graph, XMargin, d.width - XMargin, LStep);
        }

        if (ShowIntegral)
        {
            m_Graph.setColor(Color.red);
            Spline.FillIntegralArray();
            Spline.DrawIntegral(m_Graph, XMargin, d.width - XMargin, LStep);
        }

        if (ShowPoints)
            Mover.Draw(m_Graph);

        g.drawImage(m_Image, 0, 0, null);
    }

    public void init()
    {
        Dimension d = getSize();

        m_Image = createImage(d.width, d.height);
        m_Graph = m_Image.getGraphics();

        Mover.SetPromote(false);

        int H = d.height/2;
        int h = H - 40;
        int N = 11;
        int w = (d.width - 2*XMargin)/N;

        Scale scaleY = new Scale((double)h/25, H);
        Scale scaleX = new Scale((d.width-2*XMargin)/10, d.width/2);
        VPoint.SetScales(scaleX.Inverse(), scaleY.Inverse());

        VPoint.SetDist(w/4, h/4);

        for (int i = 0; i < N; i++)
        {
            double x = i - (N-1)/2;
            double y = -x*x+(double)25/3;

            x = scaleX.Do(x);
            y = scaleY.Do(y);

            VPoint p = new VPoint((int)Math.round(x), (int)Math.round(y));

            p.SetRadius(2);
            Mover.AddMoveable(p);
        }

        Spline = new CubicSpline(Mover.GetMoveables());

          m_bInitialized = true;
    }

    public void mouseClicked(MouseEvent event)
    {
    }

    public void mouseEntered(MouseEvent event)
    {
    }

    public void mouseExited(MouseEvent event)
    {
    }

    public void mousePressed(MouseEvent event)
    {
        if (!Mover.IsHit(event.getX(), event.getY()))
            if (Spline.CloseEnough(event.getX(), event.getY()) != null)
            {
                Mover.SetMoveables(Spline.GetMoveables());
                if (Mover.IsHit(event.getX(), event.getY()))
                    repaint();
            }
    }

    public void mouseReleased(MouseEvent event)
    {
        if (Mover.Dragging())
        {
            Mover.UpdateLocation(event.getX(), event.getY());
            Mover.StopDragging();
            repaint();
        }
    }

    public void mouseDragged(MouseEvent event)
    {
        if (Mover.Dragging())
        {
            Mover.UpdateLocation(event.getX(), event.getY());
            repaint();
        }
    }

     public void mouseMoved(MouseEvent event)
     {
    }

    public void ShowShade(boolean show)
    {
        Spline.SetShade(show);
    }
}