// 9/30/98 Lab 5 leader script
// Compiled using MS SDK Java 3.1 on Windows 98

import java.io.*;
import java.util.*;
import vrml.*;
import vrml.node.*;
import vrml.field.*;
import java.lang.Math;


public class leader extends Script
{
	// fields
	private SFString nodename;

	// eventouts
	private SFRotation rotation_changed;
	private SFVec3f translation_changed;
	
	// local vars
	private float arotation[]={0,1,0,0};
	private float translation[]={0,0,0};
	private float curx = 0f, cury = 0f, curz = 0f;
	private float destx = 30f, desty = 5f, destz = 3f;  // initial destination
	private float xdist = 30f, ydist = 5f, zdist = 3f;  // distance between dest and cur
	private float curAngle = 0f; //(float) Math.PI;		   // angle fish is pointing
	private float angleToRotate = 0f, angleDif, lastTime = 0f;
	private int destQuadrant = 1, curQuadrant = 2;
	private Random arand = new Random();
	
	public int findQuadrant(float x, float z)
	{
		if( (x >= 0) && (z >=0) )
			return 1;
		else if( (x >= 0) && (z < 0) )
			return 4;
		else if( (x < 0) && (z >= 0) )
			return 2;
		else
			return 3;
	}

	public void findAngle()  // finds the angle to turn to based on current and dest
	{
		// 0 angle means pointing towards positive x direction
		float anAngle = (float) Math.atan( (double) (destz-curz)/(destx-curx+0.0001f) );

		if( (destz >= curz) && (destx >= curx) )
			angleToRotate = (float)Math.PI - anAngle;
		else if( (destz < curz) && (destx >= curx) )
			angleToRotate = (float)Math.PI-anAngle;
		else if( (destz < curz) && (destx < curx) )
			angleToRotate = - anAngle;
		else
			angleToRotate = - anAngle;

		angleDif = angleToRotate - curAngle ;          // readjust so that we know what angle to rotate to.
	}

	public void initialize()
	{
		rotation_changed = (SFRotation) getEventOut("rotation_changed");
		translation_changed = (SFVec3f) getEventOut("translation_changed");
		nodename = (SFString) getField("nodename");

		destQuadrant = findQuadrant(destx, destz);
		findAngle();
		setDistances();
	}

	public void processEvent(Event e)
	{
		String EventName = e.getName();

		if(EventName.equals("set_fraction"))
			set_fraction((ConstSFFloat)e.getValue());
		
	}

	private boolean randomNegative()
	{
		if(arand.nextFloat() >= .5)
			return true;
		else
			return false;
	}

	private void setDistances()
	{
		xdist = destx - curx;
		ydist = desty - cury;
		zdist = destz - curz;
	}

	private void set_fraction(ConstSFFloat temp)
	{
		float frac = temp.getValue();

		if(frac >= 1.0f)
		{
			System.out.println("Something WRONG! Can't have fraction > 1");
			return;
		}

	
		if(lastTime <= frac)
		{
			
			if(frac < .4f)			// have the fish turn by 0.4 of the whole sequence
				arotation[3]= (frac/0.4f)*angleDif+curAngle;
			else
			{
				arotation[3]= angleToRotate;
				curAngle = angleToRotate;
			}

			translation[0] = xdist*frac+curx;
			translation[1] = ydist*frac+cury;
			translation[2] = zdist*frac+curz;
			lastTime = frac;

			rotation_changed.setValue(arotation);
			translation_changed.setValue(translation);
		}
		else  // as soon as the timer loops...
		{
			// should have arrived at destination now.
			translation[0] = destx;
			translation[1] = desty;
			translation[2] = destz;
			lastTime = 0f;

			rotation_changed.setValue(arotation);
			translation_changed.setValue(translation);
			
			curx = destx;
			cury = desty;
			curz = destz;

			// now find new worlds to discover
			float blah = arand.nextFloat()*5f;
			if(randomNegative())
				blah = -blah*1.05f;
			desty += blah;
			
			curQuadrant = destQuadrant;
			switch(curQuadrant)
			{
				case 1:
					destx += arand.nextFloat()*7;
					destz += -arand.nextFloat()*6.2-.2f;
					break;
				case 2:
					destx += arand.nextFloat()*6.2+.2f;
					destz += arand.nextFloat()*7;
					break;
				case 3:
					destx += -arand.nextFloat()*7.2;
					destz += arand.nextFloat()*6+.2f;
					break;
				case 4:
					destx += -arand.nextFloat()*6.2-.2f;
					destz += -arand.nextFloat()*7;
					break;
			}

			if(destx >= 40)
				destx = 34f;
			if(destx <= -40)
				destx = -34f;
			if(destz >= 40)
				destz = 34f;
			if(destz <= -40)
				destz = -34f;

			if( ( Math.pow((double)destx, 2) + Math.pow((double)destz, 2) ) >= 1600 )
			{
				if( (destx >= 0) && (destz >= 0) )
				{
					if( destx >= destz)
					{
						destz -= 4.5f;
						destx = (float) Math.sqrt( 1600 - Math.pow( (double)destz, 2)) - 4f;
					}
					else
					{
						destx -= 4.5f;
						destz = (float) Math.sqrt( 1600 - Math.pow((double)destx, 2)) - 4f;
					}
				}

				if( (destx >= 0) && (destz < 0) )
				{
					if( destx >= -destz)
					{
						destz += 4.5f;
						destx = (float) Math.sqrt( 1600 - Math.pow((double)destz, 2)) - 4f;
					}
					else
					{
						destx -= 4.5f;
						destz = (float) -Math.sqrt( 1600 - Math.pow((double)destx, 2)) + 4f;
					}
				}

				if( (destx < 0) && (destz >= 0) )
				{
					if( destz >= -destx)
					{
						destx += 4.5f;
						destz = (float) Math.sqrt( 1600 - Math.pow((double)destx, 2)) - 4f;
					}
					else
					{
						destz -= 4.5f;
						destx= (float) -Math.sqrt( 1600 - Math.pow((double)destz, 2)) + 4f;
					}
				}

				if( (destx < 0) && (destz < 0) )
				{
					if( -destx >= -destz)
					{
						destz += 4.5f;
						destx = (float) -Math.sqrt( 1600 - Math.pow((double)destz, 2)) + 4f;
					}
					else
					{
						destx += 4.5f;
						destz = (float) -Math.sqrt( 1600 - Math.pow((double)destx, 2)) + 4f;
					}
				}
			}

			if(desty >= 15)
				desty = 11f;
			if(desty <= -15)
				desty = -11f;

			System.out.println("New Destination: "+destx+", "+desty+", "+destx);

			setDistances();
			destQuadrant = findQuadrant(destx, destz);
			findAngle();
		}  // end else
	}  // end function
} // end class