import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.*;

public class GrowingBouncing extends JApplet {

    public void init(){

 	getContentPane().add(new Bouncing(), BorderLayout.CENTER);

	JPanel bottomPanel = new JPanel();	
	JButton grow = new JButton("Grow");
	grow.addActionListener(new ActionListener() {
		public void actionPerformed(ActionEvent e){
		    getContentPane().remove(0);
		    getContentPane().add(new Growing(), 0);
		    getContentPane().validate();
		}
	    });
	JButton bounce = new JButton("Bounce");
	bounce.addActionListener(new ActionListener() {
		public void actionPerformed(ActionEvent e){
		    getContentPane().remove(0);
		    getContentPane().add(new Bouncing(), 0);
		    getContentPane().validate();
		}
	    });
	bottomPanel.add(grow);
	bottomPanel.add(bounce);
	getContentPane().add(bottomPanel, BorderLayout.SOUTH);



    }

    public void start(){}

    public void stop(){}


}

class Bouncing extends JComponent implements Runnable {
    Random r = new Random();
    float w = 4;
    int d = r.nextInt(75) + 5;
    int x = r.nextInt(450);  // x coordinate
    int y = r.nextInt(450);  // y coordinate
    int dx; // change in x
    int dy; // change in y
    double i = 0;

    public Bouncing(){
	getDirection();

	Thread t = new Thread(this);
	t.start();
    }

    private int rectify(double s){
	if (s >= 0){return(1);}
	else {return(-1);}
    }

    private void getDirection(){
	int direct = rectify(Math.sin(Math.toRadians(r.nextDouble() * 360)));

	dx = r.nextInt(1)+1 * direct * 5;
	dy = r.nextInt(1)+1 * direct * 5;
    }

    private void atWall(){
	Double wCorrection = new Double(w/2);
	int c = wCorrection.intValue();

	if (x-c <= 0 || x+c >= 500 - d){x = x - dx; dx = dx * -1;}
	if (y-c <= 0 || y+c >= 500 - d){y = y - dy; dy = dy * -1;}
    }


    public void paint(Graphics g){
	Graphics2D g2 = (Graphics2D)g;

	// set the background color
	g2.setPaint(Color.orange);
  	g2.fillRect(0, 0, 500, 500);

	// paint the oval
	g2.setPaint(Color.green);
	g2.setStroke(new BasicStroke(w));
	g2.drawOval(x, y, d, d);

	// check if a change in direction is necessary
	atWall();

	// update the variables
 	x = x + dx;
 	y = y + dy;
	int direct = rectify(Math.sin(Math.toRadians(i)));
	if (direct == 1){
	    d = d + 1;
	    Double wid = new Double((double)w + 0.25);
	    w = wid.floatValue();
	}
	else {
	    d = d -1;
	    Double wid = new Double((double)w - 0.25);
	    w = wid.floatValue();
	}
	i = i + 1;
    }

    public void run(){
	try {
	    while(true) {
		repaint();
		Thread.sleep(2^3);
	    }
	}
	catch (InterruptedException e){}
    }

}

class Growing extends JComponent implements Runnable {
    Random r = new Random();

    Vector w = new Vector(38);  // stroke width
    Vector d = new Vector(38);  // circle diameter
    Vector x = new Vector(38);  // x location of a circle
    Vector y = new Vector(38);  // y location of a circle

    public Growing(){
	Thread t = new Thread(this);
	t.start();
    }

    public void paint(Graphics g) {
	Graphics2D g2 = (Graphics2D)g;

	// set the background color
	g2.setPaint(Color.orange);
  	g2.fillRect(0, 0, 500, 500);

	if (w.size() >= 33){
	    removeCircles();
	} 
	else {
	    addCircles();
	}

	for (int i=0; i<w.size(); i++){
	    float wid = ((Float)w.elementAt(i)).floatValue();
	    int diam = ((Integer)d.elementAt(i)).intValue();
	    int h = ((Integer)x.elementAt(i)).intValue();
	    int v = ((Integer)y.elementAt(i)).intValue();

	    if (diam <= 163){
		g2.setPaint(Color.green);
		g2.setStroke(new BasicStroke(wid));
		g2.drawOval(h, v, diam, diam);
	    }

	    w.remove(i);
	    w.insertElementAt(new Float((float)((double)wid + .25)), i);
	    d.remove(i);
	    d.insertElementAt(new Integer(diam + 1), i);
	}

    }

    private void addCircles() {
	int howMany = r.nextInt(4) + 1 + w.size();
	float width = 1; // stroke width
	int diameter = 1;   // circle diameter
	int h; // x location of a circle
	int v; // y location of a circle
	
	for (int i=w.size(); i<=howMany; i++){
	    h = r.nextInt(500);
	    v = r.nextInt(500);

	    w.add(i, new Float(width));
	    d.add(i, new Integer(diameter));
	    x.add(i, new Integer(h));
	    y.add(i, new Integer(v));
	}

    }

    private void removeCircles(){
	int [] which = new int [r.nextInt(5)];

	for (int i=0; i<which.length; i++){
	    which[i] = r.nextInt(w.size() - which.length);
	}
	
	for (int i=0; i<which.length; i++){
	    w.remove(which[i]);
	    d.remove(which[i]);
	    x.remove(which[i]);
	    y.remove(which[i]);
	}

    }

    
    public void run() {
	try {
	    while(true) {
		repaint();
		Thread.sleep(69);
	    }
	}
	catch (InterruptedException e){}
    }


}
