/* squash.java   Daniel Scharstein  10/21/96
 *
 * structure nabbed from Sun's Graph Layout demo
 */

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

class Ball {
  int x;     // position
  int y;

  int dx;    // velocity
  int dy;

  int radius;
  Color color;

  public Ball(){ // creates ball with random attributes
    x = (int)(Math.random()*100)+50;
    y = (int)(Math.random()*100)+50;
    dx = (int)(Math.random()*4)+3;
    dy = (int)(Math.random()*4)+3;
    radius = (int)(Math.random()*8)+8;
    switch ((int)(Math.random()*6)) {
    case 0: color = Color.red; break;
    case 1: color = Color.green; break;
    case 2: color = Color.blue; break;
    case 3: color = Color.cyan; break;
    case 4: color = Color.yellow; break;
    case 5: color = Color.magenta; break;
    default: color = Color.black;
    }
  }
}

public class Squash extends Applet implements Runnable {

  final int MAXBALLS = 50;
  Ball ball[] = new Ball[MAXBALLS];
  int numBalls = 0;
  int paddlepos = 0;
  int paddlewidth = 80;

  Thread bouncer;

  public void addBall() {
    if (numBalls < MAXBALLS) {
      ball[numBalls] = new Ball();
      numBalls++;
    }
  }
  public void removeBall(int num) {
    int i;
    for (i=num; i<numBalls; i++)
      ball[i] = ball[i+1];
    numBalls--;
  }
  
  public void init() {
    addBall();
  }
  
  public void run() {
    while (true) {
      int i;
      for (i=0; i<numBalls; i++)
	moveBall(ball[i], i);
      try {
      	Thread.sleep(5);
      } catch (InterruptedException e) {
      	break;
      }
    }
  }

  synchronized void moveBall(Ball ball, int num) {
    Dimension d = size();
    int XMIN = ball.radius;
    int XMAX = d.width - ball.radius;
    int YMIN = ball.radius;
    int YMAX = d.height - ball.radius;

    ball.x += ball.dx;
    if (ball.x > XMAX) {
      ball.x = XMAX - (ball.x - XMAX);
      ball.dx = -ball.dx;
    } else if (ball.x < XMIN) {
      ball.x = XMIN + (XMIN - ball.x);
      ball.dx = -ball.dx;
    }
    
    ball.y += ball.dy;
    if (ball.y > YMAX) {
      if (Math.abs(ball.x - paddlepos) + ball.radius < paddlewidth) {
	ball.y = YMAX - (ball.y - YMAX);
	ball.dy = -ball.dy;
      }
      else
	removeBall(num);
    } else if (ball.y < YMIN) {
      ball.y = YMIN + (YMIN - ball.y);
      ball.dy = -ball.dy;
    }
    repaint();
  }

  Image offscreen;
  Dimension offscreensize;
  Graphics offgraphics;
    
  public void paintBall(Graphics g, Ball ball) {
    int x = (int)ball.x;
    int y = (int)ball.y;
    g.setColor(ball.color);
    int r = ball.radius;
    g.fillOval(x - r, y - r, r+r, r+r);
    g.setColor(Color.black);
    g.drawOval(x - r, y - r, r+r, r+r);
  }

  public synchronized void update(Graphics g) {
    Dimension d = size();
    int i;

    if ((offscreen == null) || (d.width != offscreensize.width) ||
	(d.height != offscreensize.height)) {
      offscreen = createImage(d.width, d.height);
      offscreensize = d;
      offgraphics = offscreen.getGraphics();
      offgraphics.setFont(getFont());
    }

    offgraphics.setColor(getBackground());
    offgraphics.fillRect(0, 0, d.width, d.height);

    for (i=0; i<numBalls; i++)
      paintBall(offgraphics, ball[i]);

    offgraphics.setColor(Color.black);
    offgraphics.fillRect(paddlepos-paddlewidth/2, d.height-3,
			 paddlewidth, 3);

    g.drawImage(offscreen, 0, 0, null);
  }

  public synchronized boolean mouseDown(Event evt, int x, int y)
  {
    addBall();
    repaint();
    return true;
  }
  public synchronized boolean mouseMove(Event evt, int x, int y) {
    paddlepos = x;
    repaint();
    return true;
  }

  public void start() {
    bouncer = new Thread(this);
    bouncer.start();
  }

  public void stop() {
    bouncer.stop();
  }
}
