//
import java.awt.*;

public class AutoshutterApplet extends GenericApplet
{
   int inch = 20;      // scale an inch to be 20 applet pixels
   int width, height;
   int gapSize = 4 * inch;
   int screenWidth = 10 * inch;
   int shutterWidth = 27 * inch / 2;
   int phase = 0;
   int leftX, rightX, leftY, rightY;
   int headX, headY, noseX, noseY, leftEyeX, leftEyeY, rightEyeX, rightEyeY;
   int screenY, shutterY, screenLeft, screenRight, shutterLeft, shutterRight;
   double theta = 0;
   boolean isDamage = true, isPaused = true, isVisible = false;

   public void init() {
      super.init();
      width = bounds().width;
      height = bounds().height;

      screenLeft = width/2 - screenWidth/2;
      screenRight = width/2 + screenWidth/2;

      shutterLeft = width/2 - shutterWidth/2;
      shutterRight = width/2 + shutterWidth/2;

      screenY = 50;
      shutterY = screenY + gapSize;
      setPosition(width/2, 20 * inch, 0);
   }

   void setPosition(int x, int y, double angle) {
      double P = 0.75 * inch;
      double r = 1.25 * inch;
      double E = 2 * inch;
      double N = 2.75 * inch;
      double s = Math.sin(theta);
      double c = Math.cos(theta);

      y = (int)Math.max(y, shutterY+E+2*P+1);
      theta = angle;
      headX = x;
      headY = y;
      noseX = (int)(x + s * N);
      noseY = (int)(y - c * N);

      int eyeX = (int)(x + s * E);
      int eyeY = (int)(y - c * E);

      leftEyeX  = (int)(eyeX - c * r);
      rightEyeX = (int)(eyeX + c * r);
      leftEyeY  = (int)(eyeY - s * r);
      rightEyeY = (int)(eyeY + s * r);

      double phi = Math.atan((double)(noseX - width/2) / (noseY - screenY));
      c = Math.cos(phi/2);
      s = Math.sin(phi/2);
      leftX  = (int)(leftEyeX  - s * P);
      rightX = (int)(rightEyeX - s * P);
      leftY  = (int)(leftEyeY  - c * P);
      rightY = (int)(rightEyeY - c * P);

      isDamage = true;
   }

   public boolean mouseDrag(Event e, int x, int y) {
      if (y < shutterY)
         return true;
      setPosition(x, y, theta);
      return true;
   }

   public boolean mouseUp(Event e, int x, int y) {
      if (y < 20 && x < 50) {
         phase = (phase + 1) % 3;
         isDamage = true;
      }
      else if (y < 20 && x > width - 50) {
         isPaused = ! isPaused;
         isDamage = true;
      }
      else if (y < shutterY) {
         setPosition(headX, headY, theta + (x < width/2 ? -.1 : .1));
         isDamage = true;
      }
      return true;
   }

   int intercept(int ax, int ay, int bx, int by, int cy) {
      return ax + (bx - ax) * (cy - ay) / (by - ay);
   }

   public void render(Graphics g) {

      // determine which phase we're in now

      if (!isPaused) {
         isDamage = true;
         phase = (phase + 1) % 3;
      }

      if (! isDamage)
         return;
      isDamage = false;

      // draw distance ruling every inch

      g.setColor(Color.white);
      g.fillRect(0, 0, width, height);

      g.setColor(Color.black);

      for (int y = screenY ; y < height ; y += inch)
	 g.drawLine(0, y, width, y);

      // draw head and eyes

      g.setColor(Color.gray);

      g.fillOval(headX - 3*inch, headY - 3*inch, 6*inch, 6*inch);
      g.fillOval(noseX - inch*3/4, noseY - inch*3/4, inch*3/2, inch*3/2);

      g.setColor(Color.white);
      g.fillOval(leftEyeX  - inch*3/4, leftEyeY  - inch, inch*3/2, inch*3/2);
      g.fillOval(rightEyeX - inch*3/4, rightEyeY - inch, inch*3/2, inch*3/2);
      g.setColor(Color.black);
      g.drawOval(leftEyeX  - inch*3/4, leftEyeY  - inch, inch*3/2, inch*3/2);
      g.drawOval(rightEyeX - inch*3/4, rightEyeY - inch, inch*3/2, inch*3/2);

      int pupilSize = inch * 2 / 3;
      g.fillOval(leftX  - pupilSize/2, leftY  - pupilSize/2, pupilSize, pupilSize);
      g.fillOval(rightX - pupilSize/2, rightY - pupilSize/2, pupilSize, pupilSize);

      // print text labels

      g.setColor(Color.magenta.darker());
      g.drawString("Instructions: drag mouse to move head", width/2-105, 14);
      g.drawString(isPaused ? "STEP" : "", 2, 14);
      g.drawString(isPaused ? "CYCLE" : "PAUSE", width - 45, 14);
      int clickY = (screenY + shutterY) / 2 + 3;
      g.drawString("[Click here to turn left]",  width/12,  clickY);
      g.drawString("[Click here to turn right]", width*2/3, clickY);
      g.setColor(Color.yellow.darker().darker().darker());
      g.drawString(" (display screen)", screenRight, screenY + 3);
      g.setColor(Color.black);
      g.drawString(" (active shutter)", shutterRight, shutterY + 3);
      g.drawString("Viewer distance: " + (((leftY + rightY)/2 - screenY)/inch) + " inches",
         2, shutterY + 45);
      
      // display the interleaved screen and the autoshutter

      g.fillRect(shutterLeft, shutterY-1, shutterRight-shutterLeft, 2);

      int x, x1, x2;
      cx = screenRight;
      isVisible = true;
      for (ax = bx = screenLeft ; isVisible && cx > bx ; ax = cx) {

         computeIntercepts();
         if (ax == screenLeft && phase > 0) {
            ax += (phase - 3) * (cx - ax) / 3;
            computeIntercepts();
         }

         isVisible = false;

         g.setColor(Color.green);
         x1 = Math.max(screenLeft , ax);
         x2 = Math.min(screenRight, bx);
         g.fillRect(x1, screenY-2, x2-x1, 4);
         x = (ax + bx) / 2;
         if (x >= screenLeft && x < screenRight) {
            g.drawLine(x, screenY, leftX, leftY);
            isVisible = true;
            g.setColor(Color.yellow);
            g.fillRect(aX + (bX-aX)/6, shutterY-1, (bX-aX)*2/3, 2);
         }

         g.setColor(Color.red);
         x1 = Math.max(screenLeft , bx);
         x2 = Math.min(screenRight, cx);
         g.fillRect(x1, screenY-2, x2-x1, 4);
         x = (bx + cx) / 2;
         if (x >= screenLeft && x < screenRight) {
            g.drawLine(x, screenY, rightX, rightY);
            isVisible = true;
            g.setColor(Color.yellow);
            g.fillRect(cX + (dX-cX)/6, shutterY-1, (dX-cX)*2/3, 2);
         }
      }
   }

   int ax, bx, cx, aX, bX, cX, dX;

   void computeIntercepts() {
      aX = intercept(ax, screenY,  leftX,  leftY,  shutterY);
      bX = intercept(ax, screenY,  rightX, rightY, shutterY);
      bx = intercept(bX, shutterY, leftX,  leftY,  screenY);
      cX = intercept(bx, screenY,  rightX, rightY, shutterY);
      cx = intercept(cX, shutterY, leftX,  leftY,  screenY);
      dX = intercept(cx, screenY,  rightX, rightY, shutterY);
   }
}