//
/*
   Need to have each Polly follow a path.
*/

import render.*;
import java.util.*;
import java.awt.*;

public class Follow extends RenderApplet
{
   int N = 9, S = 65;
   Polly polly[] = new Polly[N];
   PathFinder pf;
   Geometry marker[][] = new Geometry[N][S];

   double R[]   = new double[N];
   double X[][] = new double[N][S];
   double Z[][] = new double[N][S];

   double ends[][] = {
	              {-4,-2,    4, 3},
	              {-3,-3,    3, 2},
                      {-2,-2,    2, 3},
                      {-1,-3,    1, 2},
		      { 0,-2,    0, 3},
		      { 1,-3,   -1, 2},
		      { 2,-2,   -2, 3},
		      { 3,-3,   -3, 2},
		      { 4,-2,   -4, 3},
   };

   public boolean keyUp(Event e, int k) {          // SET ACTIONS VIA KEYBOARD
      if (! super.keyUp(e, k))
         key(k);
      return true;
   }

   int n = 0;
   public void key(int k) {
      if (k >= '0' && k < '0' + N)
         n = k - '0';
      else if (k >= 'a' && k <= 'a' + Polly.nActions)
         polly[n].setAction(k - 'a');
   }

   double w[][] = { {6,4, -6,4, -6,-4, 6,-4, 6,4}}; // WALL DATA

   void createPaths(int state) {
      for (int i = 0 ; i < N ; i++) {
         for (int s = 1 ; s < S-1 ; s++)
            X[i][s] = Z[i][s] = 0;
         R[i] = .7;
	 X[i][  0] = ends[i][state==0 ? 0 : 2];
	 Z[i][  0] = ends[i][state==0 ? 1 : 3];
	 X[i][S-1] = ends[i][state==0 ? 2 : 0];
	 Z[i][S-1] = ends[i][state==0 ? 3 : 1];
      }
      pf = new PathFinder(R, X, Z);
      pf.findPaths();
   }

   public void initialize() {                       // INITIALIZE EVERYTHING

      // CREATE THE PATHS FOR THE POLLYS TO FOLLOW

      createPaths(0);

      // SET UP THE SCENE TO BE RENDERED

      addLight(1,1,1, 1,1,1);          // LIGHTS
      addLight(0,-1,0, 1,1,1);
      setBgColor(.2,.2,.8);            // BACKGROUND COLOR
      setFL(12);                       // CAMERA FOCAL LENGTH
      push();
         translate(-.5,0,0);
	 rotateX(Math.PI/2);
	 transform(world);             // INITIAL VIEW ANGLE
      pop();

      world.add().setMaterial(
         (new Material()).setColor(0,1,0).setTransparency(.5));
      world.child[0].mesh(10, 10).setDoubleSided(true);
      push();                          // MAKE THE TRANSPARENT FLOOR
	 scale(6,1,4);
	 rotateX(-Math.PI/2);
	 transform(world.child[0]);
      pop();

      Geometry walls = world.add().setMaterial(
         (new Material()).setColor(1,1,1).setTransparency(.5));
      walls.setDoubleSided(true);

      Polly.clearWalls();
      for (int i = 0 ; i < w.length ; i++) {
         Polly.addWall(w[i]);
         makeWall(walls, w[i]);
      }

      Polly.clearPollys();

      for (int i = 0; i < N ; i++) {
         polly[i] = new Polly();
         world.add(polly[i]);

         polly[i].setPosition(X[i][0], Z[i][0]);
         setDirection(i, X[i][1]-X[i][0], Z[i][1]-Z[i][0]);
         polly[i].setAction("swagger");
	 polly[i].avoidActors(false);
	 polly[i].avoidWalls(false);
         polly[i].setColor(s(i+1),s(i+2),s(i));
/*
         Material m0 = (new Material()).setColor(1,0,0);
         Material m1 = (new Material()).setColor(0,0,1);
	 for (int s = 0 ; s < S ; s++) {
	    world.add((marker[i][s] = new Geometry()).cube());
	    marker[i][s].setMaterial(s < S/2 ? m0 : m1);
	    placeMarker(i,s,0,0);
         }
*/
      }
   }
   double s(double x) { return .5 + .5 * Math.sin(x*x); }

   double norm(double x, double z) {
      return Math.sqrt(x*x + z*z);
   }

   void setDirection(int i, double dx, double dz) {
      polly[i].setDirection(Math.atan2(dx,dz));
   }

   Random random = new Random();
   double rand() { return 2 * random.nextDouble() - 1; }

   void makeWall(Geometry g, double w[]) {
      for (int j = 0 ; j < w.length/2 - 1 ; j++) {
         double ax = w[2*j  ], az = w[2*j+1],
                bx = w[2*j+2], bz = w[2*j+3];
         push();
            double dx = (bx-ax)/2, dz = (bz-az)/2;

            Geometry wall = g.add();
            wall.mesh((int)Math.sqrt(dx*dx+dz*dz)+2, 2);

            translate((ax+bx)/2, .25, (az+bz)/2);
	    rotateY(Math.atan2(-dz, dx));
	    scale(Math.sqrt(dx*dx + dz*dz), .25, 1);
            transform(wall);
         pop();
      }
   }

   int step = 0;
   int state = 0;
   double pxz[] = new double[2];
   public void animate(double time) {              // ANIMATE ONE FRAME
      pf.relax();
      for (int i = 0 ; i < N ; i++)
         polly[i].animate(time);
      if (step == S)
         return;

      boolean advance = true;
      for (int i = 0 ; i < N ; i++) {
/*
         for (int s = 0 ; s < S ; s++)
            placeMarker(i,s, X[i][s], Z[i][s]);
*/
         if (norm(X[i][step] - polly[i].x, Z[i][step] - polly[i].z) >= .5)
            advance = false;
      }
      if (advance) {
         step++;
         if (step < S)
            for (int i = 0 ; i < N ; i++) {
               setDirection(i, X[i][step]-polly[i].x, Z[i][step]-polly[i].z);
               polly[i].setThrottle(norm(X[i][step] - polly[i].x, Z[i][step] - polly[i].z));
            }
      }  
      if (step == S) {
         createPaths(state = 1 - state);
         step = 0;
      } 
   }

   void placeMarker(int i, int s, double x, double z) {
      push();
         identity();
	 translate(x,.01,z);
         scale(.03,.01,.03);
	 transform(marker[i][s]);
      pop();
   }
}