/*
 * Selim Mimaroglu
 *
 * CS680
 * Object-Oriented Design
 * Spring 2002
 *
 * File: ~smimarog/cs680/p3/MarbleGround.java
 *
 */

import javax.swing.*;
import java.awt.*;
import java.util.Enumeration;
import java.util.Vector;
import java.net.URL;

/**
 * @author Selim Mimaroglu
 * @version 1.0
 *
 * All the motions related to marbles take place here.
 * It's the play ground of the Marble Game.
 *
 */

public class MarbleGround extends JPanel implements DoubleBufferedComponent {

    /**
     * Width of the playing area,
     * Height of the plaing area
     */
    private int playingWidth = 500, playingHeight = 500;


    /**
     * Marble Game will take place in a circle. Radius of this circle
     * is specified below
     */
    private final int RADIUS = 175;

    /**
     * middle of the circle has fallowing two components
     */
    private final int xoffset = playingWidth/2, yoffset = playingHeight/2;

    /**
     * Dimension object will be used for convenience
     */
    protected Dimension d;

    /**
     * Double Buffer Handler object
     */
    protected DoubleBufferHandler dbHandler;


    /**
     * default animation delay
     */
    private static int DEFAULT_ANIMATION_DELAY = 10;


    /**
     * this is the actual animation delay
     */
    private int animationDelay;


    /**
     * the set of balls on the table
     * player1 has index 0
     * player2 has index 1
     * and there are additional 13 marbles initially. Number of balls
     * vary depending on the condition
     * player1 and 13 marbles will be created in setupBalls()
     * method
     */
    private Vector balls;


    /**
     * Marks placed on the pool table for making a shot
     * There may be 0, or 1 of these
     *
     * it will look like below:
     *
     * mark(+) --------------> shooter
     *
     * in this case we need only one mark for shooting the marble
     */
    private Point marks[];

    /**
     * this value shows the amount of energy to be transfered
     * from one ball to the other one
     */
    final private static double TRANSFER_EFFICIENCY = 0.70;



    /**
     * this part keeps information about lagging
     * state 0: no lagging is done
     * state 1: lagging, first player
     * state 2: lagging, second player
     * state 3: indicates that lagging is done and there is
     *          a winner, start with the winner!
     *
     */
    private int lagState = 0;
    private int firstPlayerDistance, secondPlayerDistance;



    /**
     * score and scorer are kept in those fields.
     * They will be sent to Marble class
     *
     * Score panel will be modified depending on this
     * info
     *
     */
    private int playingUser = 0;
    private int relativeScore = 0;

    /**
     * URL codebase of the applet
     */
    public URL codebase;

    /**
     * Returns current player
     * @return current player
     *
     * whoIsPlaying will be called by
     * it will return the player who made score in the
     * previous shot
     * @see Marble (JApplet)
     *
     * 0 - if it's lagging
     * 1 - player 1
     * 2 - player 2
     * 3 - indicates that, a new set of game should start
     */
    public int whoIsPlaying() {
	return this.playingUser;
    }



    /**
     * Returns the current score
     * @return number of marbles gained by current user in this shot
     *
     * whatIsScore will return how much
     * whoIsPlaying scored
     *
     */
    public int whatIsScore() {
	return this.relativeScore;
    }

    /**
     * Set the lag state 
     * @param state state of the game
     * 0 - no lagging
     * 1 - player1 lagging
     * 2 - player2 lagging
     *
     */
    private void setLagState(int state) {
	this.lagState = state;
    }

    /**
     *
     * Constructs a marble ground with specific animation delay
     * set size of the playing ground here, call setupBalls()
     *
     * @param animationDelay delay of animation
     * @param codebase codebase of this JApplet
     */

    public void initCanvas( int animationDelay, URL codebase) {
	this.codebase = codebase;
	dbHandler = new DoubleBufferHandler(this);
	if( animationDelay < 0 ) {
	    animationDelay = DEFAULT_ANIMATION_DELAY;
	}
	this.animationDelay = animationDelay;

	//set the size of this Jpanel here
	setSize(playingWidth, playingHeight);

	// this is for convenience
	d = getSize();

	balls = new Vector();
	marks = new Point[2];

	//set up balls here;
	setupBalls();


	//one of the marks is stationary, its the place of player1 or player2
	marks[0] = new Point( playingWidth/2, playingHeight/2 + RADIUS);



    }



