// -----------------------------------------------------------------
// An example of using threads for dynamic graphics.  In this case, we
// want an analog clock face with hour, minute and second hands.
//
// Paul McNamee 3/99
// -----------------------------------------------------------------

import java.applet.Applet;
import java.awt.*;
import java.util.*;

public class Clock extends Applet implements Runnable {
  private Date date;
  private Date lastDate;
  private Thread timeThread;
  private volatile boolean running = false;

  public void start () {
    running = true;
  }

  public void stop () {
    running = false;
  }

  public void init () {
    date = new Date();
    lastDate = date;
    ThreadGroup appletGroup = Thread.currentThread().getThreadGroup();
    timeThread = new Thread(appletGroup, this);
    timeThread.start();
    setBackground(Color.white);
  }

  public void update (Graphics g) {
    // Don't clear!
    paint(g);
  }

  public void run () {
    while (true) {
      pause(0.05);  // check new date every 20th of a second
      if (running) {
        date = new Date();
        repaint();
      }
    }
  }

  public void pause (double seconds) {
    try {
      Thread.sleep((long) (seconds * 1000));
    }
    catch (InterruptedException ie) {}
  }


  // -----------------------------------------------------------------
  public void paint (Graphics g) {
    if ((date.getTime() - lastDate.getTime()) > 1000) {
      // More than 1000 milliseconds have passed
      g.clearRect(0,0,getSize().width,getSize().height);

      int hour = (date.getHours() % 12);
      int minute = date.getMinutes();
      int seconds = date.getSeconds();

      int x = (getSize().width-1) / 2;
      int y = (getSize().height-1) / 2;
      double radius = x;  // works

      // Primative appointment alarm!
      if ((hour == 5) && (minute == 0)) {
        showStatus("Time to go home");
      } else {
        showStatus("");
      }

      // Draw background (circle and minute/5-minute tick marks)
      g.setColor(Color.black);
      g.drawArc(0,0,getSize().width-1,getSize().height-1,0,360);
      for (int i=0; i<60; i++) {
        if ((i % 5)==0)
          drawTic(g, x, y, radius, i / 60.0, 0.10);
        else
          drawTic(g, x, y, radius, i / 60.0, 0.05);
      }

      // Draw hands
      double hourRatio = (double) hour / (double) 12;
      double minuteRatio = (double) minute / (double) 60;
      double secondsRatio = (double) seconds / (double) 60;
      g.setColor(Color.blue);
      drawLine(g, x, y, radius * 0.7, hourRatio + (minuteRatio / 12.0));
      drawLine(g, x, y, radius * 0.95, minuteRatio + (secondsRatio / 60.0));
      g.setColor(Color.red);
      drawLine(g, x, y, radius * 0.95, secondsRatio);

      // lastDate drawn
      lastDate = date;
    }
  }

  // Helper function to draw lines starting from clock center (ie, hands)
  public void drawLine(Graphics g, int x, int y, double radius, double fraction) {
    int xOnRim = x + (int) (Math.sin(fraction * 2.0 * Math.PI) * radius);
    int yOnRim = y - (int) (Math.cos(fraction * 2.0 * Math.PI) * radius);
    g.drawLine(x, y, xOnRim, yOnRim);
  }

  // Helper function for line segments abutting clock circle
  public void drawTic(Graphics g, int x, int y, double radius, double fraction, double length) {
    int xOnRim = x + (int) (Math.sin(fraction * 2.0 * Math.PI) * radius);
    int yOnRim = y - (int) (Math.cos(fraction * 2.0 * Math.PI) * radius);
    int xInside = x + (int) (Math.sin(fraction * 2.0 * Math.PI) * radius * (1.0 - length));
    int yInside = y - (int) (Math.cos(fraction * 2.0 * Math.PI) * radius * (1.0 - length));
    g.drawLine(xInside, yInside, xOnRim, yOnRim);
  }
}

