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

public class Laser 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 Browser b;
	private int count;
	private float s;

	//fields
	private float damage;
    private Node thisLaser;
	private Node owner;
	private Node ownerScript;
    private Node world;
	private Node choice;
	private Node clock;

	//outputs
	private SFVec3f translation_changed;
	private SFVec3f scale_changed;
	private SFInt32 choice_changed;
	private SFInt32 laser_hit;

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

		damage = ((SFFloat) getField("damage")).getValue();
		thisLaser = (Node) ((SFNode) getField("thisLaser")).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();
	
		temp = (SFVec3f)thisLaser.getExposedField("translation");
		initial[0] = temp.getX();
		initial[1] = temp.getY();
		initial[2] = temp.getZ();
	
		//eventouts		
		translation_changed = (SFVec3f) getEventOut("translation_changed");
		scale_changed = (SFVec3f) getEventOut("scale_changed");
		choice_changed = (SFInt32) getEventOut("choice_changed");
		laser_hit = (SFInt32) getEventOut("laser_hit");

		b = world.getBrowser();
		
		//routings
		b.addRoute(this,"translation_changed",thisLaser,"set_translation");
		b.addRoute(this,"scale_changed",thisLaser,"set_scale");
		b.addRoute(this,"choice_changed",choice,"set_whichChoice");
		b.addRoute(clock,"fraction_changed",this,"set_fraction");
		
		b.addRoute(this,"laser_hit",ownerScript,"laser_hit");
	}

	private void set_fraction(ConstSFFloat frac)
	{
		int i;
		SFVec3f l,d;
		boolean isHit;
		
		switch (state)
		{
			case IDLE:
				break;
			case MOVING:
				if (count < 5)
				{
					count++;
				}
				else
				{
					translation_changed.setValue(initial[0],initial[1],initial[2]+s);
					choice_changed.setValue(1);
					state = EXPLODE;
					s = 1.0f;
				}
				//m = (SFVec3f)thisLaser.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())*(m.getY()-d.getY())+
						                  (m.getZ()-d.getZ())*(m.getZ()-d.getZ()) );
					if (l < 0.5f)
					{
						missle_hit.setValue(i);
						isHit = true;
						break;
					}
				}
				if (!isHit)
				{
					if ( (Math.abs(m.getX()) > 8.0) || (Math.abs(m.getY()) > 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 < 3.0)
				{
					s = s+0.5f;
					scale_changed.setValue(s,s,s);
				}
				else
				{
					state = RELOAD;
				}
				break;
			case RELOAD:
				laser_hit.setValue(0);
				scale_changed.setValue(1.0f,1.0f,1.0f);
				choice_changed.setValue(-1);
				translation_changed.setValue(initial[0],initial[1],initial[2]);
				state = IDLE;
				break;
		}
	}

	private void set_target(ConstSFVec3f t)
	{
		SFVec3f r,l;
		float dx,dz;

		r = (SFVec3f)owner.getExposedField("translation");
		l = (SFVec3f)thisLaser.getExposedField("translation");
		

		dx = t.getX()-r.getX();
		dz = t.getZ()-r.getZ();
		choice_changed.setValue(0);
		s = (float)Math.sqrt(dx*dx+dz*dz);
		translation_changed.setValue(l.getX(),l.getY(),l.getZ()+s/2.0f);
		scale_changed.setValue(1.0f,1.0f,s);
		count = 0;
		state = MOVING;
	}

	// 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());		
	}
}