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

// This appears in Core Web Programming from
// Prentice Hall Publishers, and may be freely used
// or adapted. 1997 Marty Hall, hall@apl.jhu.edu.

//----------------------------------------------------
/** Bounce circles around on the screen.
 *  Doesn't use double buffering so has problems
 *  with overlapping circles. Overrides update
 *  to avoid flicker problems.
 */

public class Bounce extends Applet
                    implements Runnable {
  private Vector circles;
  private int width, height;
  private Button startButton, stopButton;
  private Thread animationThread = null;
  private ThreadGroup appletThreadGroup;

  public void init() {
    setBackground(Color.white);
    width = size().width;
    height = size().height;
    circles = new Vector();
    startButton = new Button("Start a circle");
    add(startButton);
    stopButton = new Button("Stop all circles");
    add(stopButton);
    // For Netscape-3 problems
    appletThreadGroup =
      Thread.currentThread().getThreadGroup();
  }

  //----------------------------------------------------
  /** When the "start" button is pressed, start the
   *  animation thread if it is not already started.
   *  Either way, add a circle to the Vector of
   *  circles that are being bounced.
   *  <P>
   *  When the "stop" button is pressed, stop
   *  the thread and clear the Vector of circles.
   */
  public boolean action(Event event, Object object) {
    if (event.target == startButton) {
      if (circles.size() == 0) {
        animationThread =
          new Thread(appletThreadGroup, this);
        animationThread.start();
      }
      int radius = 25;
      int x = radius + randomInt(width - 2 * radius);
      int y = radius + randomInt(height - 2 * radius);
      int deltaX = 1 + randomInt(10);
      int deltaY = 1 + randomInt(10);
      circles.addElement(new MovingCircle(x, y, radius,
                                          deltaX,
                                          deltaY));
    } else if (event.target == stopButton) {
      if (animationThread != null) {
        animationThread.stop();
        circles.removeAllElements();
      }
    }
    repaint();
    return(true);
  }
                                  
  //----------------------------------------------------
  /** Each time around the loop, call paint and then
   *  take a short pause. The paint method will
   *  move the circles and draw them.
   */
  public void run() {
    while(true) { // Really while thread not stopped
      repaint();
      pause(100);
    }
  }
                                  
  //----------------------------------------------------
  /** Skip the usual screen-clearing step of update
   *  so that there is no "flicker" between each
   *  drawing step.
   */
  public void update(Graphics g) {
    paint(g);
  }
                                  
  //----------------------------------------------------
  /** Erase each circle's old position, move it,
   *  then draw it in new location.
   */
  public void paint(Graphics g) {
    MovingCircle circle;
    for(int i=0; i<circles.size(); i++) {
      circle = (MovingCircle)circles.elementAt(i);
      g.setColor(getBackground());
      circle.draw(g);
      circle.move(width, height);
      g.setColor(getForeground());
      circle.draw(g);
    }
  }
                                  
  //----------------------------------------------------
  // Returns an int from 0 to max (inclusive),
  // yielding max + 1 possible values.

  private int randomInt(int max) {
    double x =
      Math.floor((double)(max + 1) * Math.random());
    return((int)(Math.round(x)));
  }
                                  
  //----------------------------------------------------
  // Sleep for the specified amount of time.
                                  
  private void pause(int milliseconds) {
    try {
      Thread.sleep((long)milliseconds);
    } catch(InterruptedException ie) {}
  }
}

