import java.applet.*;
import java.awt.*;
import java.lang.Math;

public class Clicker extends Applet implements Runnable {

   String copyright="Copyright (C) 2002 Anders Johnson";
   Thread animation;
   boolean running;
   int width, height;
   int state;
   double x, y, d;
   double theta, pi4;
   double A, B, C;
   Image offscreen;
   Graphics b;
   AudioClip click1, click2;

   public void init() {
	// Some (maybe all) Macintoshes don't support getSize(), which is
	// a shame because it means that the applet won't scale on any
	// platform now. (Insert favorite "run anywhere" joke here.)
	//width = getSize().width;
	//height = getSize().height;
   	width=321;
   	height=301;

	setBackground( Color.gray );
	state=0;
	x=4.0;
	y=8.0;
	d=9.0;
	theta=0.0;
	pi4=16.0*Math.atan(1);
	double m=-1; // minimum d
	double M1=9; // maximum d
	double M2=5; // maximum "shallow" d
	A=(M1+M2+2*m)/4.0;
	B=(M1+M2-2*m)/4.0;
	C=(M1-M2)/2.0;
	click1=getAudioClip(getDocumentBase(), "click1.au");
	click2=getAudioClip(getDocumentBase(), "click2.au");
	offscreen=createImage(width, height);
	b=offscreen.getGraphics();
	animation=new Thread(this);
	running=true;
	animation.start();
   }

   public void move(double din) {
	d=din;
	if((state==0 || state==2) && d<=0.0) {
		click1.play();
		state=(state+1)%4;
	}
	if((state==1 || state==3) && d>=4.0) {
		click2.play();
		state=(state+1)%4;
	}
	if(state==0) {
		x=4.0;
		y=d;
		if(y>8) { y=8; }
	}
	if(state==1) {
		double d1=0.0;
		if(d>0.0) { d1=d; }
		x=5.0+d1/2.0;
		y=1+d-d1/2.0;
	}
	if(state==2) {
		double d1=4.0;
		if(d<d1) { d1=d; }
		x=8.0;
		y=d1;
	}
	if(state==3) {
		double d1=0;
		if(d>0.0) { d1=d; }
		x=1.0+d1/2.0;
		y=1+d-d1/2.0;
	}
   }

   int xc(double xin) {
	return (int) Math.rint((width-1) * xin/16.0);
   }

   int yc(double yin) {
	return (int) Math.rint((height-1)*(10.0-yin)/15.0);
   }

   void xfill(int targ[], double in[], double delta, int ofs) {
   	for(int i=0; i<in.length; i++) {
		targ[i+ofs]=xc(in[i]+delta);
	}
   }

   void yfill(int targ[], double in[], double delta, int ofs) {
   	for(int i=0; i<in.length; i++) {
		targ[i+ofs]=yc(in[i]+delta);
	}
   }

   public void paint( Graphics g ) {
	b.clearRect(0, 0, width, height);
	
	// Stationary cam
	int x1[]=new int[14];
	int y1[]=new int[14];
	x1[0]=xc(0); y1[0]=yc(10);
	{
		double x1i[]={0, 2, 2, 4, 4, 8};
		double y1i[]={0, 2, 8, 8, 0, 4};
		xfill(x1, x1i, 0, 1);
		xfill(x1, x1i, 8, 7);
		yfill(y1, y1i, 0, 1);
		yfill(y1, y1i, 0, 7);
	}
	x1[13]=xc(16); y1[13]=yc(10);
	b.setColor( Color.cyan );
	b.fillPolygon(x1, y1, 14);
	
	// Drive cam
	int x2[]=new int[12];
	int y2[]=new int[12];
	x2[0]=xc(0); y2[0]=yc(10);
	x2[1]=xc(0); y2[1]=yc(d);
	for(int i=1; i<5; i++) {
		x2[2*i]=xc(4*i-3); y2[2*i]=yc(d+1);
		x2[2*i+1]=xc(4*i-1); y2[2*i+1]=yc(d-1);
	}
	x2[10]=xc(16); y2[10]=yc(d);
	x2[11]=xc(16); y2[11]=yc(10);
	b.setColor( Color.green );
	b.fillPolygon(x2, y2, 12);
	
	// Drive cam & ! Stationary cam
	b.setColor( Color.yellow );
	for(int i=0; i<2; i++) {
		double w=8.0*i;
		if(d<8) {
			int x3[]={xc(2+w), xc(2+w), xc(3+w), xc(4+w), xc(4+w)};
			int y3[]={yc(8), yc(d),yc(d-1),yc(d), yc(8)};
			b.fillPolygon(x3, y3, 5);
		}
		else if(d<9) {
			int x3[]={xc(d-6+w),xc(3+w),  xc(12-d+w)};
			int y3[]={yc(8),  yc(d-1),yc(8)};
			b.fillPolygon(x3, y3, 3);
		}
		if(d<0) {
			int x3[]={xc(0+w), xc(0+w), xc(1+w), xc(2+w), xc(2+w)};
			int y3[]={yc(0), yc(d),yc(d+1),yc(d), yc(2)};
			b.fillPolygon(x3, y3, 5);
			int x9[]={xc(4+w), xc(4+w), xc(5+w), xc(5+d/2.0+w)};
			int y9[]={yc(0), yc(d), yc(d+1), yc(d/2.0+1)};
			b.fillPolygon(x9, y9, 4);
		}
		else if(d<2) {
			int x3[]={xc(2+w), xc(2+w), xc(1+d/2.0+w)};
			int y3[]={yc(2), yc(d), yc(1+d/2.0)};
			b.fillPolygon(x3, y3, 3);
		}
		if(d<4) {
			int x3[]={xc(5+d/2.0+w), xc(7+w), xc(8+w), xc(8+w)};
			int y3[]={yc(1+d/2.0),yc(d-1),yc(d), yc(4)};
			b.fillPolygon(x3, y3, 4);
		}
	}
	
	// Lifter
	for(int i=0; i<(x<2 ? 3 : 2); i++) {
		double w=8.0*i;
		b.setColor( Color.red );
		int x4[]={xc(x-2+w), xc(x-2+w), xc(x+w), xc(x+w)};
		int y4[]={yc(-5),  yc(y-2), yc(y), yc(-5)};
		b.fillPolygon(x4, y4, 4);
		b.setColor( Color.black );
		b.fillOval(xc(x-1+w)-5, yc(y-3)-5, 10, 10);
		b.drawPolygon(x4, y4, 4);
	}
	
	// Draw outlines
	b.setColor( Color.black );
	b.drawPolygon(x1, y1, 14);
	b.drawPolygon(x2, y2, 12);

	// Border
	b.drawRect(0, 0, width-1, height-1);
	
	// Copy to screen
	g.drawImage(offscreen, 0, 0, this);
   }

   // Override update() to avoid flickering
   public void update(Graphics g) {
	paint(g);
   }
   
   public void run() {
	while(running) {
		if(isActive()) {
			move(A + B*Math.cos(theta) + C*Math.cos(theta/2.0));
			repaint();
			theta+=0.05;
			// Keep theta manageably small
			if(theta > pi4) { theta-=pi4; }
		}
		try {
			// Wait 100ms (10Hz)
			animation.sleep(100);
		}
		catch(InterruptedException e) {
			System.out.println(e);
		}
	}
   }

   public void destroy() {
        	running=false;
        	animation=null;
   }
}

