import java.awt.*;
import java.lang.Math;
import java.util.Random;

public class week6 extends BufferedApplet {
	int wid_, hei_;
	long T0 = -1;
	double tlast_ = 0., max_t = 0;
	static Random rnd_ = new Random();
	Vector3D mouse_ = new Vector3D(),
		tempV_ = new Vector3D(),
		tempV2_ = new Vector3D();
	boolean pressing_ = false;
	Matrix3D view_ = new Matrix3D(),
		screen_ = new Matrix3D(),
		tempM_ = new Matrix3D(),
		tempM2_ = new Matrix3D();
	Color backg_ = Color.white;
	final double F = -10;
	Shape shapes_[] = new Shape[100];

	enum WhichGears {First,Second,Third}
	WhichGears currentGears_ = WhichGears.First;
	
	//Sphere sphere_ = new Sphere(12,12);
	Multispline anims_[] = new Multispline[100];
	Shape.Changer obs_[] = new Shape.Changer[100];

	public void init() {
		super.init();
		wid_ = getBounds().width;
		hei_ = getBounds().height;
		animating=true;
		int smdim = Math.min(hei_,wid_);
		screen_.identity();
		screen_.scale(smdim/2.,-smdim/2.,0);
		screen_.translate(wid_/2.,hei_/2.,0);
		
		tempM_.translation(0,0,-10);
		tempM2_.perspectivator(F);
		tempM_.multiply(tempM2_,view_);
		
		/*
		final int N = 80;
		splinetime_.vals = new double[N][1];
		splinetime_.derivs = new double[N][1];
		splinetime_.Ts = new double[N];
		
		double t = 0;
		for(int i = 1; i<N; ++i) {
			splinetime_.Ts[i] = t += Math.pow(1.5,(N/2-i)/8.);
			splinetime_.vals[i][0] = 0;
			splinetime_.derivs[i][0] = (2*(double)N/(i+1))*(i%2-.5)*2;
		}
		splinetime_.derivs[N-1][0] = 0; // stop
		splinetime_.precalc();
		*/
		
		//sphere_.setScale(3,3,3);
		final int NARMS = 50;
		
		for(int i = 0; i<NARMS; ++i) {
			Shape tube = shapes_[i] = new Tube(6);
			double desx = rnd_.nextGaussian()*4.,
				desy = rnd_.nextGaussian()*4.,
				r = 5. + rnd_.nextGaussian()*2.,
				a = rnd_.nextDouble()*Math.PI*2.,
				cx = desx + Math.cos(a)*r,
				cy = desy + Math.sin(a)*r,
				wid = rnd_.nextGaussian()/6.+.5;
			tube.setScale(wid,wid,r);
			tube.setTranslation(cx,cy,0);
			Multispline anim = anims_[i] = new Multispline();
			anim.vals = new double[4][4];
			anim.derivs = new double[4][4];
			anim.Ts = new double[4];
			obs_[i] = tube.new Rotator();
			double t0 = 10 + 3.*rnd_.nextDouble(),
				t1 = t0 + 5 + 2*rnd_.nextGaussian(),
				t2 = t1 + 5 + 2*rnd_.nextGaussian(),
				t3 = t2 + 5 + 2*rnd_.nextGaussian();
			anim.Ts[0] = t0;
			anim.Ts[1] = t1;
			anim.Ts[2] = t2;
			anim.Ts[3] = t3;
			double rot = rnd_.nextDouble();
			for(int j = 0; i<4; ++i) {
				anim.vals[j][0] = 0; // oops a;
				anim.vals[j][2] = 0.;
				anim.vals[j][3] = 1;
				for(int k = 0; k<4; ++k)
					anim.derivs[j][k] = 0.;
			}
			anim.vals[0][1] = anim.vals[3][1] = 0;
			anim.vals[1][1] = anim.vals[2][1] = Math.PI/2;
			anim.precalc();
			max_t = Math.max(max_t,t3);
		}			
			
		//shapes_[0] = sphere_;
		
		/*
		gear_.Smallify = 1.;
		gear_.build();*/
	}
	double p[] = new double[1];
	public void render(Graphics g) {
		long T = System.currentTimeMillis();
		if(T0<0) {
			T0 = T;
			return; // in case zero time is bad
		}
		double t = (T-T0) / 1000.,
			dt = t - tlast_;
		if(t>max_t) {
			T0 = T;
			return;
		}
		Graphics2D g2 = (Graphics2D)g;
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
	    g.setColor(backg_);
     	g.fillRect(0,0,wid_,hei_);
     	     	
     	int i=0;
     	for(Multispline anim : anims_) {
     		if(anim!=null) {
				anim.calc(t,tempV_.vector());
				obs_[i].change(tempV_);
			}
			++i; // hmmforeach
		}
     	
     	for(Shape sh : shapes_) 
     		if(sh!=null) {
     			sh.render(view_,screen_);
     			sh.draw(g);
			}
     	
		tlast_ = t;
	}
	public boolean mouseMove(Event e, int wx, int wy) {
		mouse_.set(0,wx);
		mouse_.set(1,wy);
		return true;
	}
	public boolean mouseDown(Event e, int wx, int wy) {
		pressing_ = true;
		return true;
	}
	public boolean mouseUp(Event e, int wx, int wy) {
		pressing_ = false;
		return true;
	}
	public boolean keyDown(Event e, int key) {
		switch(key) {
		case Event.UP:
			break;
		case Event.DOWN:
			break;
		case 'z':
			break;
		case Event.RIGHT:
			break;
		case Event.LEFT:
			break;
		}			
		return true;
	}	
}
