///////////////////////////////////////////////////////////////////////////
//  VI profile plotting applet for GeoTC.                                //
///////////////////////////////////////////////////////////////////////////
//
//  Master source is at
//    http://www.abelian.demon.co.uk/tssp/geotc/geoplot.java
//
//  Maintained by Paul Nicholson, paul@abelian.demon.co.uk
//

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

public class Fpoint 
{
   public double x;
   public double y;

   public Fpoint( double x, double y)
   {
      this.x = x;
      this.y = y;
   }
}

public class geoplot extends Applet {

   public boolean ecor_flag = false;
   public boolean wbox_flag = false;
   public String title = "";
   public int N = 0;
   public Fpoint points[] = new Fpoint[100];
   public Color bgnd = Color.green;
   public String bcolor = null;

   public void init() 
   {
      N = 0;

      String s = getParameter( "wbox");
      if( s != null && s.equals( "yes")) wbox_flag = true;     
   }

   public void add_point( double x, double y)
   {
      points[N++] = new Fpoint( x, y);
   }

   public void set_title( String s)
   {
      title = s;
      repaint();
   }

   public static Fpoint bezier( int N, Fpoint a[], double s) 
   {
      for( int j=N ; j>0; j--) 
         for( int i=1; i<j; i++) 
         {
            Fpoint p0 = a[i-1];
            Fpoint p1 = a[i];
            a[i-1] = new Fpoint( s * p1.x + (1-s) * p0.x, 
                                 s * p1.y + (1-s) * p0.y);
         }

      return a[0];
   }

   public void paint(Graphics g) 
   {
      if( bcolor == null) return;
      if( N == 0) return;

      Font font = g.getFont();
      FontMetrics fm = g.getFontMetrics();
      Dimension d = size();

      int rs = Integer.parseInt( bcolor.substring( 1,3), 16);
      int gs = Integer.parseInt( bcolor.substring( 3,5), 16);
      int bs = Integer.parseInt( bcolor.substring( 5,7), 16);
      g.setColor( new Color( rs, gs, bs));

      g.fillRect(0,0,d.width, d.height);
      int lbwid = d.width/20 + fm.stringWidth( "8.888");   // Left border width
      int gwid = d.width - lbwid;                    // Width of the graph box

      double maxd = 0;
      for( int i=0; i<N; i++) if( points[i].y > maxd) maxd = points[i].y;
      double xw = gwid/N;
      double vscale = d.height/(maxd * 1.1);
      g.setColor( Color.black);
      g.drawRect( lbwid, 0, gwid-1, d.height-1);

      if( wbox_flag)
      {
         g.setColor( Color.blue);
         double x = 0;
         for( int i=0; i<N; i++, x += xw)
         {
            int val = (int)(0.5 + points[i].y * vscale);
            g.fillOval( (int)(lbwid + points[i].x*gwid - 3),
                             d.height-val - 3, 6, 6);
         }
      }

      g.setColor( Color.black);
      g.drawString( title, 
                    lbwid+(gwid-fm.stringWidth(title))/2, 
                    d.height-fm.getHeight()-5);

      int k = 31, h = (int)(d.height * 0.1);
      for( int i=0; i<k; i++)
      {
         if( (i % 2) == 0)
            g.drawLine( lbwid + (i*gwid)/k, h, lbwid + ((i+1)*gwid)/k, h);
      }

      g.drawLine( lbwid -3, h-1, lbwid, h-1);
      g.drawLine( lbwid -3, h, lbwid, h);
      g.drawLine( lbwid -3, h+1, lbwid, h+1);

      maxd = Math.round( maxd * 10);
      maxd /= 10;
      String pval = Double.toString( maxd) + " ";
      g.drawString( pval, lbwid-fm.stringWidth(pval), h);
      
      int NP = gwid/10;
      Fpoint ptArray[] = new Fpoint[N];
      Fpoint erArray[] = new Fpoint[N];
      Fpoint rfArray[] = new Fpoint[NP+1];

      Fpoint p0, p1;

      p0 = new Fpoint( points[0].x, points[0].y);
      rfArray[0] = new Fpoint( p0.x, p0.y);
      g.setColor(Color.black);
      for (int i = 1 ; i <= NP; i++) 
      {
         double t = i/(double) NP;
         for( int j=0; j<N; j++)
            ptArray[j] = new Fpoint( points[j].x, points[j].y);

         p1 = bezier( N, ptArray, t);
         rfArray[i] = new Fpoint( p1.x, p1.y);
   
         if( !ecor_flag)
            g.drawLine( (int)(lbwid + p0.x * gwid), 
                        d.height - (int)(0.5 + p0.y * vscale), 
                        (int)(lbwid + p1.x * gwid), 
                        d.height - (int)(0.5 + p1.y * vscale));
         p0 = p1;
      }

      if( !ecor_flag) return;

      for( int i=0; i<N; i++)
      {
         int u = (int)(0.5 + NP * i/(double) (N-1));
         erArray[i] = new Fpoint( points[i].x, points[i].y - rfArray[u].y);
      }

      Fpoint grArray[] = new Fpoint[NP+1];
      g.setColor(Color.black);
      p0 = new Fpoint( erArray[0].x, erArray[0].y);
      grArray[0] = new Fpoint( p0.x, p0.y);
      for (int i = 1 ; i <= NP; i++) 
      {
         for( int j=0; j<N; j++) 
            ptArray[j] = new Fpoint( erArray[j].x, erArray[j].y);

         p1 = bezier( N, ptArray, i/(double) NP);
         double ecor = p0.y;
         grArray[i] = new Fpoint( rfArray[i].x, rfArray[i].y + ecor);
         g.drawLine( (int)(lbwid + p0.x * gwid), 
                     d.height - (int)(0.5 + (rfArray[i-1].y+ecor) * vscale),
                     (int)(lbwid + p1.x * gwid), 
                     d.height- (int)(0.5 + (rfArray[i].y+ecor) * vscale));
         p0 = p1;
      }
   }

   public String getAppletInfo()
   {
      return "Profile plots for GeoTC";
   }
}
