/*

Stage.java

The Stage class creates and manages all the balls, does all the
drawing, and actually does the work for the applet's start() and
stop() methods, suspending and resuming its thread and those of all
the balls.

*/

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


public class Stage extends Canvas implements Runnable {

    Graphics offGraphics = null;
    Image    offImage;

    Thread   conductor;

    Ball     balls[];
    int      numBalls;
    int      numBallsAllocated;

    int      width;
    int      height;
    
    int      sleepy = 5;


    // ----- constructor
    public Stage( int width,int height )  {
	this.width  = width;
	this.height = height;
        setBackground( Color.black );
        numBalls = 0;
        numBallsAllocated = 10;
        balls = new Ball[numBallsAllocated];
        conductor = null;
    } // end of Stage constructor



    //----- methods for setting and maintaining the size of the canvas

    public Dimension preferredSize() {
	return( new Dimension( width,height ));
    } // end of preferredSize()
    
    public Dimension minimumSize() {
	return( new Dimension( width,height ));
    } // end of minimumSize()



    //----- methods for the Bounce applet object to call

    public void start() {
        if ( conductor == null ) {
            conductor = new Thread(this, "Stage");
            conductor.start();
        } 
	else {
            for ( int i = 0; i < numBalls; i++ ) {
                balls[i].start();
            }
            conductor.resume();
        }
    } // end of start()

    public void stop() {
        for( int i = 0; i < numBalls; i++ ) {
            balls[i].stop();
        }
        conductor.suspend();
    } // end of stop()

    public void addBall() {
	Color color = chooseColor( numBalls );
	Ball ball = new Ball( "Ball "+(numBalls+1),color,this,sleepy );
	System.out.println( "here "+ball.toString() );
	// enlarge ball array if necessary.
	if ( numBalls == numBallsAllocated ) {
	    Ball newBalls[];
	    numBallsAllocated *= 2;
	    newBalls = new Ball[numBallsAllocated];
	    System.arraycopy( balls,0,newBalls,0,numBalls );
	    balls = newBalls;
	}
	balls[numBalls] = ball;
	numBalls++;
	ball.start();
    } // end of addBall()



    //----- methods for conductor thread to run

    public void run() {
        while ( true ) {
            repaint();
            try {
                Thread.sleep( sleepy );
            } 
	    catch ( InterruptedException ix ) {
                break;
            }
        }
    } // end of run()

    public void faster() {
	if ( sleepy > 0 ) {
	    sleepy--;
	}
	for ( int i=0; i<numBalls; i++ ) {
	    balls[i].setSleepy( sleepy );
	}
	System.out.println( "faster... " + sleepy );
    } // end of faster()

    public void slower() {
	sleepy++;
	for ( int i=0; i<numBalls; i++ ) {
	    balls[i].setSleepy( sleepy );
	}
	System.out.println( "slower... " + sleepy );
    } // end of slower()


    // we have overridden update() instead of paint() since the
    // background does not need to be cleared when doing double
    // buffering.
    public synchronized void update( Graphics g ) {
	if ( offGraphics == null ) {
	    offImage = createImage( width,height );
	    offGraphics = offImage.getGraphics();
	}
	offGraphics.setColor( getBackground() );
	offGraphics.fillRect( 0,0,width,height );
	for (int i = 0; i < numBalls; i++) {
	    balls[i].paint( offGraphics );
	}
	g.drawImage( offImage, 0, 0, this );
    } // end of update()



    //----- private methods.

    private Color chooseColor( int i ) {
        switch (i % 5) {
            case 0: return Color.white;
            case 1: return Color.red;
            case 2: return Color.blue;
            case 3: return Color.green;
            case 4: return Color.yellow;
        }
        // Not reached
        return Color.white;
    } // end of chooseColor()



} // end of Stage class
