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

public class fish extends Script {
  // eventIn
  private SFRotation leaders_rotation;
  private SFVec3f leaders_translation;
  
  // eventOut
  private SFRotation rotation_changed;
  private SFVec3f translation_changed;

  // fields
  private SFRotation current_rotation;
  private SFVec3f current_translation;

  // variables
  private float max_ang_deviation;
  private float max_ang_velocity;
  private float min_ang_velocity;

  private float max_radius_deviation;
  private float max_radius_velocity;
  private float min_radius_velocity;

  private float max_height_deviation;
  private float max_height_velocity;
  private float min_height_velocity;

  private float time_slice;
  private float dampening;
  
  private float angular_difference;
  private boolean angular_difference_sampled;
  private float[] trans_difference;
  private boolean trans_difference_sampled;
  
  private float ang_acceleration;
  private float ang_velocity;

  private float radius_acceleration;
  private float radius_velocity;

  private float height_acceleration;
  private float height_velocity;

  public void initialize() {
    try {
      current_rotation = (SFRotation)getField("current_rotation");
      current_translation = (SFVec3f)getField("current_translation");
      leaders_rotation = (SFRotation)getField("leaders_rotation");
      leaders_translation = (SFVec3f)getField("leaders_translation");
      rotation_changed = (SFRotation)(getEventOut("rotation_changed"));
      translation_changed = (SFVec3f)(getEventOut("translation_changed"));

      max_ang_deviation = (float).2;
      max_ang_velocity = (float).9;
      min_ang_velocity = (float)0;

      max_radius_deviation = (float).9;
      max_radius_velocity = (float).9;
      min_radius_velocity = (float)-.9;

      max_height_deviation = (float).9;
      max_height_velocity = (float).9;
      min_height_velocity = (float)-.9;

      time_slice = (float).2;
      dampening = (float).985;
      
      angular_difference_sampled = false;
      trans_difference_sampled = false;
      
      ang_acceleration = 0;
      ang_velocity = 0;
      
      radius_acceleration = 0;
      radius_velocity = 0;

      height_acceleration = 0;
      height_velocity = 0;
    }
    catch (InvalidFieldException e) {
      System.exit(1);
    }
  }

  public void rotation_signal() {
    // to get the new rotation;
    if (!angular_difference_sampled) {
      float temp[] = new float[4];
      leaders_rotation.getValue(temp);
      float temp2[] = new float[4];
      current_rotation.getValue(temp2);
      angular_difference = temp[3]-temp2[3];
      angular_difference_sampled = true;
    }

    float my_rot[] = new float[4];
    float lead_rot[] = new float[4];
    current_rotation.getValue(my_rot);
    leaders_rotation.getValue(lead_rot);
    ang_acceleration = (float) (((Math.random())*2)-1);

    if (((my_rot[3]+max_ang_deviation+angular_difference) < lead_rot[3]) &&
	(ang_acceleration < 0))
      ang_acceleration = 1;
    if (((my_rot[3]+angular_difference) > lead_rot[3]) &&
	(ang_acceleration > 0))
      ang_acceleration = -1;
    
    ang_velocity = ang_velocity+(ang_acceleration*time_slice);

    if (ang_velocity < min_ang_velocity)
      ang_velocity = min_ang_velocity;
    if (ang_velocity > max_ang_velocity)
      ang_velocity = max_ang_velocity;

    my_rot[3] = (float)(my_rot[3]+(ang_velocity*time_slice));
    current_rotation.setValue(my_rot);
    rotation_changed.setValue(my_rot);
  }

  public void translation_signal() {
    // get the location
    if (!trans_difference_sampled) {
      float temp3[] = new float[3];
      leaders_translation.getValue(temp3);
      float temp4[] = new float[3];
      current_translation.getValue(temp4);
      trans_difference = new float[3];
      for (int i=0; i<3;i++)
	trans_difference[i] = temp3[i]-temp4[i];
      trans_difference_sampled = true;
    }

    float my_trans[] = new float[3];
    float lead_trans[] = new float[3];
    current_translation.getValue(my_trans);
    leaders_translation.getValue(lead_trans);

    // to get the new radius
    radius_acceleration = (float) (((Math.random())*2)-1);

    if (((my_trans[0]+trans_difference[0]+max_radius_deviation) < lead_trans[0]) &&
    	(radius_acceleration < 0))
      radius_acceleration = 1;
    if (((my_trans[0]+trans_difference[0]) > (lead_trans[0]+max_radius_deviation)) &&
	(radius_acceleration > 0))
      radius_acceleration = -1;

    radius_velocity = (float)(radius_velocity*dampening)+(radius_acceleration*time_slice);

    if (radius_velocity < min_radius_velocity)
      radius_velocity = min_radius_velocity;
    if (radius_velocity > max_radius_velocity)
      radius_velocity = max_radius_velocity;

    my_trans[0] = (float)(my_trans[0]+(radius_velocity*time_slice));
    
    // get the new height.
    height_acceleration = (float) (((Math.random())*2)-1);

    if (((my_trans[1]+trans_difference[1]+max_height_deviation) < lead_trans[1]) &&
	(height_acceleration < 0))
      height_acceleration = 1;
    if (((my_trans[1]+trans_difference[1]) > (lead_trans[1]+max_height_deviation)) &&
	(height_acceleration > 0))
      height_acceleration = -1;

    height_velocity = (float)(height_velocity*dampening)+(height_acceleration*time_slice);

    if (height_velocity < min_height_velocity)
      height_velocity = min_height_velocity;
    if (height_velocity > max_height_velocity)
      height_velocity = max_height_velocity;

    my_trans[1] = (float)(my_trans[1]+(height_velocity*time_slice));

    // send the results
    current_translation.setValue(my_trans);
    translation_changed.setValue(my_trans);
    }
  
  public void processEvent(Event e) {
    String event_name = e.getName();
 
    if (event_name.equals("leaders_rotation")) {
      rotation_signal();
    } else if (event_name.equals("leaders_translation")) {
      translation_signal();
    } else {
      System.out.println("Were jacked!");
    }
  }
}