import vrml.*;
import vrml.node.*;
import vrml.field.*;

public class Missle extends Script
{
	final static int IDLE = 0;
	final static int MOVING = 1;
	final static int EXPLODE = 2;
	final static int RELOAD = 3;
	
	//internal
	private int state;
	private float initial[];
	private float delta[];
	private float des[];
	private Browser b;
	private float s;
	private boolean isHit;

	//fields
	private float velocity;
	private float damage;
    private Node thisMissle;
	private Node owner;
	private Node ownerScript;
	private MFNode otherRobot;
    private Node world;
	private Node choice;
	private Node clock;

	//outputs
	private SFVec3f translation_changed;
	private SFRotation rotation_changed;
	private SFVec3f scale_changed;
	private SFInt32 choice_changed;
	private MFNode addChildren_Robot,removeChildren_Robot;
	private MFNode addChildren_World,removeChildren_World;
	private SFInt32 missle_hit;

	// This method is called when the script is loaded
	public void initialize()
	{
		SFVec3f temp;
		
		initial = new float[3];
		delta = new float[3];
		des = new float[3];
		state = IDLE;

		velocity = ((SFFloat) getField("velocity")).getValue();
		damage = ((SFFloat) getField("damage")).getValue();
		thisMissle = (Node) ((SFNode) getField("thisMissle")).getValue();
		owner = (Node) ((SFNode) getField("owner")).getValue();
		ownerScript = (Node) ((SFNode) getField("ownerScript")).getValue();
		world = (Node) ((SFNode) getField("world")).getValue();
		choice = (Node) ((SFNode) getField("choice")).getValue();
		clock = (Node) ((SFNode) getField("clock")).getValue();
		otherRobot = (MFNode) getField("otherRobot");
	
		temp = (SFVec3f)thisMissle.getExposedField("translation");
		initial[0] = temp.getX();
		initial[1] = temp.getY();
		initial[2] = temp.getZ();
	
		//eventouts
		addChildren_Robot = (MFNode) getEventOut("addChildren_Robot");
		removeChildren_Robot = (MFNode) getEventOut("removeChildren_Robot");
		addChildren_World = (MFNode) getEventOut("addChildren_World");
		removeChildren_World = (MFNode) getEventOut("removeChildren_World");
		translation_changed = (SFVec3f) getEventOut("translation_changed");
		scale_changed = (SFVec3f) getEventOut("scale_changed");
		choice_changed = (SFInt32) getEventOut("choice_changed");
		missle_hit = (SFInt32) getEventOut("missle_hit");
		rotation_changed = (SFRotation) getEventOut("rotation_changed");
		b = world.getBrowser();
		
		//routings
		b.addRoute(this,"translation_changed",thisMissle,"set_translation");
		b.addRoute(this,"scale_changed",thisMissle,"set_scale");
		b.addRoute(this,"choice_changed",choice,"set_whichChoice");
		b.addRoute(this,"rotation_changed",thisMissle,"set_rotation");

		b.addRoute(this,"addChildren_Robot",owner,"addChildren");
		b.addRoute(this,"removeChildren_Robot",owner,"removeChildren");
		b.addRoute(this,"addChildren_World",world,"addChildren");
		b.addRoute(this,"removeChildren_World",world,"removeChildren");

		b.addRoute(this,"missle_hit",ownerScript,"missle_hit");
		b.addRoute(clock,"fraction_changed",this,"set_fraction");

	}

	private void set_fraction(ConstSFFloat frac)
	{
		int i;
		float l;
		SFVec3f m,d;
		
		switch (state)
		{
			case IDLE:
				break;
			case MOVING:
				m = (SFVec3f)thisMissle.getExposedField("translation");
				isHit = false;
				for (i=0; i<otherRobot.getSize(); i++)
				{
					d = (SFVec3f)((Node)otherRobot.get1Value(i)).getExposedField("translation");
					l = (float)Math.sqrt( (m.getX()-d.getX())*(m.getX()-d.getX())+(m.getY()-d.getY()-1.0f)*(m.getY()-d.getY()-1.0f)+
						                  (m.getZ()-d.getZ())*(m.getZ()-d.getZ()) );
					if (l < 0.5f)
					{
						isHit = true;
						break;
					}
				}
				if (!isHit)
				{
					if ( (Math.abs(m.getX()) > 8.0) || (Math.abs(m.getZ()) > 8.0) )
						state = RELOAD;
					else
						translation_changed.setValue(m.getX()+delta[0],m.getY()+delta[1],m.getZ()+delta[2]);
				}
				else
				{
					choice_changed.setValue(1);
					s = 1.0f;
					state = EXPLODE;
				}
				break;
			case EXPLODE:
				if (s < 10.0)
				{
					s = s+1.0f;
					scale_changed.setValue(s,s,s);
				}
				else
				{
					state = RELOAD;
				}
				break;
			case RELOAD:
				if (isHit)
					missle_hit.setValue(0);
				else
					missle_hit.setValue(-1);
				scale_changed.setValue(1.0f,1.0f,1.0f);
				choice_changed.setValue(-1);
				removeChildren_World.set1Value(0,thisMissle);
				addChildren_Robot.set1Value(0,thisMissle);
				translation_changed.setValue(initial[0],initial[1],initial[2]);
				rotation_changed.setValue(0.0f,0.0f,0.0f,0.0f);
				state = IDLE;
				break;
		}
	}

	private void set_target(ConstSFVec3f t)
	{
		
		float l,dx,dy,dz;
		SFVec3f r,m;
		float rr[] = {0.0f,0.0f,0.0f,0.0f};

		r = (SFVec3f)owner.getExposedField("translation");
		m = (SFVec3f)thisMissle.getExposedField("translation");
		((SFRotation)owner.getExposedField("rotation")).getValue(rr);
		removeChildren_Robot.set1Value(0,thisMissle);
		addChildren_World.set1Value(0,thisMissle);

		translation_changed.setValue(m.getX()+r.getX(),m.getY()+r.getY(),m.getZ()+r.getZ());
		rotation_changed.setValue(rr[0],rr[1],rr[2],rr[3]);

		dx = t.getX()-m.getX();
		dy = t.getY()-m.getY()+1.0f;
		dz = t.getZ()-m.getZ();
		l = (float)Math.sqrt(dx*dx+dy*dy+dz*dz);

		delta[0] = dx/l*velocity;
		delta[1] = dy/l*velocity;
		delta[2] = dz/l*velocity;
		state = MOVING;
		choice_changed.setValue(0);
	}

	// In Java, you have to explicitly handle each event using the
	// processEvent method. Use it to call a private method for each event. 
	public void processEvent (Event e) 
	{
		String EventName = e.getName();

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