// package PongishGame;
import java.awt.*;
import java.awt.geom.*;
import edu.neu.ccs.gui.*;

public class Ball{
	double x, y, vx, vy;   //(x, y) position of this ball, and velocity components
	double radius, mass;   //radius and mass of this ball
	boolean hit;           //has this ball been involved in a collision in the current frame 
	boolean fill;		   //draw the ball filled if true, otherwise draw outline
	Mover m;               //the mover responsible for moving this ball
	Color fillCol = Color.blue;   //The color that the ball is filled with
	
	public Ball(double x, double y, double vx, double vy, double mass, double radius, boolean fill, Mover m){
		//initialize variables
		this.x = x;
		this.y = y;
		this.vx = vx;
		this.vy = vy;
		this.mass = mass;
		this.radius = radius;
		this.hit = false;
		this.m = m;
		this.fill = fill;
	}
	
	public void draw(Graphics g){
		if(fill){ //-draw filled circle
			Ellipse2D.Double circle = new Ellipse2D.Double((int)(x-radius), (int)(y-radius), (int)(2*radius), (int)(2*radius));
			ShapePaintable c = new ShapePaintable(circle, PaintMode.FILL, fillCol);
			c.paint(g);
		}else{    //-draw outlined circle
			g.setColor(Color.black);
			g.drawOval((int)(x-radius),(int)(y-radius),(int)(2*radius),(int)(2*radius));
		}
	}

	public void interact(Ball b) {
		double dx = b.x - x;                 //delta x
		double dy = b.y - y;                 //delta y
		double h = Math.sqrt(dx*dx + dy*dy); //distance between center of balls

		// if the balls are colliding, compute their new velocities using conservation of momentum
		if (h < radius+b.radius){ 
			hit = b.hit = true;   //these balls have collided... do not exert gravity on them
			
		    //  Compute the (elastic) collision of this ball and given ball
			//  m1 * v1 + m2 * v2 = k*((m1 + m2) * v')
			double v1, v2, l1, l2, vPrime, v, tm;
		    dx /= h;
		    dy /= h;						// normalize
		    v1 = vx*dx + vy*dy;
		    v2 = b.vx*dx + b.vy*dy;			// collision velocity
		    l1 = vx*dy - vy*dx;
		    l2 = b.vx*dy - b.vy*dx;			// leftover velocity
		    tm = mass + b.mass;				// total mass
		    if ((tm==0) || (v1 < v2)) return;
		    
		    vPrime = (v1*mass + v2*b.mass)/tm;
		    
		    //new velocity for this ball
		    v = vPrime + 0.85 * (v2 - v1) * b.mass / tm;
		    vx = v*dx + l1*dy;
		    vy = v*dy - l1*dx;
		    
		    //new velocity for ball b
		    v = vPrime + 0.85 * (v1 - v2) * mass / tm;
		    b.vx = v*dx + l2*dy;
		    b.vy = v*dy - l2*dx;
		}
	}
	

	public boolean update(){
		// add velocities and keep ball within boundaries
		x += vx;
		y += vy;
		boolean hitOut = fence();
		
		if(!hit) vy += m.grav;   // exert gravity if this ball wasnt involved in a collision
		hit = false;             // reset the 'hit' flag
		return hitOut;
	}
	
	public boolean fence(){
		double nx, ny;
		nx = x - m.width/2;
		ny = y - m.height/2;
		double hypot = hypot(nx, ny);
		if(hypot + radius > m.rBound){
			hit = true;
			
			//check if ball was left to fall out of bounds
			double ballRad = Math.atan2(nx,ny) + Math.PI;
			double position = Math.toDegrees(ballRad);
			double halfPdl = m.paddleWidth/2;
			
			if((m.playerPos < halfPdl) && (position > (360-halfPdl)))
				position -= 360;
			else if((position < halfPdl) && (m.playerPos > (360-halfPdl))) 
				position += 360;
			
			if(Math.abs(position - m.playerPos) > m.paddleWidth/2){
				fillCol = Color.red;
				return true;
			}
			
			m.retCount++;
			
			//ball was returned, bounce it off the object
			double chg = hypot / (m.rBound - radius);
			if(nx < 0){
				x *= chg;
				vx = Math.abs(vx);
				if(ny < 0){
					y *= chg;
					vy = Math.abs(vy);
				}else{
					y /= chg;
					vy = -Math.abs(vy);
				}
			}else{
				x /= chg;
				vx = -Math.abs(vx);
				if(ny < 0){
					y *= chg;
					vy = Math.abs(vy);
				}else{
					y /= chg;
					vy = -Math.abs(vy);
				}
			}

			//make the ball go faster after hitting it,
			//  to make things a little more interesting ;)
			vx *= 1.1;
			vy *= 1.1;
		}
		return false;
	}

	//return the length of the hypotenuse
	public static double hypot(double x, double y){
		return Math.sqrt(x*x + y*y);
	}
}