    /**
     * private helper to create the initial set of balls, and position
     * them on the table
     * player1, and player2 have distinct shooters
     *
     * they will be treated differently
     */
    private void setupBalls() {

	if ( lagState != 3 ) {
	    balls.removeAllElements();
	}

	int diameter = Ball.getRadius() * 2;

	// gap between each marble
	int gap = 2;

	// default - is starting with player one
	// if lagging, also start with player one
	if ( lagState == 0 || lagState == 1) {
	    PlayerBall p1 = new PlayerBall("violetball.gif", 0,0, playingWidth, playingHeight, codebase);
	    p1.setPlaying(true);
	    p1.setVertex( d.width/2 , d.height/2 + RADIUS);
	    p1.setActive(true);
	    balls.addElement(p1);
	}

	// lagging is going on, it's second player turn
	if ( lagState == 2 ) {
	    PlayerBall p2 = new PlayerBall("yellowball.gif", 0, 0, playingWidth, playingHeight, codebase);
	    p2.setPlaying(true);
	    p2.setVertex( d.width/2, d.height/2 + RADIUS);
	    p2.setActive(true);
	    balls.addElement(p2);
	}

	// lagging is done! and there is a winner
	// start game with the winner
	if ( lagState == 3 ) {
	    // reset lag state, and draw remaining 13 marbles
	    lagState = 0;
	}

	// we don't need 13 balls when we do lagging
	// but we need them when the regular game starts!
	if (lagState == 0) {

	    // here are remaining thirteen balls, they will be organized in
	    // plus shape in the center
	    Ball b;
	    String filename = "ball";
	    String number;

	    // first ball is in the center
	    b = new Ball("ball4.gif", 0, 0, playingWidth, playingHeight, codebase);
	    b.setVertex(xoffset, yoffset);
	    b.setActive(true);
	    balls.addElement(b);

	    // organize remaining 12 balls, set their vertex and
	    // activate all of them (including shooter and the one
	    // in the center)
	    for(int k = 0, i = diameter ; i < 4 * diameter ; i += diameter, k++) {

		if( k == 0 )
		    gap = 1;
		else
		    gap = 2;

		// for setting  upper half of plus shape
		b = new Ball( filename + Integer.toString(k) + ".gif", 0, 0, playingWidth, playingHeight, codebase);
		b.setVertex( xoffset, yoffset - i - gap);
		b.setActive(true);
		balls.addElement(b);

		// for setting lower half of plus shape
		b = new Ball(filename +Integer.toString(k) + ".gif", 0, 0, playingWidth, playingHeight, codebase);
		b.setVertex(xoffset, yoffset + i + gap);
		b.setActive(true);
		balls.addElement(b);
	    }

	    for ( int k = 1, i = diameter; i < 4 * diameter; i += diameter, k++) {

		// for setting left half of plus shape
		b = new Ball(filename + Integer.toString(k) + ".gif", 0, 0, playingWidth, playingHeight, codebase);
		b.setVertex( xoffset - i - gap, yoffset);
		b.setActive(true);
		balls.addElement(b);

		//for settting right half of plus shape
		b = new Ball( filename + Integer.toString(k) + ".gif", 0, 0, playingWidth, playingHeight, codebase);
		b.setVertex( xoffset + i + gap, yoffset);
		b.setActive(true);
		balls.addElement(b);

	    }
	}

	// set first mark
	// when balls are first step first mark is always the shooter
	// shooter is at the edge of the circle!
	marks[0] = new Point( d.width/2, d.height/2 + RADIUS);

    }

    /**
     * It will make double buffered painting
     *
     * @param g is Graphics instance
     */
    public void update(Graphics g) {
	dbHandler.update(g);
    }


    /**
     * Calls update(g) method
     * @param g is Graphics instance
     * 
     */
    public void paint(Graphics g) {
	update(g);
    }


    /**
     * It draws the playing ground,
     * every ball, including shooters drawn in this method
     *
     * @param g is Graphics instance,
     */

