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

class Flap extends Script {

	private ConstSFFloat set_fraction;
	private ConstSFVec3f set_magnitude;
	private SFRotation set_right_wing;
	private SFRotation set_left_wing;
	private SFVec3f set_chain;
	private SFFloat magnitude;
	private SFFloat drag;
	private SFFloat maxFlap;
	private SFFloat scaleMagnitude;
        private SFFloat expansion_in;
	private SFVec3f magnitude_mask;
        private float expand;
	private float curMagnitude;
	private float offset = 0.0f;
	private float totalTime = 0.0f;
	private float curTime;
	private float lastTime = 0.0f;

	public void initialize() {
		magnitude = (SFFloat) getField("magnitude");
		drag = (SFFloat) getField("drag");
		maxFlap = (SFFloat) getField("maxFlap");
		scaleMagnitude = (SFFloat) getField("scaleMagnitude");
		expansion_in = (SFFloat) getField("expansion_in");
		expand = (float) expansion_in.getValue();
		magnitude_mask = (SFVec3f) getField("magnitude_mask");
		set_right_wing = (SFRotation) getEventOut("set_right_wing");
		set_left_wing = (SFRotation) getEventOut("set_left_wing");
		set_chain = (SFVec3f) getEventOut("set_chain");
		curMagnitude = (float) magnitude.getValue();
	}

	public void processEvent(Event e) {
		String name = e.getName();
		if (name.equals("set_fraction")) {
			Interpolate(e);
		}
		if (name.equals("set_magnitude")) {
			setMagnitude(e);
		}
	}

	public void Interpolate(Event e) {
		curTime = (float) ((ConstSFFloat) e.getValue()).getValue();
		float dTime;
		if (curTime < lastTime) {
			dTime = (1.0f - lastTime) + curTime;
			totalTime += dTime;
		} else {
			dTime = curTime - lastTime;
			totalTime += dTime;
		}
		lastTime = curTime;		
		
		if (curMagnitude > 0) {
			curMagnitude -= dTime * (float)drag.getValue();
			set_right_wing.setValue((float) magnitude_mask.getX(),
						(float) magnitude_mask.getY(),
						(float) magnitude_mask.getZ(),
				(float)maxFlap.getValue()*curMagnitude*
					(float)-Math.cos((double)expand*((double)2.0f*(float)Math.PI*(totalTime-offset))));
			set_left_wing.setValue((float) magnitude_mask.getX(),
						(float) magnitude_mask.getY(),
						(float) magnitude_mask.getZ(),
				(float)maxFlap.getValue()*curMagnitude*
					(float)Math.cos((double)expand*((double)2.0f*(float)Math.PI*(totalTime-offset))));
		} else {
			set_right_wing.setValue((float) magnitude_mask.getX(),
						(float) magnitude_mask.getY(),
						(float) magnitude_mask.getZ(),
						0);
			set_left_wing.setValue((float) magnitude_mask.getX(),
						(float) magnitude_mask.getY(),
						(float) magnitude_mask.getZ(),
						0);
		}

		if ((totalTime - offset) > 0.5) {
			set_chain.setValue(0,0,0);
		}			
	}

	public void setMagnitude(Event e) {
		offset = totalTime;
		set_magnitude = (ConstSFVec3f) e.getValue();
		curMagnitude = Math.abs(((float) set_magnitude.getY()))
		  / (float) scaleMagnitude.getValue();	
	}
}