import java.applet.*; 
import java.awt.*; 
import java.awt.image.*; 
import java.awt.event.*; 
import java.io.*; 
import java.net.*; 
import java.text.*; 
import java.util.*; 
import java.util.zip.*; 

public class abstract_clock extends BApplet {
// ABSTRACT CLOCK
// by Paul Cage
// on 09 Mar 2003

// ==============================================
// VARIABLE DECLARATIONS HERE
// ==============================================
int margin;
int hours_w;
int hours_startx;
int hours_starty;
int hours_endx;
Ball sec, asec, asec2, hm;
Ball[] h;
int numSecs;
int numMins;
int numHours;

// ==============================================
// SETUP
// ==============================================
void setup() {
  size(820, 220);
  background(0xffffffff);
  for (int i = 0; i < 10; i++) {
    println();
  }
  h = new Ball[12];
  for (int i = 0; i < 12; i++) {
    h[i] = new Ball();
    h[i].y = 0;
    h[i].ty = 0;
    h[i].active = true;
    h[i].stepme = 8;
  }
  margin = 10;
  hours_startx = width*5/8;
  hours_starty = margin*2;
  hours_endx = width - margin*2;
  hours_w = (width - margin*2 - width*5/8)/12;
  sec = new Ball();
  sec.stepme = 12;
  sec.x = -5;
  sec.y = height/2;
  sec.tx = width*2/8;
  sec.active = true;

  /////////////////////////////////// set start time here
  numSecs = second();
  numMins = minute();
  numHours = hour();
  if (numHours > 11) numHours -= 12;
  h[numHours].ty = margin;
  h[numHours].active = true;
  asec = new Ball();
  asec.stepme = 48;
  asec.x = 0;
  asec.tx = asec.x;
  asec.active = true;
  asec2 = new Ball();
  asec2.stepme = 12;
  asec2.x = 0;
  asec2.tx = asec.x;
  asec2.active = true;

  hm = new Ball();
  hm.stepme = 12;
  hm.x = hours_startx - 1 - hours_w * numHours * 1.5f;
  hm.tx = hm.x;
  hm.active = true;
}

// ==============================================
// LOOP
// ==============================================
void loop() {
  noStroke();

  // draw interior color
  fill(0xffD0E6C8);
  rect(0 + margin, 0 + margin, width-margin*2, height-margin*2);

  // draw hours
  stroke(0xffFFA37F);
  line(hours_startx, hours_starty, hours_endx, hours_starty);
  noStroke();
  fill(0xffFFA37F);

  for (int i = 0; i < 12; i++) {
    h[i].move();
    rect(hours_startx + i*hours_w, hours_starty + 2 + h[i].y, hours_w, 3);
  }

  // draw mirrored hour markers
  stroke(0);
  line(hours_startx - 1, height - margin - 7, hours_startx - 1, height - margin - 1);
  line(hours_startx - 1 - hours_w*12*1.5f, height - margin - 7, hours_startx - 1 - hours_w*12*1.5f, height - margin - 1);
  hm.move();
  line(hm.x, height - margin - 7, hm.x, height - margin - 1);

  // draw minutes
  int minutes_startx = hours_startx - (40*(5) + 3*12);
  int drawx = minutes_startx;
  fill(0xffFFBA7F);
  noStroke();
  if (numMins > 59) {
    numMins = 0;
    h[numHours].ty = 0;
    h[numHours].active = true;

    numHours++;
    if (numHours > 11) {
      numHours = 0;
    }
    h[numHours].ty = margin;
    h[numHours].active = true;
    hm.tx = hours_startx - 1 - hours_w*numHours*1.5f;
    hm.active = true;

  }
  for (int i = 1; i <= numMins; i++) {
    rect(drawx, height/2 - 6, 4, 10);
    if (i%10 == 0) {
      drawx += 12;
    } else {
      drawx += 5;
    }
  }

  // draw second hand
  noStroke();
  fill(0xffF8E8B9);
  rect(sec.x, height/2 - 15, 2, 25);
  stroke(0xffF8E8B9);
  line(sec.x - 2, height/2 - 15, sec.x - 2, height/2 - 1);
  sec.move();
  if (sec.x == sec.tx || second() > numSecs) {
    sec.x = margin;
    sec.active = true;
    numSecs++;
  }
//println("second(): " + second() + ", numSecs: " + numSecs);
  // draw accumulated seconds
  noStroke();
  if (numSecs > 59) {
    numSecs = 0;
    numMins++;
    asec.x = asec.tx = 0;
    asec2.x = asec2.tx = 0;

  }
  if (numSecs%12 == 0) {
    asec.tx = (numSecs*(5) + 3*12);
    asec.active = true;
  }
  asec2.tx = (numSecs*(5) + 3*12);
//  if (asec.tx != asec.x) {
//    asec.a>ctive = true;
//  }
  if (asec2.tx != asec2.x) {
    asec2.active = true;
  }
  asec.move();
  asec2.move();
//  rect(minutes_startx, height/2 + 5,  asec2.x, 2);
rect(minutes_startx, height/2 + 5,  (numSecs*(5) + 3*12), 2);
  stroke(0xffF8E8B9);
  line(minutes_startx, height/2 + 8,   minutes_startx + asec.x, height/2 + 8);

  // draw horizontal "time" line
  stroke(0xffffffff);
  line(0, height/2, width, height/2);

  // draw vertical partition
  stroke(0xffFFA37F);
  line(width*2/8, margin*5, width*2/8, height-margin*5);

}
// A ball is a container for a set of coordinates x and y, and target coordinates
// that the ball can be told to approach. This is a common data structure used in
// the trendy flash experiments these days.

class Ball
{
  float x, y, tx, ty;  // Coords and target coords.
  boolean active;      // Is this ball active? if so, then animate.
  int stepme;
  Ball() {
    // When a new ball is constructed, give it random coords and targets.
    x = random(width);
    y = random(height);
    tx = random(width);
    ty = random(height);
    // Animate this ball.
    active = true;
    stepme = 32;
  }

  // Tell the ball to approach a new set of coords.
  void setTarget(float xin, float yin) {
    tx = xin;
    ty = yin;
    active = true;
  }

  // Move the ball if it is active.
  void move() {
    if (this.active) {
      // Calculate the horizontal and vertical distance from target.
      float xdif, ydif;
      xdif = tx - x;
      ydif = ty - y;
      // Update the coordinates incrementally. as the ball gets closer
      // to its target, the values xdif/16 and ydif/16 become smaller,
      // causing it to slow down.
      // (The value '16' is completely arbitrary. Play with different
      // numbers and see what happens.)
      x += xdif/stepme;
      y += ydif/stepme;
      // When the ball has reached a reasonably close proximity of its
      // target, tell it to snap into position and stop.
      if (abs(xdif)<0.5 && abs(ydif)<0.5) {
        x = this.tx;
        y = this.ty;
        active = false;
      }
    }// End if active
  } // End move method
} // End class

}