    public void paintFrame (Graphics g) {

	// draw outer part
	// outer circle is gray
	g.setColor(Color.lightGray);
	g.fillRect(0, 0, d.width, d.height);

	// draw inner circle
	// inner circle is white
	g.setColor(Color.white);
	g.fillOval( (d.width - 2*RADIUS) / 2, (d.height - 2*RADIUS)/2, 2*RADIUS, 2*RADIUS);

	// draw balls
	for( int index = 0; index < balls.size(); index++) {
	    Ball b = (Ball) balls.elementAt(index);

	    if ( b == null ) {
		continue;
	    }
	    // if ball is active draw it
	    if( b.isActive() ) {
		b.draw(g);
	    }
	}

	// draw lag line if needed
	if ( lagState == 1 || lagState == 2) {
	    g.setColor(Color.darkGray);
	    g.drawLine( d.width/4, d.height/2 - RADIUS, 3 *d.width/4, d.height/2 -RADIUS);
	}


	// draw cue mark
	if ( marks[1] != null ) {
	    g.setColor(Color.blue);
	    g.drawLine(marks[1].x-3, marks[1].y, marks[1].x+3, marks[1].y);
	    g.drawLine(marks[1].x, marks[1].y-3, marks[1].x, marks[1].y+3);
	}

    }



    /**
     * Reset the table to a starting state
     * put the balls back in their default positions,
     * clear the marks
     *
     */
    public void resetTable() {
	marks[1] = null;
	setupBalls();
	repaint();
    }




    /**
     * @param x x coordinate of the mark
     * @param y y coordinate of the mark
     * @return the number of set marks
     *
     * Ask the pooltable to set a mark at the given coordinates.
     * Return the number of marks on the table (including the one we just set).
     *
     * these are the marks used to  shoot a marble. There is one stationary mark
     * There may be 1, or 2 at any given time
     *
     * if two marks are set do nothing. (it means we are done, we don't need anymore)
     * otherwise, test to see if the mark is within table boundaries, and set
     * it.
     *
     */
    public int setMark(int x, int y) {
	int nextmark = 0;
	while (nextmark < marks.length) {
	    if (marks[nextmark] == null) {
		break;
	    }
	    nextmark++;
	}

	//if there are two marks return without doing anything
	if( nextmark == marks.length) {
	    return nextmark;
	}

	// don't let setting the same mark twice
	if ( nextmark == 1) {
	    if( marks[0].x == x && marks[0].y == y) {
		return 1;
	    }
	}

	// set the mark, repaint the frame
	marks[nextmark] = new Point(x, y);
	repaint();
	return nextmark + 1;

    }


    /**
     * Clear the marks on the circle, repaint the playing ground
     * without marks
     */

    public void clearMarks() {
	marks[1] = null;
	repaint();
	return;
    }


    /**
     * Shoot marble, in this method
     * One shooter at a time
     * Only shooter1 or shooter2 may be shot at a time.
     *
     */

    public void shootBall() {
	if ( marks[0] == null || marks[1] == null ) {
	    /* something wrong */
	    throw new IllegalStateException("shootBall: missing marks");
	}
	double direction = 0;
	double magnitude = 0;
	Graphics g = getGraphics();

	// the "velocity" is half of the distance applied between marks
	// one of the marks is shooter itself
	// so, the distance is between set mark and the shooter!
	magnitude = (MotionUtils.distance(marks[1], marks[0]) / 2.0);
	direction = MotionUtils.direction(marks[1], marks[0]);

	// when lagging, send the shooter slower for convenience
	if( lagState != 0) {
	    magnitude = magnitude / 2;
	}

	// Shot is done, we should erase the mark set by user
	// reset the mark
	marks[1] = null;

	// findout which player has to play, get the marble
	PlayerBall shootBall = (PlayerBall)balls.elementAt(0);
	if ( shootBall != null && shootBall.isPlaying() ) {
	    ;
	}
	else {
	    shootBall = (PlayerBall)balls.elementAt(1);
	}

	// activate the shootball, repaint it
	shootBall.setActive(true);
	repaint();

	// apply the force to the shootball
	shootBall.applyForce(magnitude, direction);

	//handle the rest of the motion
	playShot();

	// see if the shootBall fell of the table, also check other marbles
	checkBalls(shootBall);

	// schedule a redraw
	repaint();
	return;
    }



    /**
     * While there are balls in motion move them, check for collisions,
     * check for balls that have fallen into pockets, and re-draw the display.
     *
     */
    private void playShot() {
	Graphics g = this.getGraphics();

	while (haveBallsInMotion()) {
	    repositionBalls();
	    update(g);


	    // animation Delay
	    try {
		Thread.currentThread().sleep(animationDelay);
	    }
	    catch (InterruptedException e) {}
	}
    }



    /**
     * Test to see if there are balls moving on the Ground
     *
     * @return true if there are balls
     */
    private boolean haveBallsInMotion() {
	for (int index = 0; index < balls.size(); index++) {
	    Ball b = (Ball)balls.elementAt(index);
	    if (b.isMoving() ){
		return true;
	    }
	}
	return false;
    }


