/*
 * BezierApplet.java
 *
 * (C) 2004, Alex S.
 */
 
import java.awt.*;
import java.util.*;

public class BezierApplet extends BufferedApplet
{

    Vector points = new Vector();    

    int selectedPoint = -1;

    /**
     * initialize things
     */
    public void init(){
        super.init();
    }

    public double distance(double x1,double y1,double x2,double y2){
        return Math.sqrt( (x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) );
    }

    public int hitsPoint(int x,int y){
        for(int i=0;i<points.size();i++){
            double[] p = (double[])points.elementAt(i);
            if(distance(p[0],p[1],x,y) <= 5)
                return i;
        }
        return -1;
    }

    /**
     * function that gets called whenever something needs to be
     * rendered.
     */
    public void render(Graphics g) {
        if (damage) {
            g.setColor(Color.lightGray);
            g.fillRect(0, 0, bounds().width, bounds().height);
            
            double[] GX = new double[4];
            double[] GY = new double[4];

            g.setColor(Color.red);

            for(int i=0;i<points.size() && points.size()-i >= 4;i+=3){                
                double[] a = (double[])points.elementAt(i+0);
                double[] b = (double[])points.elementAt(i+1);
                double[] c = (double[])points.elementAt(i+2);
                double[] d = (double[])points.elementAt(i+3);
                
                GX[0] = a[0]; GX[1] = b[0]; GX[2] = c[0]; GX[3] = d[0]; 
                GY[0] = a[1]; GY[1] = b[1]; GY[2] = c[1]; GY[3] = d[1]; 

                Cubic xSpline = new Cubic(Cubic.BEZIER, GX);
                Cubic ySpline = new Cubic(Cubic.BEZIER, GY);

                for (double t = 0 ; t < 1 ; t += 0.01)
                    g.drawLine(
                        (int)xSpline.eval(t), 
                        (int)ySpline.eval(t), 
                        (int)xSpline.eval(t+0.01), 
                        (int)ySpline.eval(t+0.01)
                    );
            }
            g.setColor(Color.gray);
            for(int i=1;i<points.size();i++){                
                double[] p = (double[])points.elementAt(i);
                double[] q = (double[])points.elementAt(i-1);
                g.drawLine((int)(p[0]),(int)(p[1]),(int)(q[0]),(int)(q[1]));
            }

            for(int i=0;i<points.size();i++){
                if(i % 3 == 0){
                    g.setColor(Color.green);
                }else{
                    g.setColor(Color.black);
                }
                double[] p = (double[])points.elementAt(i);
                g.fillOval((int)(p[0]-5),(int)(p[1]-5),10,10);
            }            
            if(selectedPoint != -1){
                g.setColor(Color.blue);
                double[] p = (double[])points.elementAt(selectedPoint);
                g.fillOval((int)(p[0]-5),(int)(p[1]-5),10,10);
            }
	}
    }
    
    public boolean mouseDown(Event evt, int x, int y){
        if((selectedPoint = hitsPoint(x,y)) < 0){
            points.addElement(new double[]{x,y});
            selectedPoint = points.size()-1;
        }
        damage = true;
        return true;
    }
    
    public boolean mouseUp(Event evt, int x, int y){
        damage = true;
        return true;
    }
	
    public boolean mouseDrag(Event evt, int x, int y){
        if(selectedPoint != -1){
            double[] p = (double[])points.elementAt(selectedPoint);

            if(selectedPoint % 3 == 0 && selectedPoint != 0 && 
                selectedPoint+1 < points.size()){
                double[] a = (double[])points.elementAt(selectedPoint-1);
                double[] b = (double[])points.elementAt(selectedPoint+1);
                a[0] += (x - p[0]);
                a[1] += (y - p[1]);
                b[0] += (x - p[0]);
                b[1] += (y - p[1]);
            }
            p[0] = x; p[1] = y;
        }
        damage = true;
        return true;
    }

    public boolean mouseMove(Event evt, int x, int y){
        damage = true;
        return true;
    }

    public boolean keyUp(Event evt, int key){
        damage = true;
        return true;
    }

    public boolean keyDown(Event evt, int key){
        //System.out.println("key: "+(char)key+" KEY: "+key);
        if((key == 'd' || key == 'D' || key == 127) && selectedPoint != -1){
            points.removeElementAt(selectedPoint);
            selectedPoint = -1;
        }
        damage = true;
        return true;
    }
    
}



