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

// A variation of a class that appears in Core Web
// Programming from Prentice Hall. May be freely used
// or adapted.
// 1998 Marty Hall, http://www.apl.jhu.edu/~hall/java/

//----------------------------------------------------
/** 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,
                               ActionListener {
  private Vector circles;
  private int width, height;
  private Button startButton, stopButton;
  private Thread animationThread = null;

  public void init() {
    setBackground(Color.white);
    width = getSize().width;
    height = getSize().height;
    circles = new Vector();
    startButton = new Button("Start a circle");
    startButton.addActionListener(this);
    add(startButton);
    stopButton = new Button("Stop all circles");
    stopButton.addActionListener(this);
    add(stopButton);
  }

  //----------------------------------------------------
  /** 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 void actionPerformed(ActionEvent event) {
    if (event.getSource() == startButton) {
      if (circles.size() == 0) {
        // Erase any circles from previous run.
        getGraphics().clearRect(0, 0, getSize().width,
                                      getSize().height);
        animationThread = new Thread(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.getSource() == stopButton) {
      if (animationThread != null) {
        animationThread.stop();
        circles.removeAllElements();
      }
    }
    repaint();
  }

  //----------------------------------------------------
  /** 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);  // Old position
      circle.move(width, height);
      g.setColor(getForeground());
      circle.draw(g);  // New position
    }
  }

  //----------------------------------------------------
  // 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) {}
  }
}