    /**
     * For each ball on the table:
     *  - see if the ball is in motion. If so ask it to move
     *  - see if the ball hit any other balls on the table
     *    If so, apply a force
     *    to any ball that was hit
     *
     *
     */
    private void repositionBalls() {

	for(int index = 0; index < balls.size(); index++ ) {
	    Ball current = (Ball)balls.elementAt(index);
	    if( ! current.isMoving() ){
		continue;
	    }

	    /**
	     * aside from checking for collisions after the ball moves,
	     * we need to check points between where the ball is, and where
	     * it will move to
	     */
	    int r = Ball.getRadius();
	    Enumeration pathIter = current.getPathEnumerator();

	    while( pathIter.hasMoreElements() ) {
		Ball other;
		Point pathPoint = (Point) pathIter.nextElement();
		for (int other_idx = 0; other_idx < balls.size(); other_idx++) {
		    other = (Ball)balls.elementAt(other_idx);
		    if(current == other) {
			continue;
		    }
		    if( other.isTouching(pathPoint, r) ) {
			/**
			 * Find direction to the center of the other ball, and
			 * the angle, relative to our direction
			 * Apply cos(theta) of velocity to the ball we hit,
			 * then apply the opposite force to current ball
			 *
			 */
			double theta = MotionUtils.direction(current.getVertex(), other.getVertex() );
			double direction = current.getDirection();
			double velocity = current.getVelocity();
			double delta = Math.abs(direction - theta);
			double applied = velocity * Math.cos(delta) * TRANSFER_EFFICIENCY;
			if (MotionUtils.distance(pathPoint, other.getVertex()) < 2 * r) {
			    if (applied < 1.0) {
				/**
				 * Technically, this is a hack--a little extra
				 * nudge to prevent balls from coming to rest
				 * in overlapping position
				 */
				applied += 2 * Ball.getFriction();
			    }
			}

			other.applyForce(applied, theta);
			current.applyForce(applied, MotionUtils.oppositeDirection(theta));
		    }
		}
	    }
	    current.move();
	}

    }




