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

public class BouncingBallsExt extends Applet {
    private static int width;
    private static int height;

    private int diameter = 10; // Diameter of the balls
    private int radius = diameter/2; //  Radius of the balls

    private Choice choice;
    private TextArea echoArea;
    private Button clearButton, newBallButton;

    private Color color;
    private String colorName; 

    private int lastClickX;
    private int lastClickY;
    
    private int lastMotionX;
    private int lastMotionY;

    private int clickNumber;
    private Vector balls;
    
    public void init ( ) {

	setBackground(Color.white);
	height = getBounds().height;
	width = getBounds().width;
	addMouseListener(new MouseHandler());
	addMouseMotionListener(new MouseMotionHandler());
	balls = new Vector();
	
        // Create a Clear button and add it to the Frame.
	clearButton = new Button("Clear");
	clearButton.setForeground(Color.black);
	clearButton.setBackground(Color.lightGray);
	add(clearButton);
	clearButton.addActionListener(new ClearButtonHandler());
	
        // Create a NewBall button and add it to the Frame.
	newBallButton = new Button("New Ball");
	newBallButton.setForeground(Color.black);
	newBallButton.setBackground(Color.lightGray);
	add(newBallButton);
	newBallButton.addActionListener(new NewBallButtonHandler());
	
        // Create a menu of user choices and add it to the Frame.
	choice = new Choice();
	choice.addItem("Orange");
	choice.addItem("Green");
	choice.addItem("Magenta");
	choice.addItem("Blue");
	add(choice);
	choice.addItemListener(new ChoiceHandler());
	
        // Create a TextArea and add it to the Frame.
        echoArea = new TextArea(2, 48);
        echoArea.setEditable(false);
        add(echoArea);   

    } // init

    
    public void start ( ) {
        repaint();
        newBallButton.setEnabled(true);  
	clickNumber=0;
        color = Color.orange;
        colorName = "Orange";
        choice.select("Orange");
	echoArea.setText("Color: Orange");
        echoArea.append("\nClick New Ball button to create a new ball with this color"); 
    } // start


    public void stop () {
        for (int i=0; i<balls.size(); i++) 
	    ((Ball) balls.elementAt(i)).stopBall();
        balls.removeAllElements();
    } // stop

   
    public void paint (Graphics g) {
	for (int i=0; i<balls.size(); i++) 
	    ((Ball) balls.elementAt(i)).paint(g);
    } // method paint of the applet


    private class ClearButtonHandler implements ActionListener {
	public void actionPerformed (ActionEvent e) {
            newBallButton.setEnabled(true);  
            clickNumber=0;
	    stop();   
            repaint(); 
	    echoArea.setText("Color: " + colorName);
	    echoArea.append("\nClick New Ball button to create a new ball with this color"); 
        }//actionPerformed
    }//clearButton handler


    private class NewBallButtonHandler implements ActionListener {
	public void actionPerformed (ActionEvent e) {	
	    echoArea.setText("Add a new " + colorName + " ball:");   	  
	    echoArea.append("\nclick mouse twice to define params of the new ball");	
	    newBallButton.setEnabled(false);  
	    lastMotionX = -1; 
	    lastMotionY = -1;
	    clickNumber=0;
	    for(int i=0;i<balls.size(); i++)				
		((Ball) balls.elementAt(i)).pauseBall(); // pause all the Balls
        }
    }//NewBallButton handler

    private class ChoiceHandler implements ItemListener {
	public void itemStateChanged (ItemEvent e) {
	    colorName = (String) e.getItem();
       
	    if (colorName.equals("Orange"))
		color=Color.orange;
	    
	    if (colorName.equals("Green"))
		color=Color.green;

	    if (colorName.equals("Magenta"))
		color=Color.magenta;
	    
	    if (colorName.equals("Blue"))
		color=Color.blue;	    

            echoArea.setText("Color selected: " + colorName);
            // prepare to handle first mouse click for this choice
            clickNumber = 0;
            echoArea.append("\nClick New Ball button to create a new ball with this color"); 
	}
    } // Choice menu handler      
    

