import vrml.*;
import vrml.node.*;
import vrml.field.*;
import java.lang.Math;
import java.util.*;

public class leadfish extends Script
{
    
    private double x, y, z;    // potition
    private double vx, vy, vz; // velocity
    private double ax, ay, az; // acceleration

    private int timecount;
    private double lasttime;
    
    private SFRotation rotation;
    private SFVec3f translation;
    private SFRotation bodyrot;
    private SFFloat myx;

    private Random rnd;

    public void initialize( )
    {
	vx = 1;
	vy = 0;
	vz = 0;
	ax = 0;
	ay = 0;
	az = 0;

	timecount = 0;
	lasttime = 0;

	rnd = new Random( );

	rotation = (SFRotation)getField( "rotation" );
	bodyrot = (SFRotation)getField( "bodyrot" );
	translation = (SFVec3f)getField( "translation" );
	
	SFFloat initrotation = (SFFloat)getField( "initrotation" );
	SFFloat initradius = (SFFloat)getField( "initradius" );
	SFFloat initheight = (SFFloat)getField( "initheight" );
	myx = (SFFloat)getEventOut( "myx" );
	y = initheight.getValue();	
	z = initradius.getValue();	
	x = initrotation.getValue( );
    }

    private double clamp( double val, double min, double max )
    {
	if( val < min )
	    return min;
	else if( val > max )
	    return max;
	else
	    return val;
    }

    public void timer( float frac )
    {
	// time elapsed before this frame
	if( frac < lasttime )
	    timecount ++;
	double t = (double)timecount + (double)frac - lasttime;
	lasttime = (double)timecount + (double)frac;

	// randomized acceleration
	double acoeff = 0.01;
	ax = ax + acoeff * rnd.nextGaussian( );
	ay = clamp( ay + acoeff * rnd.nextGaussian( ), -0.05, 0.05 );
	az = clamp( az + acoeff * rnd.nextGaussian( ), -0.05, 0.05 );

	x = x + vx*t + ax*t*t;
	y = clamp( y + vy*t + ay*t*t, -3.5, 3.5 );
	z = clamp( z + vz*t + az*t*t, 2, 7.5 );

	vx = 2 * ax * t;
	vy = 2 * ay * t;
	vz = 2 * az * t;

	if( vx < 0.5 )
	    ax += 0.05;
	else if( vx > 1 )
	    ax -= 0.05;

	if( y < -2.5 )
	    ay += 0.1;
	else if( y > 2.5 )
	    ay -= 0.1;

	if( z < 3 )
	    az += 0.1;
	else if( z > 6.5 )
	    az -= 0.1;

	// rotation around tank
	float rot[] = new float[4];
	rot[0] = 0;
	rot[1] = 1;
	rot[2] = 0;
	rot[3] = (float)( (x/50) * 6.28 ); // tank circumfrence =~50
	rotation.setValue( rot );
	myx.setValue( (float)x );

	// translation vertically and radially
	float tr[] = new float[3];
	tr[0] = 0;
	tr[1] = (float)y;
	tr[2] = (float)z;
	translation.setValue( tr );

	// fish body rotation is around cross product of straight (1,0,0)
	// and the rotation its travelling
	rot[0] = 0;
	rot[1] = (float)(- vz);
	rot[2] = (float)vy;

	// amount of fish body rotation is computed from dot product:
	// v1.v2=|v1|*|v2|*cos(angle)
	// v1 = 1,0,0, v2 = velocity vector
	double totalVelocity = Math.sqrt( vx*vx + vy*vy + vz*vz );
	rot[3] = (float)Math.acos(vx/totalVelocity);

	bodyrot.setValue( rot );
    }

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

	if( EventName.equals( "setfraction" ) )
	    timer( ((ConstSFFloat)e.getValue()).getValue() );
    }
}