    /**
     * Check the status of all balls, make the game ready
     * to next shot...
     *
     * it's possible that one of the players won a few marbles
     * and it's maybe other player's turn
     * decide all of them here
     *
     * @param p shooter
     */
    private void checkBalls(PlayerBall p) {

	Ball ball;
	String currentFileName = p.getImageName(), otherFileName;
	PlayerBall otherplayer = null;
	boolean succeed = false, changeturn = true;
	boolean isotherplayer = false;
	boolean throwMarbleOut = false;

	// reset relative score
	this.relativeScore = 0;

	// lagging for first ball
	if ( lagState == 1 ) {
	    int y = p.getVertex().y;
	    firstPlayerDistance = y - (d.height/2 - RADIUS);
	    // goto next state
	    setLagState(2);
	    doLagging();

	    // When lagging we don't need to keep score
	    // indicate this situation
	    this.playingUser = 0;

	    return;
	}
	else if( lagState == 2) {
	    int y = p.getVertex().y;
	    secondPlayerDistance = y - (d.height/2 - RADIUS);
	    // goto nextSate
	    setLagState(3);
	    doLagging();

	    // When lagging we don't need to keep score
	    // indicate this situation
	    this.playingUser = 0;

	    return;
	}

	if ( currentFileName.equals("violetball.gif") ) {

	    // keep track of playing user
	    this.playingUser = 1;
	    otherFileName = "yellowball.gif";
	}
	else {
	    // keep track of playing user
	    this.playingUser = 2;
	    otherFileName = "violetball.gif";
	}

	Point center = new Point(d.width/2, d.height/2);

	// check all the balls one by one and look their situation
	for (int index = 0; index < balls.size();  index++) {
	    ball = (Ball)balls.elementAt(index);

	    // we shoot the other ball out of the circle
	    if( (ball instanceof PlayerBall) && ball != p) {


		ball.setActive( center, RADIUS);
		otherplayer = (PlayerBall) ball;
		isotherplayer = true;

		//it's out of the circle
		if( !ball.isActive() ) {
		    // this is end of the game, current player wins
		    this.playingUser = 3;
		    setupBalls();
		    return;
		}

	    }

	    // it's current players ball
	    else if ( (ball instanceof PlayerBall) && ball == p) {

		ball.setActive(center, RADIUS);

		// is it outof circle
		if ( !ball.isActive() ) {

		    // current player is out of circle he doesn't score
		    // any balls
		    this.playingUser = 0;
		    changeturn = true;
		    balls.removeElementAt(index);
		    index--;
		}
		// it's in the circle
		else {
		    // maybe we will continue with this ball
		    // if any other ball is outside, current player
		    // will continue
		    // change the location of first mark
		    marks[0] = p.getVertex();
		    changeturn = false;
		}
	    }

	    // those are remaining balls
	    else {
		ball.setActive(center, RADIUS);

		// is this ball out of circle
		if ( !ball.isActive() ) {

		    // keep score for each ball
		    this.relativeScore++;

		    throwMarbleOut = true;
		    balls.removeElementAt(index);
		    index--;
		}
	    }
	}

	// if there is nobody remaining  new game
	if( balls.size() == 0 ) {
	    this.playingUser = 3;
	    return;
	}

	// if remainig one ball is palyer's ball, it's a winning game
	if ( balls.size() == 1 ) {

	    if( (Ball)balls.elementAt(0) instanceof PlayerBall) {
		this.playingUser = 3;
		return;
	    }
	}





	// let's check all the data and make a decision

	// current ball remains inside the circle, there are some balls
	// outside the circle =
	// - current player will continue
	if ( (changeturn == false) &&  throwMarbleOut ) {
	    // no change in situation
	    // change first mark
	    marks[0] = p.getVertex();


	}
	else if ( (changeturn == false) && ( throwMarbleOut == false) ) {
	    // current ball remains inside
	    // all other balls remains inside
	    // marks[0] will be set to
	    // other players ball position, if there is any
	    // change turn of player


	    // O.K. is other player in the palying area
	    if ( isotherplayer ) {

		int i = balls.indexOf( otherplayer);
		((PlayerBall)balls.elementAt(i)).setPlaying(true);

		// set the new starting mark
		marks[0] = ((PlayerBall)balls.elementAt(i)).getVertex();

		i = balls.indexOf( p );
		if ( i != -1)
		    ((PlayerBall)balls.elementAt(i)).setPlaying(false);


	    }
	    else {
		// other player isn't in the play ground create it

		PlayerBall pNew = new PlayerBall( otherFileName, 0, 0, d.width, d.height, codebase);
		pNew.setVertex(d.width/2, d.height/2 + RADIUS);
		pNew.setActive(true);
		pNew.setPlaying(true);
		balls.insertElementAt(pNew, 0);
		marks[0] = new Point(d.width/2, d.height/2 + RADIUS);


	    }
	}
	else if ( changeturn) {
	    // current ball is outside the circle,
	    // no matter what turn changes

	    //if we have other ball, in playground
	    if ( isotherplayer ) {
		int i = balls.indexOf( otherplayer);
		((PlayerBall)balls.elementAt(i)).setPlaying(true);
		marks[0] = ((PlayerBall)balls.elementAt(i)).getVertex();
		}
	    else {
		// create other player
		PlayerBall pNew = new PlayerBall( otherFileName, 0, 0, d.width, d.height, codebase);

		pNew.setVertex(d.width/2, d.height/2 + RADIUS);
		pNew.setActive(true);
		pNew.setPlaying(true);
		balls.insertElementAt(pNew, 0);
		marks[0] = new Point(d.width/2, d.height/2 + RADIUS);
	    }
	}
    }



    /**
     * it makes angular turn to left
     * it turns all the marbles in angular
     * direction by pi/4.0 radians(45 degrees)
     * It doesn't effect the position of the shooter
     *
     */
    public void turnLeft() {

	// center point
	Point p = new Point( d.width/2, d.height/2);
	HiResPoint center = new HiResPoint(p);
	HiResPoint ballPoint;

	double direction, length, x, y;
	Ball b;

	for( int index = 0; index < balls.size(); index++ ) {
	    b = (Ball)balls.elementAt(index);
	    ballPoint = new HiResPoint( b.getVertex() );

	    // if it's shooter, do nothing
	    if( b instanceof PlayerBall) {
		continue;
	    }

	    if ( center.x == ballPoint.x && center.y == ballPoint.y ) {
		length = 0.0;
		direction = 0.0;
	    }
	    else {
		length = MotionUtils.distance( center, ballPoint );
		direction = MotionUtils.direction( center, ballPoint );
	    }

	    // reduce direction by PI/10.0
	    direction -= Math.PI/4.0;

	    // if resultant direction is negative, take care of it
	    if ( direction < 0 ) {
		direction = 2 * Math.PI + direction;
	    }

	    // get x and y components
	    x = length * Math.cos( direction );
	    y = length * Math.sin( direction );

	    // add offset values
	    x = d.width/2 + x;
	    y = d.height/2 - y;

	    // set the new vertex
	    ((Ball)balls.elementAt(index)).setVertex(Math.round(x), Math.round(y));

	}

	// paint the new locations
	repaint();
    }