    private class MouseMotionHandler extends MouseMotionAdapter {

	public void mouseMoved(MouseEvent e) {

	    if (newBallButton.isEnabled())
		return;  

	    int x = e.getX();
	    int y = e.getY();

	    Graphics g= getGraphics();		

	    if(clickNumber % 2 == 1){ // initial position already set
		g.setColor(Color.red);
		g.setXORMode (Color.white);			
		g.drawLine (lastClickX, lastClickY, x, y); //draw new line
		g.fillOval(x-3, y-3, 6, 6);	// draw small dot under the mouse
		g.drawLine (lastClickX, lastClickY, lastMotionX, lastMotionY); // erase previous line
		g.fillOval(lastMotionX-3, lastMotionY-3, 6, 6);	
		lastMotionX = x;			
		lastMotionY = y;		
	    } else {	
	        g.setColor(Color.lightGray); // before start() the new ball is light gray
		g.setXORMode(Color.white);			
		g.fillOval(x-radius, y-radius, diameter, diameter); // draw ball in new position
                if (lastMotionX!=-1) // erase ball from previous position
		    g.fillOval(lastMotionX-radius, lastMotionY-radius, diameter, diameter);	
		lastMotionX = x;  
		lastMotionY = y;
	    }
	}
    } // Mouse Motion handler


    private class MouseHandler extends MouseAdapter {

	public void mouseClicked(MouseEvent e) { 

	    if (newBallButton.isEnabled())
		return;  

	    int x = e.getX();
	    int y = e.getY();

            echoArea.setText("Mouse Clicked at " + x + ", " + y);
	    
	    clickNumber = clickNumber + 1;

	    // is it the first click?
	    if (clickNumber % 2 == 1) {  
		echoArea.append("\nClick in another point to set direction and speed");
		lastClickX = x;
		lastClickY = y;
	    }
	    // or the second?
	    else {
		int dx = (x-lastClickX)/10;
		int dy = (y-lastClickY)/10;
                newBallButton.setEnabled(true);  
	        for(int i=0;i<balls.size(); i++)				
		    ((Ball) balls.elementAt(i)).resumeBall(); // resume all the Balls
		Ball b = new Ball(lastClickX-radius, lastClickY-radius, dx, dy, color);
		balls.addElement(b);
		b.start();
		echoArea.setText("Color: " + colorName);
		echoArea.append("\nClick New Ball button to create a new ball with this color"); 
	    }	    
	} // mouseClicked
    } // Mouse handler
    

    private class Ball extends Thread {
	
        int x, y;     // current location
        int dx, dy;   // speed
        Color color;
        boolean alive;
        boolean pause;

        public Ball (int x, int y, int dx, int dy, Color color) {
            this.x = x;
            this.y = y;
            this.dx = dx;
            this.dy = dy;
            this.color = color;
            alive = true;
            pause = false;
        }

        public void move () {
            if (x < 0 || x >= BouncingBallsExt.width)
                dx = - dx;
            if (y < 0 || y >= BouncingBallsExt.height)
                dy = - dy;
            x += dx;
            y += dy;
        }

        public void paint (Graphics g) {
	    g.setColor(color);
            g.fillOval(x, y, diameter, diameter);
        }

        public synchronized void stopBall () { //substitutes stop() which is deprecated
            alive = false;
        }

        public synchronized boolean isLiving() {
            return alive;
        }
 
        public synchronized void pauseBall() {
            pause = true;
        }

        public synchronized void resumeBall() { 
            pause = false;
        }

        public synchronized boolean isPaused() {
            return pause;
        }
 
        public void run () {
            while  (isLiving()) {
                if (!isPaused()) {
                    move();
                    if (this==balls.lastElement())
		        repaint();
                }
                try { 
                    Thread.sleep(50);
                } catch (InterruptedException exc) { }
            }
	    
	    
        }


    } // Ball

} // BouncingBalls

