/***********************************************************************
 * Bounce2.java
 *
 * This applet is a second pass at controlling a bouncing ball via a
 * moded start/stop button.
 *
 * Comments in the following point out departures from Bounce1.java.
 ***********************************************************************/

import java.applet.*;
import java.awt.*;
import java.awt.event.*;

public class Bounce2 extends Applet implements ActionListener
{
    private Canvas display = new Canvas();
    private Button startStop = new Button("Start");
    private Ball ball = null;

    public void init()
    {
        setLayout(new BorderLayout());
        add("South", startStop);
        add("Center", display);
        startStop.addActionListener(this);
    }

    public void actionPerformed(ActionEvent e)
    {
        if (e.getActionCommand().equals("Start"))
        {
            startStop.setLabel("Stop");
            ball = new Ball(display, Color.red);

            /* We no longer animate the ball here.  Instead, we start its
             * thread.
             */

            ball.start();
        }
        else
        {
            startStop.setLabel("Start");
            ball.finish();  // Terminate the ball's thread.
        }
    }
}


/***********************************************************************
 * class Ball --- This class extends the Thread class, therefore it must
 *    have a run() method.
 ***********************************************************************/

class Ball extends Thread
{
    private Canvas theCanvas;
    private Color color;
    private int x, y;
    private int dx, dy;
    private boolean done = false;  // Is thead done executing?
    final static int RADIUS = 5;
    
    public Ball(Canvas c, Color co)
    {
        theCanvas = c;
        color = co;
        x = 0;
        y = (int) (10 + 480 * Math.random());
        dy = (int)(1.0 + Math.round(2.5 * Math.random()));
        dx = (int)(1.0 + Math.round(2.5 * Math.random()));
    }
    
    
/***********************************************************************
 * public void run() --- As its last action, the default start() method
 *    calls run().  This is where we use the new thread to animate the
 *    ball.
 ***********************************************************************/

    public void run()
    {
        draw(color);
        
        while (!done)
        {
            move();

            /* Try/catch pair necessary as during sleep() the checked
             * InterruptedException may occur and must be handled.
             */

            try
            {
                /* Thread sleeps for 10 ms., yielding control to another
                 * thread.  This efficiently replaces our spin-loop.
                 */

               sleep(10);
            }
            catch (InterruptedException e)
            {
            }
        }
        
        draw(Color.white);  // Clean up by erasing the ball.
    }

    
    private void draw(Color c)
    {
        Graphics g = theCanvas.getGraphics();
        g.setColor(c);
        g.fillOval(x, y, 2*RADIUS, 2*RADIUS);
        g.dispose();
    }
    

    private void move()
    {
        draw(Color.white);
        x += dx;  
        y += dy;
        Dimension d = theCanvas.getSize();
        if (x < 0) {x = 0; dx = -dx;}
        if (x + 2*RADIUS >= d.width) { x = d.width-2*RADIUS; dx = -dx;}
        if (y < 0) {y = 0; dy = -dy;}
        if (y + 2*RADIUS >= d.height) { y = d.height-2*RADIUS; dy = -dy;}
        draw(color);
    }
    
    
/***********************************************************************
 * public void finish() --- Set the done flag, ultimately causing the 
 *    thread to complete.
 ***********************************************************************/
    
    public void finish()
    {
       done = true;
    }
}
