
import java.awt.*;
import java.applet.*;

/*
 * Can be run either as a standalone application by
 * typing "java hwrveloc" or as an applet in the AppletViewer.
 */


class hwrVelocCanvas extends Canvas {

    /* begin object attributes */

    public Event ev_changed = new Event(this, Event.ACTION_EVENT,"VelocEvent");
    public Event ev_cursor = new Event(this, Event.ACTION_EVENT,"CursorEvent");
    public Event ev_minima = new Event(this, Event.ACTION_EVENT,"MinimaEvent");

    Font	Font;
    double      Vmax;

    double      Box_xmargin = 0.05; /* LR symmetrical of graphbox on canvas */
    double      Box_ymargin = 0.15; /* bottom margin of graphbox on canvas */
    double      Hwrmargin = 0.02;   /* all sides within graphics box */
    double      Xpix, Ypix, Wpix, Hpix;

    int         Cursor = -1;

    hwrCoord    H;

    double Time[];
    double Vabs[];
    int Npoints;

    boolean     ShowMinima = false;
    boolean     oldShowMinima = !ShowMinima;

    /* end object attributes */

    public void calc() {
        double dx, dy;
        Npoints = H.Npoints;
        Time = new double [H.Npoints];
        Vabs = new double [H.Npoints];

        H.Vbs.Nsegm = 0;
        for(int i = 1; i < Npoints; ++i) {
               Time[i] = (double) i-1;
               dx = H.X[i] - H.X[i-1];
               dy = H.Y[i] - H.Y[i-1];
               Vabs[i] = Math.sqrt(dx*dx + dy*dy);
        }
        Vabs[0] = Vabs[1];
        Time[0] = (double) 0;

	if(ShowMinima) {
           calc_vbs();
        } else {
           H.Vbs.Nsegm = 0;
        }
//        if(ShowMinima != oldShowMinima) {
           deliverEvent(ev_minima);
//           oldShowMinima = ShowMinima;        
//        }

    }

    private void calc_vbs() {
        H.Vbs.Nsegm = 0;
        if(Vabs[0] < Vabs[1]) {
            H.Vbs.t[0] = 0;
            ++H.Vbs.Nsegm;
        }
        for(int i = 2; i < Npoints - 2; ++i) {
           if((Vabs[i] <= Vabs[i-2] &&
               Vabs[i] <= Vabs[i-1] && 
               Vabs[i] <  Vabs[i+1] &&
               Vabs[i] <  Vabs[i+2]) ||
              (Vabs[i] <  Vabs[i-2] &&
               Vabs[i] <  Vabs[i-1] && 
               Vabs[i] <= Vabs[i+1] &&
               Vabs[i] <= Vabs[i+2]) ) {
                  H.Vbs.t[H.Vbs.Nsegm] = i;
                  ++H.Vbs.Nsegm;
           }
        }
        if(Vabs[Npoints - 1] < Vabs[Npoints - 2]) {
            H.Vbs.t[H.Vbs.Nsegm] = 0;
            ++H.Vbs.Nsegm;
        }
    }

    void scale() {
         int kk;

         Vmax = Vabs[0];

         for(kk = 1; kk < Npoints; ++kk) {
                if( Vabs[kk] > Vmax) {
                    Vmax = Vabs[kk];
                }
         }
    } 

    public void paint(Graphics g) {
        init(g);
        calc();
        scale();
        draw(g);
        annot(g);
    }

    public void annot(Graphics g) {

        g.drawString("V(t)", 2, (int) (Ypix + Hpix/2.));


        g.drawString("t", (int) (Xpix + Wpix/2), (int) (Ypix + Hpix + 18.));

/* arrow */

        g.drawLine((int) (Xpix + Wpix/2) + 10, (int) (Ypix + Hpix + 14.)
                 , (int) (Xpix + Wpix/2) + 30, (int) (Ypix + Hpix + 14.));

        g.drawLine((int) (Xpix + Wpix/2) + 30, (int) (Ypix + Hpix + 14.)
                 , (int) (Xpix + Wpix/2) + 27, (int) (Ypix + Hpix + 11.));

        g.drawLine((int) (Xpix + Wpix/2) + 30, (int) (Ypix + Hpix + 14.)
                 , (int) (Xpix + Wpix/2) + 27, (int) (Ypix + Hpix + 17.));


/* ms */
        g.drawLine(scalex(Npoints - 15), (int) (Ypix + Hpix + 4.)
                 , scalex(Npoints-5), (int) (Ypix + Hpix + 4.));
        g.drawLine(scalex(Npoints - 15), (int) (Ypix + Hpix + 2.)
                 , scalex(Npoints - 15), (int) (Ypix + Hpix + 4.));
        g.drawLine(scalex(Npoints - 5), (int) (Ypix + Hpix + 2.)
                 , scalex(Npoints - 5), (int) (Ypix + Hpix + 4.));

        g.drawString("100 ms", scalex(Npoints - 22), (int) (Ypix + Hpix + 18.));


        g.drawString("Velocity of " + H.Inkfilename
                              , (int) Xpix, bounds().height - 4);
    }

