import java.applet.*;
import java.awt.*;

// run this applet with width=300 height=300
public class Woogie extends Applet implements Runnable {

  Thread animation;

  Graphics offscreen;
  Image image;

  static final int NUM_RECTS = 9;	// in ms
  static final int REFRESH_RATE = 100;	// in ms

  Rectangle ab;
  DancingRect r[];

  public void init() {
    System.out.println(">> init <<");
    setBackground(Color.black);
    ab = bounds();
    System.out.println("("+ab.x+","+ab.y+","+ab.width+","+ab.height+")");
    initRectangles();
    image = createImage(ab.width,ab.height);
    offscreen = image.getGraphics();
  }

  public int abx(int x) {
    return x*ab.width/300+ab.x;
  }

  public int aby(int y) {
    return y*ab.height/300+ab.y;
  }

  public int abw(int w) {
    return w*ab.width/300;
  }

  public int abh(int h) {
    return h*ab.height/300;
  }

  public void initRectangles() {
    // allocate dancing rectangles
    r = new DancingRect[NUM_RECTS];
    r[0] = new DancingRect(abx(0),aby(0),abw(90),abh(90),Color.yellow);
    r[1] = new BoogieRect(abx(250),aby(0),abw(40),abh(190),Color.yellow);
    r[2] = new WaltzRect(abx(200),aby(55),abw(60),abh(135),Color.yellow);
    r[3] = new BoogieRect(abx(80),aby(200),abw(220),abh(90),Color.blue);
    r[4] = new ChaChaChaRect(abx(100),aby(10),abw(90),abh(80),Color.blue);
    r[5] = new WaltzRect2(abx(80),aby(100),abw(110),abh(90),Color.lightGray);
    r[6] = new OvalRect(abx(200),aby(0),abw(45),abh(45),Color.red);
    r[7] = new WaltzRect(abx(0),aby(100),abw(70),abh(200),Color.red);
    r[8] = new BoogieRect(abx(200),aby(55),abw(60),abh(135),Color.magenta);
  }

  public void start() {

    System.out.println(">> start <<");
    animation = new Thread(this);
    if (animation != null) {
      animation.start();
    }
  }

  // update each rectangle's position
  // DYNAMIC METHOD BINDING OCCURS HERE!
  public void updateRectangles() {
    for (int i = 0; i<NUM_RECTS; i++) {
      r[i].danceStep();		// each rectangle's dance step
    }
  }

  // override update so it doesn't erase screen
  public void update(Graphics g) {
    paint(g);
  }

  public void paint(Graphics g) {

    offscreen.setColor(Color.black);
    offscreen.fillRect(0,0,ab.width,ab.height);	// clear buffer

    for (int i=0; i<NUM_RECTS; i++) {
      r[i].paint(offscreen);		// paint each rectangle
    }

    g.drawImage(image,0,0,this);
  }

  public void run() {
    while (true) {
      repaint();
      updateRectangles();
      try {
        Thread.sleep (REFRESH_RATE);
      }
      catch(Exception exc) { };
    }
  }

  public void stop() {

    System.out.println(">> stop <<");
    if (animation != null) {
      animation.stop();
      animation = null;
    }
  }
}
