/*

Stage.java

The Stage class creates and manages all the balls, does all
the drawing and sound playing, 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 {

    public Bounce   bounce;

    Graphics        offGraphics = null;
    Image           offImage;

    private Thread  conductor;

    private Ball    balls[];
    private int     numBalls;
    private int     numBallsAllocated;

    private int     width;
    private int     height;
    
    private int     sleepy = 5;


    // ----- constructor
    public Stage( Bounce bounce,int width,int height )  {
	this.bounce = bounce;
	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