    void init(Graphics g) /* init and draw graphics box */
    {
        int x1,y1,x2,y2;

	Rectangle box = bounds();

	g.setColor(Color.black);
	g.setFont(Font);

/* canvas */

        x1 = 0; /* is left */
        y1 = 0; /* is top */

        x2 = box.width - 1;
        y2 = box.height - 1;

	g.drawLine(x1, y1, x1, y2 );
	g.drawLine(x1, y2, x2, y2);
	g.drawLine(x2, y2, x2, y1);
	g.drawLine(x2, y1, x1, y1);

/* graphics area */

        x1 = (int) (Box_xmargin * box.width);
        y1 = (int) (0.04 * box.height); /* is top */

        x2 = (int) ((1. - Box_xmargin) * box.width);
        y2 = (int) ((1. - Box_ymargin) * box.height);

	g.drawLine(x1, y1, x1, y2 );
	g.drawLine(x1, y2, x2, y2);
	g.drawLine(x2, y2, x2, y1);
	g.drawLine(x2, y1, x1, y1);

/* Remember that this is the graphics box */

        Xpix = x1;
        Ypix = y1;
        Wpix = x2 - x1 + 1;
        Hpix = y2 - y1 + 1;

	g.setColor(Color.blue);

    }

    private void draw(Graphics g) 
    {
        for (int i =  1; i < (Npoints - 1); i++) {

              g.drawLine(scalex(Time[i]), scaley(Vabs[i])
                             , scalex(Time[i+1]), scaley(Vabs[i+1]));
        }

        if(Cursor >= 0 && Cursor < Npoints) {
             Color now = g.getColor();
	     g.setColor(Color.red);
             g.fillArc(scalex(Time[Cursor])-4
                      ,scaley(Vabs[Cursor])-4, 8, 8, 0, 360);
	     g.setColor(now);
        }

        if(H.Vbs.Nsegm > 0 && ShowMinima == true) {
            Color now = g.getColor();
	    g.setColor(Color.green);
            for (int i =  0; i < H.Vbs.Nsegm; i++) {
             g.fillArc(scalex(Time[H.Vbs.t[i]])-3
                      ,scaley(Vabs[H.Vbs.t[i]])-3, 6, 6, 0, 360);
            }
	    g.setColor(now);
        }

    }

    private int scalex(double r)
    {
        return((int) (Xpix + Wpix * r / (double) Npoints));
    }

    private int scaley(double r)
    {
        return((int) (Ypix + (Hpix-1.) * ( 1. - 0.95 * r/Vmax)));
    }

    public void redraw() {
        repaint();
        deliverEvent(ev_changed);
    }

    public boolean mouseDown(Event e, int nx, int ny) {
        Cursor = (int) ((double) Npoints * (double) (nx - Xpix)/ (double) Wpix + 0.5);
        repaint();
        deliverEvent(ev_cursor);
        return true;
    }

    public boolean mouseDrag(Event e, int nx, int ny) {
        Cursor = (int) ((double) Npoints * (double) (nx - Xpix)/ (double) Wpix + 0.5);
        repaint();
        deliverEvent(ev_cursor);
        return true;
    }
}

class hwrVelocControls extends Panel {
    hwrVelocCanvas canvas;
    Scrollbar Boxcarwidth_slider;

    public hwrVelocControls(hwrVelocCanvas canvas) {
	this.canvas = canvas;

	add(new Button("Minima"));
    }

    public boolean handleEvent(Event ev) {
        if (ev.target instanceof Scrollbar) {
	    canvas.redraw();
	    return true;
	}

	if (ev.target instanceof Button) {
            if(this.canvas.ShowMinima == true) {
               this.canvas.ShowMinima = false;
            } else {
               this.canvas.ShowMinima = true;
            }

       	    canvas.redraw();
	    return true;
	}

	return false;
    }
}


class hwrVelocPanel extends Panel {
     hwrVelocControls controls;
     hwrVelocCanvas canvas;
 
     public hwrVelocPanel() {
        canvas = new hwrVelocCanvas();
        controls = new hwrVelocControls(canvas);

        this.setLayout(new BorderLayout());
        add("Center",canvas);
        add("South", controls);
     }

    public boolean handleEvent(Event ev) {
	return false;
    }
}

/* end hwrveloc.java */