    /**
     * 
     *  it makes angular right turn
     *  it turns all the marbles in angular
     *  direction by pi/4.0 radians(45 degrees)
     *
     *
     *  It doesn't effect the position of the shooter
     *
     */
    public void turnRight() {

	// center point
	Point p = new Point( d.width/2, d.height/2);
	HiResPoint center = new HiResPoint(p);
	HiResPoint ballPoint;

	double direction, length, x, y;
	Ball b;

	for( int index = 0; index < balls.size(); index++ ) {
	    b = (Ball)balls.elementAt(index);
	    ballPoint = new HiResPoint( b.getVertex() );

	    // if it's shooter, do nothing
	    if( b instanceof PlayerBall) {
		continue;
	    }

	    if ( center.x == ballPoint.x && center.y == ballPoint.y ) {
		length = 0.0;
		direction = 0.0;
	    }
	    else {
		length = MotionUtils.distance( center, ballPoint );
		direction = MotionUtils.direction( center, ballPoint );
	    }

	    // increase direction by PI/4
	    direction += Math.PI/4.0;

	    // if resultant direction is negative, take care of it
	    if ( direction > 2*Math.PI ) {
		direction -= 2*Math.PI;
	    }

	    // get x and y components
	    x = length * Math.cos( direction );
	    y = length * Math.sin( direction );

	    // add offset values
	    x = d.width/2 + x;
	    y = d.height/2 - y;

	    // set the new vertex
	    ((Ball)balls.elementAt(index)).setVertex(Math.round(x), Math.round(y));

	}

	// paint the new locations
	repaint();
    }




    /**
     * Lagging is done here.
     * Two shooters do lagging. One, closer to line wins
     * If both of them pass the line: closer wins
     * If both of them are out of the playing area red marble
     * wins by default
     */
    public void doLagging() {

	// red ball is the first player
	if ( lagState == 0) {
	    setLagState(1);
	    setupBalls();
	    repaint();
	}
	else if (lagState == 2) {
	    setupBalls();
	    repaint();
	}
	else if (lagState == 3) {
	    String firstBall = "violetball.gif";
	    String secondBall = "yellowball.gif";
	    PlayerBall playerBall;

	    // if both of them didn't pass the line
	    if ( firstPlayerDistance >= 0 && secondPlayerDistance >= 0) {

		// first player is closer
		if( firstPlayerDistance <= secondPlayerDistance ) {
		    playerBall = new PlayerBall(firstBall, 0, 0, d.width, d.height, codebase);
		}
		// second player is closer
		else {
		    playerBall = new PlayerBall( secondBall, 0, 0, d.width, d.height, codebase);
		}

	    }
	    // both of the balls pass the line
	    else if(  firstPlayerDistance < 0 && secondPlayerDistance < 0 ) {

		// first player is closer
		if( firstPlayerDistance >= secondPlayerDistance ) {
		    playerBall = new PlayerBall(firstBall, 0, 0, d.width, d.height, codebase);
		}
		// second player is closer
		else {
		    playerBall = new PlayerBall( secondBall, 0, 0, d.width, d.height, codebase);
		}
	    }

	    // first player pass the line, second didn't pass it
	    // in this case second player wins lagging
	    else if ( firstPlayerDistance < 0 && secondPlayerDistance >= 0) {
		playerBall = new PlayerBall( secondBall, 0, 0, d.width, d.height, codebase );
	    }

	    // second player pass the line, first player didn't pass the line
	    // in this case, first player wins lagging
	    else {
		playerBall = new PlayerBall( firstBall, 0, 0, d.width, d.height, codebase);
	    }

	    playerBall.setPlaying(true);
	    playerBall.setVertex( d.width/2 , d.height/2 + RADIUS);
	    playerBall.setActive(true);
	    balls.removeAllElements();
	    balls.addElement(playerBall);

	    setupBalls();
	}

    }








}












