import objectdraw.*;
import java.awt.*;

/* $Id: BreakoutBall.java 1602 2011-04-14 02:51:26Z terescoj $ */

/**
 * 
 * A simple active object that controls a ball that bounces around the
 * canvas and interacts with a boundary, a pong paddle, and a set of
 * breakout bricks.
 *
 * @author Jim Teresco, Siena College, CSIS 120, Fall 2011
 *
 */

public class BreakoutBall extends ActiveObject {

    // control speed of falling balls
    private static final double MIN_SPEED = 3;
    private static final double MAX_SPEED = 10;
    private static final int DELAY_TIME = 33;

    // the ball controlled by this instance
    private FilledOval ball;

    // the paddle with which we will interact
    private FilledRect paddle;

    // how far to fall before stopping and disappearing?
    private double yMax;
    // how far up to go before bouncing off the ceiling?
    private double yMin;
    // and what about the walls?
    private double xMin, xMax;

    // is this ball still in play?
    private boolean outOfPlay;

    // the brick collection with which we interact
    private BrickCollection bricks;

    /**
     * Draw a ball and start it moving around the playing area.
     * 
     * @param diameter size of the ball to create
     * @param paddle the paddle with which to interact
     * @param bricks the collection of bricks with which the ball may collide
     * @param boundary the boundary of the playing area determining the
     *    walls off which the ball will bounce
     * @param aCanvas the DrawingCanvas on which to place the ball
     */
    public BreakoutBall(double diameter, FilledRect paddle, 
    BrickCollection bricks, FramedRect boundary,
    DrawingCanvas aCanvas) {

        // compute/remember our boundaries (of the upper left corner of a ball)
        yMax = boundary.getY()+boundary.getHeight();
        yMin = boundary.getY();
        xMin = boundary.getX();
        xMax = boundary.getX() + boundary.getWidth() - diameter;

        // random generator for the x-coordinate
        RandomDoubleGenerator posGen = new RandomDoubleGenerator(xMin, xMax);

        // draw the ball at its initial position, which is half way down
        // from the top of the playing area, at a randomly-selected x position
        ball = new FilledOval(posGen.nextValue(), (yMin + yMax)/2,
            diameter, diameter, aCanvas);
        ball.setColor(Color.white);

        // remember the paddle
        this.paddle = paddle;

        // remember the bricks
        this.bricks = bricks;

        // set the ball as in play
        outOfPlay = false;

        // activate!
        start();
    }

    /**
     * move the ball repeatedly until it falls off screen, bouncing
     * off the paddle and walls and taking out bricks along the way
     */ 
    public void run() {
        double xSpeed, ySpeed;

        // start by moving downward and some amount to the left or right
        RandomDoubleGenerator speedGen = new RandomDoubleGenerator(MIN_SPEED, MAX_SPEED);

        xSpeed = speedGen.nextValue();
        double initYSpeed = speedGen.nextValue();
        ySpeed = initYSpeed;
        
        // keep moving as long as we haven't fallen off the bottom of
        // the screen
        while (ball.getY() <= yMax) {
            // if we are above the top line, start moving down
            if (ball.getY() < yMin) {
                ySpeed = initYSpeed;
            }

            // if we are in contact with the paddle, start moving up
            if (ball.overlaps(paddle)) {
                if (ball.getY() > (paddle.getY() - ball.getHeight()/2)) {
                    // hit a side, so change xSpeed instead of ySpeed
                    xSpeed = -xSpeed;
                }
                else {
                    ySpeed = -initYSpeed;
                }
            }

            // 
            // bounce off side walls
            if (ball.getX() < xMin || ball.getX() > xMax) {
                xSpeed = -xSpeed;
            }

            // check for contact with bricks
            if (bricks.hitBrick(ball)) {
                ySpeed = -ySpeed;
            }

            // move a little in the appropriate direction
            ball.move(xSpeed, ySpeed);
            pause(DELAY_TIME);
        }

        ball.removeFromCanvas();
        outOfPlay = true;
    }

    /**
     * check if the ball has moved out of the playing area (turn over)
     *
     * @return whether the ball has moved out of the playing area
     */
    public boolean outOfPlay() {

        return outOfPlay;
    }
}
