/*
 * robot.java
 * Aleksey Potashnik (cs184-bk)
 * Created on PC, NT4, MSJ++ 1.1
 * Project 1
 */

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


public class robot extends Script {

	final private float step_length = 2.0f;
	final private float step_lift = 1.2f;
	final private int frames = 10;

	final private float bx = step_length / frames;
	final private float zero_a = 4 * step_lift / step_length / step_length;
	final private int   zero_leg_delay = 5;
	final private float zero_other_angle = (float)Math.PI/3 / frames;

	final private float one_x = step_length - 0.9f * 
								(1 - (float)Math.cos(zero_other_angle));
	final private float one_y = 0.9f * (float)Math.sin(zero_other_angle);

	final private float two_x = (one_x + step_length) / frames;
	final private float two_a = zero_a / 3.0f;

	private SFVec3f left_translation_changed;
	private SFVec3f right_translation_changed;
	private SFVec3f robot_translation_changed;
	private SFRotation robot_rotation_changed;

	boolean walk = false, done = true;
	int step_type = 1, leg = 0;

	int cur_frame;
	float curX = 0.0f, curZ = 0.0f;
	float curAngle = 0.0f;

	public void initialize(){
		left_translation_changed = 
			(SFVec3f)getEventOut("left_translation_changed");
		right_translation_changed = 
			(SFVec3f)getEventOut("right_translation_changed");
		robot_translation_changed = 
			(SFVec3f)getEventOut("robot_translation_changed");
		robot_rotation_changed = 
			(SFRotation)getEventOut("robot_translation_changed");
	}

	private void update_translation(int o, float x, float y, float z){
		switch (o){
		case 0:
			right_translation_changed.setValue(x, y, z);
			break;
		case 1:
			left_translation_changed.setValue(x, y, z);
			break;
		case 2:
			curX += x * (float)Math.sin(curAngle);
			curZ += x * (float)Math.cos(curAngle);
			robot_translation_changed.setValue(curX, 0.0f, curZ);
			break;
		default:
		}
	}

	private void step_zero(){
		float oa, lx;
		if (cur_frame <= frames - zero_leg_delay){
			lx = step_length * cur_frame / (frames - zero_leg_delay);
			update_translation(leg, lx - bx * cur_frame, 
				- 3.6f + zero_a * lx * (step_length - lx), 0.0f);
		} else
			update_translation(leg, step_length - bx * cur_frame,
			-3.6f, 0.0f);
		oa = cur_frame * zero_other_angle;
		update_translation((leg+1)%2, 
			0.9f * (1 - (float)Math.cos(oa)) - bx * cur_frame,
			-3.6f + (float)Math.sin(oa), 
			0.0f);
		update_translation(2, bx, 0.0f, 0.0f);
	}

	private void step_one(){
		float lx = - one_x + one_x * cur_frame / frames;
		update_translation(leg, lx,
			-3.6f + zero_a * lx * (-step_length - lx), 0.0f);
	}

	private void step_two(){
		float oa, lx = - one_x + two_x * cur_frame;

		oa = cur_frame * zero_other_angle;
		update_translation(leg, - bx * cur_frame + lx,
			-3.6f + two_a * (step_length - lx) * (step_length + lx), 0.0f);
		update_translation((leg+1)%2, 
			0.9f * (1 - (float)Math.cos(oa)) - bx * cur_frame,
			-3.6f + (float)Math.sin(oa), 
			0.0f);
		update_translation(2, bx, 0.0f, 0.0f);
	}

	private void init_step(int st){
		step_type = st;
		leg = (leg + 1) % 2;
		done = false;
	}

	private void make_step(){
		if (!done){
			cur_frame++;
			switch (step_type){
			case 0: 
				step_zero();
				break;
			case 1:
				step_one();
				break;
			case 2:
				step_two();
				break;
			default:
			}
			if (cur_frame == frames){
				done = true;
				cur_frame = 0;
			}
		} else 
			if (step_type % 2 == 0)
				if (walk) init_step(2);
				else init_step(1);
			else if (walk) init_step(0);
	}
			

	public void processEvent (Event e){
		String name = e.getName();
		float arr[] = new float[4];

		if (name.equals("set_step") && 
			((ConstSFBool)e.getValue()).getValue())	walk = !walk;

		if (name.equals("set_fraction")) make_step();

		if (name.equals("set_rotation")){
			((ConstSFRotation)e.getValue()).getValue(arr);
			curAngle = arr[3];
		}
	}
}