// person.java: simulates a person making a throwing motion
// 
// Michael Jeon / cs184-dq
//

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

public class person extends Script {

	// constants
	private final boolean debug = true;
	private final boolean right_arm = true;
	private final float quickness = 0.1f;
	private final float UAlimit = -2.0f; // UpperArm angle limit
	private final float LAlimit = -2.0f; // LowerArm angle limit
	private final int Rlimit = 20; // Rotation limit

	// eventOuts
	private SFRotation RightUpperArmMovement;
	private SFRotation RightLowerArmMovement;
	private SFRotation LeftUpperArmMovement;
	private SFRotation LeftLowerArmMovement;
	private SFRotation RightLegMovement;
	private SFRotation LeftLegMovement;
	private SFRotation BallAngle;
	private SFRotation PersonAngle;

	// variables
	private float RUA[];
	private float RLA[];
	private float LUA[];
	private float LLA[];
	private float RL[];
	private float LL[];
	private float BA[];
	private float PA[];
	private boolean aiming;
	private boolean throwing;
	private boolean isNow;
	private boolean rotating;
	private boolean overlimit;
	private boolean U_done , L_done;
	private boolean throwing_arm = right_arm;
	private int progress;

	public void initialize() {

		// initialize variables
		RUA = new float[4];
		RLA = new float[4];
		LUA = new float[4];
		LLA = new float[4];
		RL = new float[4];
		LL = new float[4];
		BA = new float[4];
		PA = new float[4];
		aiming = false;
		throwing = false;
		rotating = false;
		overlimit = false;
		U_done = false;
		L_done = false;
		isNow = false;
		progress = 0;

		// get handles to eventOuts from the VRML environment
		RightUpperArmMovement = (SFRotation)getEventOut("RightUpperArmMovement");
		RightLowerArmMovement = (SFRotation)getEventOut("RightLowerArmMovement");
		LeftUpperArmMovement = (SFRotation)getEventOut("LeftUpperArmMovement");
		LeftLowerArmMovement = (SFRotation)getEventOut("LeftLowerArmMovement");
		RightLegMovement = (SFRotation)getEventOut("RightLegMovement");
		LeftLegMovement = (SFRotation)getEventOut("LeftLegMovement");
		BallAngle = (SFRotation)getEventOut("BallAngle");
		PersonAngle = (SFRotation)getEventOut("PersonAngle");

		RUA[0] = 1f; RUA[1] = 0f; RUA[2] = 0f; RUA[3] = 0f;
		RLA[0] = 1f; RLA[1] = 0f; RLA[2] = 0f; RLA[3] = 0f;
		LUA[0] = 1f; LUA[1] = 0f; LUA[2] = 0f; LUA[3] = 0f;
		LLA[0] = 1f; LLA[1] = 0f; LLA[2] = 0f; LLA[3] = 0f;
		RL[0] = 1f; RL[1] = 0f; RL[2] = 0f; RL[3] = 0f;
		LL[0] = 1f; LL[1] = 0f; LL[2] = 0f; LL[3] = 0f;
		BA[0] = 1f; BA[1] = 0f; BA[2] = 0f; BA[3] = 0f;
		PA[0] = 0f; PA[1] = 1f; PA[2] = 0f; PA[3] = 0f;
	}

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

		if (EventName.equals("set_fraction"))
			set_fraction((ConstSFFloat) e.getValue());
		else if (EventName.equals("set_aim_button"))
			set_aim_button(((ConstSFBool) e.getValue()).getValue());
		else if (EventName.equals("set_throw_button"))
			set_throw_button(((ConstSFBool) e.getValue()).getValue());
		else if (EventName.equals("set_rotate_button"))
			set_rotate_button(((ConstSFBool) e.getValue()).getValue());
	}

	private void set_fraction(ConstSFFloat frac) {
		if (aiming)
			aim_and_throw();
		else if (rotating)
			rotate();
	}

	private void set_aim_button(boolean flg) {
		if (!rotating)
		aiming = true;
	}

	private void set_throw_button(boolean flg) {
		if (aiming && !rotating) {
			isNow = true;
			throwing = true;
		}
	}

	private void set_rotate_button(boolean flg) {
		if (!aiming)
			rotating = true;
	}

	private void rotate() {
		double leg_angle;
		float person_angle;

		if (progress < Rlimit) {
			progress++;
			
			if (progress == Rlimit) {
				progress = 0;
				rotating = false;
			}

			leg_angle = ((double) progress) / ((double) Rlimit) * 6.28;
			RL[3] = ((float) 0.5) * ((float) Math.sin(leg_angle));
			LL[3] = -1f * RL[3];

			RightLegMovement.setValue(RL);
			LeftLegMovement.setValue(LL);

			person_angle = 1f / ((float) Rlimit) * 0.157f;
			PA[3] += person_angle;
			
			if (PA[3] >= 6.28f)
				PA[3] = 0f;

			PersonAngle.setValue(PA);
			dprint("PersonAngle = " + PA[3]);
		}
	}

	private void aim_and_throw() {
		if (throwing_arm == right_arm) {
			if (RUA[3] > UAlimit && !throwing && !overlimit) {
				RUA[3] -= quickness;
				RightUpperArmMovement.setValue(RUA);
			}
			else if (RLA[3] > LAlimit && !throwing && !overlimit) {
				RLA[3] -= quickness;
				RightLowerArmMovement.setValue(RLA);
	
				if (RLA[3] <= LAlimit)
					overlimit = true;
			}
			else if (overlimit || throwing) { // when the arm is over the limit, or 'throw' is pushed
				float throw_vel = 1f;

				if (throwing) {
					throw_vel = 6f;
					
					if (isNow) {
						isNow = false;
						BA[3] = -1f * (RLA[3] + RUA[3]);
						BallAngle.setValue(BA);
						dprint("BallAngel = " + BA[3]);
					}					

					if (RLA[3] >= 0f)
						L_done = true;
					if (RUA[3] >= 0f)
						U_done = true;
				}

				if (RLA[3] < 0f) {
					RLA[3] += (throw_vel * quickness);
					if (RLA[3] >= 0f)
						L_done = true;
					RightLowerArmMovement.setValue(RLA);
				}
				if (RUA[3] < 0f) {
					RUA[3] += (throw_vel * quickness);
					if (RUA[3] >= 0f)
						U_done = true;
					RightUpperArmMovement.setValue(RUA);
				}

				if (U_done && L_done) {
					RUA[3] = 0f;
					RightUpperArmMovement.setValue(RUA);
					RLA[3] = 0f;
					RightLowerArmMovement.setValue(RLA);

					U_done = false;
					L_done = false;
					aiming = false;
					throwing = false;
					overlimit = false;
				}

			}
		}
		/*
		else if (throwing_arm != right_arm) {
			if (LUA[3] > UAlimit && !throwing) {
				LUA[3] -= quickness;
				LeftUpperArmMovement.setValue(LUA);
			}
			else if (LLA[3] > LAlimit && !throwing) {
				LLA[3] -= quickness;
				LeftLowerArmMovement.setValue(LLA);
			} 
		}
		*/
}

	private void dprint(String s) {
		if (debug)
			System.out.println(s);
	}
}