//
import java.awt.*;

public class sideView extends BufferedApplet
{
   double time0;
   Graphics g;
   Color diskColor[] = new Color[256];

   // INITIALIZE EVERYTHING

   public void init() {
      super.init();
      time0 = System.currentTimeMillis() / 1000.;
      for (int i = 0 ; i < 256 ; i++)
         diskColor[i] = new Color(0,0,(int)(165+90*Math.cos(.032*i)));
   }

   double X = 0, TX = -1, TY = 0, C0 = -10, rate = 1;
   Color bgColor = new Color(160,160,255);
   Color feltColor = new Color(0,150,0);
   Color metalColor = new Color(220,220,220);
   boolean grabbed = false;

   // RENDER EVERYTHING

   public void render(Graphics g) {
      this.g = g;

      // COMPUTE STIRRING MOVEMENT

      double theta = rate*Math.PI * (System.currentTimeMillis()/1000. - time0);
      double C = .19 * Math.cos(theta);
      if (C0 == -10)
         C0 = C;

      // CLEAR THE BACKGROUND

      g.setColor(bgColor);
      g.fillRect(0, 0, width(), height());

      // DRAW THE MOVING GRATE

      g.setColor(Color.black);
      fillRect(-1.5, -.08, 3,.09);
      g.setColor(metalColor);
      for (int i = 0 ; i < 20 ; i++)
         fillRect(-1.5+C+.15*i, .2, .075,.04);

      // WHEN MAGNET REACHES DISK, TELL IT TO GRAB THE DISK

      if (! mouseIsDown && ! grabbed && Math.abs(TX-X) <= .02) {
         grabbed = true;
	 TX = 0;
      }

      // SHOULD MAGNET MOVE WITH THE GRATE?

      boolean move = C < C0 == TX < X && Math.abs(TX-X) > .02;

      // IF SO, THEN IT LIFTS UP TO CONTACT THE GRATE

      double Y = move ? .02 : 0;

      // DRAW THE ELECTROMAGNET

      g.setColor(Color.red);
      fillRect(-.4+X,Y+.01, .8,.16);
      g.setColor(Color.black);
      for (double t = .01 ; t <= .17 ; t += .032)
         fillRect(-.4+X,Y+t, .8,.01);
      g.setColor(metalColor);
      fillRect(-.2+X,Y+.015, .4,.155);

      // DRAW THE TABLE TOP

      g.setColor(feltColor);
      fillRect(-1.5,.24,3,.04);

      // DRAW THE DISK ATOP THE TABLE...

      double GX = grabbed ? X : TX;
      for (int i = 0 ; i <= 18 ; i++) {
	 g.setColor(diskColor[i * 255 / 18]);
         fillRect(-.35 + .035 * i + GX, .28+TY, .071, .4);
      }

      // ...AND ITS METAL BASE

      g.setColor(metalColor);
      fillRect(-.35+GX,.27+TY, .7,.06);

      // DRAW THE DIRECTIONAL ARROWS INSIDE THE DISK

      if (mouseIsDown || Math.abs(TX-X) <= .02) {
         g.setColor(Color.white);
         int x = X2x(GX), y = Y2y(.5+TY), s = R2r(.23);
	 for (int t = -s ; t <= s ; t += 2*s) {
            g.drawLine(x-t,y, x-2*t/5,y);
            g.drawLine(x-t,y, x-4*t/5,y-t/5);
            g.drawLine(x-t,y, x-4*t/5,y+t/5);
         }
      }

      X += move ? C - C0 : 0;

      C0 = C;
      animating = true;
   }

   // RECTANGLE FILL CALLED IN CONTINUOUS WORLD COORDS

   void fillRect(double x, double y, double w, double h) {
      g.fillRect(X2x(x),Y2y(y+h),R2r(w),R2r(h));
   }

   // CONVERT BETWEEN CONTINUOUS WORLD COORDS AND PIXEL COORDS

   int X2x(double X) { return (int)(  width ()/2 + width()/4 * X); }
   int Y2y(double Y) { return (int)(2*height()/3 - width()/4 * Y); }
   int R2r(double R) { return (int)(               width()/4 * R); }

   double x2X(int x) { return (double)(x -   width ()/2) / ( width()/4); }
   double y2Y(int y) { return (double)(y - 2*height()/3) / (-width()/4); }
   double r2R(int r) { return (double) r                 / ( width()/4); }

   // ALLOW USER TO GRAB AND MOVE THE DISK

   boolean mouseIsDown = false;
   int mx, my;

   public boolean mouseDown(Event e, int x, int y) {
      mouseIsDown = true;
      if (x >= X2x(X-.2) && x <= X2x(X+.2)) {
         TX = X;
         TY = 0;
         grabbed = false;
      }
      mx = x;
      return true;
   }
   public boolean mouseDrag(Event e, int x, int y) {
      if (! grabbed) {
         TX += r2R(x - mx);
         TY = Math.max(0, TY - r2R(y - my));
         mx = x;
         my = y;
      }
      return true;
   }
   public boolean mouseUp(Event e, int x, int y) {
      mouseIsDown = false;
      TY = 0;
      return true;
   }

   // ALLOW USER TO CONTROL THINGS WITH THE KEYBOARD

   public boolean keyUp(Event e, int key) {
      switch (key) {
      case ' ':
         rate = rate == 1 ? 6 : 1;  // SPACE KEY TOGGLES STIRRING RATE
	 break;
      case 1006:
         TX = -1;                   // LEFT ARROW PUTS DISK ON THE LEFT
	 grabbed = false;
	 break;
      case 1007:
         TX = 1;                    // RIGHT ARROW PUTS DISK ON THE RIGHT
	 grabbed = false;
	 break;
      }
      return true;
   }
}