import java.awt.*;
import java.util.*;
/** Assignment A4: using a Turtle 
 * 
 Do this:
 
    b1= new Ballnas28(30, 70, 30);
    b2= new Ballnas28(-30, 40, 30);
    Ballnas28.ballSplit(b1, b2);
    
 To see two balls bounce around. When they collide, the smaller
 one splits into two balls (and the colors change).
 It may take a while for them to collide. Be patient.*/
public class Ballnas28 extends Turtle{
  
  private int radius; // the radius of the current ball
  private double vx; // the ball's acceleration in the x direction
  private double vy; // the ball's acceleration in the y direction  
  private double origin; // a random number that is assigned to a ball when it splits from another
  
  /** = the radius of the ball*/
  public int getRadius(){
    return radius;
  }
  /** = the balls acceleration in the x direction, type double */
  public double getVX(){
    return vx;
  }
  /** = the balls acceleration in the y direction, type double*/
  public double getVY(){
    return vy;
  }
  /** = the balls origin, type double */
  public double getOrigin(){
    return origin;
  }
  /** Constructor: a new Ball, parameters are: position (int x,int y), acceleration (double vx,double vy), radius int r, color c*/
  public Ballnas28( int x, int y, double vx, double vy, int r, Color c){
    moveTo(x,y,0); 
    setColor(c);
    fillCircle(r*2);
    radius= r;
    this.vx= vx;
    this.vy= vy;
    origin= Math.random();
    
  }
  /** Constructor: a new Ball, parameters are: position (int x,int y), acceleration (double vx,double vy), radius int r, color c, double origin*/
  public Ballnas28( int x, int y, double vx, double vy, int r, Color c, double origin){
    moveTo(x,y,0); 
    setColor(c);
    fillCircle(r*2);
    radius= r;
    this.vx= vx;
    this.vy= vy;
    this.origin= origin;  
  }
  /** Constructor: a new Ball, parameters are: acceleration (double vx,double vy), radius int r, the Ballnas28 starts at the midpoint of the panel and is black*/
  public Ballnas28( double vx, double vy, int r){
    int x= (getWidth()/2); // gets the mid point of width
    int y= (getHeight()/2); // gets the mid point of the height
    moveTo(x,y,0); 
    setColor(Color.black);
    fillCircle(r*2);
    radius= r;
    this.vx= vx;
    this.vy= vy;
    origin= Math.random();
    
    
  }
  /** Moves Ball once by the acceleration (vx, vy) of the Ball. The respective acceleration of the Ball will reverse once it 
   * it touches the wall parallel with the x or y axis */
  public void moveBallOnce(){
    Color save= getColor();                                           // This variable saves the color of the Ball
    new Ballnas28( getX(), getY(), getVX(), getVY(), getRadius(), Color.white);
    moveTo(getX()+ (int)getVX(), getY()+ (int)getVY(), 0);            // Changes the Balls values of X and Y
    if (getRadius() > getX() || getHeight()- getX() < getRadius())
      vx= -vx;                                                        // reverses the value of x if the ball is touching a wall
    if (getRadius() > getY() || getHeight()- getY() < getRadius())
      vy= -vy;                                                        // reverses the value of y if the ball is touching a wall
    new Ballnas28( getX(), getY(), vx, vy, getRadius(), save);
    
  }
  /** puts a Ball in motion forever moving according to 
   * its acceleration (vx, vy), the procedure will not terminate by itself*/
  public void inMotion(){
    while(true){
      pause(100);
      moveBallOnce();
    }
  }
  /** Static method,  puts Ball b1, and Ball b2 in motion forever moving according
   * to there acceleration (vx, vy) the procedure will not terminate by itself*/ 
  public static void inMotion(Ballnas28 b1, Ballnas28 b2){
    for(;;){
      b1.pause(100);
      b1.moveBallOnce();
      b2.moveBallOnce();
    }
  }
  /** Static method, puts Ball b1, and Ball b2 in motion, they splitbwhen they collide. The procedure 
   * will not terminate by itself. When two Balls collide one will split into more balls with random color and 
   * lesser radius than the Ball which was split, and acceleration (vx,vy) of the new balls are components of the Ball 
   * which was split. When two balls with similar origin collide, they wont split. Balls of radius less than 5 do not 
   * collide. Only 2 splits allowed per frame */
  public static void ballSplit(Ballnas28 b1, Ballnas28 b2){
    Vector v= new Vector(); // the vector in which Balls will be stored
    v.add(b1);
    v.add(b2);
    int n= v.size(); // number of elements in the vector
    // each cycle of this forever loop is a new frame
    while(true){
      b1.pause(100);
      // inv: n, n+1, ... v.size()-1 are the vector positions of Balls that have been moved this frame
      while (n != 0){
        n= n-1;
        ((Ballnas28)v.elementAt(n)).moveBallOnce();
      }  
      n= v.size(); // n is again the number of elements in the vector
      int q= n; // another value for the number of elements in the vector
      int nofram= 0; // the number of collisions that have occured in this frame
      // inv: n, n+1, ... v.size()-1 are the vector positions of Balls that have been tested for collision
      while (n != 0){ 
        n= n-1;
        //inv: q, q+1, ... v.size()-1 are the vector positions of Balls that have been tested for collision with Ball in vector position n
        while (q != 0) {
          q= q-1;
          int rn= ((Ballnas28)v.elementAt(n)).getRadius(); // the radius of ball in vector position n
          int rq= ((Ballnas28)v.elementAt(q)).getRadius(); // the radius of ball in vector position q
          int xn= ((Ballnas28)v.elementAt(n)).getX(); // the x position of the ball in vector position n
          int xq= ((Ballnas28)v.elementAt(q)).getX(); // the x position of the ball in vector position q
          int yn= ((Ballnas28)v.elementAt(n)).getY(); // the y position of the ball in vector position n
          int yq= ((Ballnas28)v.elementAt(q)).getY(); // the y position of the ball in vector position q
          double vxn= ((Ballnas28)v.elementAt(n)).getVX(); // the x acceleration of the ball in vector position n
          double vxq= ((Ballnas28)v.elementAt(q)).getVX(); // the x acceleration of the ball in vector position q
          double vyn= ((Ballnas28)v.elementAt(n)).getVY(); // the y acceleration of the ball in vector position n
          double vyq= ((Ballnas28)v.elementAt(q)).getVY(); // the y acceleration of the ball in vector position q
          if (     q != n 
                && nofram < 2
                && rn >= 5
                && rq >= 5
                && Math.abs(xn-xq) <= (rn+rq)
                && Math.abs(yn-yq) <= (rn+rq)
                && Math.abs((xn-vxn)-(xq-vxq)) <= (rn+rq)
                && Math.abs((yn-vyn)-(yq-vyq)) <= (rn+rq)
                && (((Ballnas28)v.elementAt(n)).getOrigin() != ((Ballnas28)v.elementAt(q)).getOrigin())){
            Ballnas28 b;// the ball that will be split
            int xb; // the x position of ball that will be split
            int yb; // the y position of ball that will be split
            double vxb; // the x acceleration of ball that will be split
            double vyb; // the y acceleration of ball that will be split
            int rb; // the radius of ball that will be split
            int vb; // the vector position of ball that will be split
            double og;// the origin for the split balls
            double nb= Math.random(); // a random number that will be used to specify the ball that splits, split ball 1's color, and the split balls origins
            double nbb= Math.random(); // a random number that will be used to specify split ball 2's color
            Color cb1= Color.green; // the color of split ball 1 will be choosen randomly from orange, red, blue, green, and yellow
            Color cb2= Color.red; // the color of split ball 1 will be choosen randomly from orange, red, blue, green, and yellow
            if (nb <= 0.5){
              b= (Ballnas28)v.elementAt(n);
            }
            else {
              b= (Ballnas28)v.elementAt(q);
            }
            if ( nb < .2){
              cb1= Color.red;
            }
            if ( .2 <= nb && nb < .4){
              cb1= Color.blue;
            }
            if ( .4 <= nb && nb < .6){
              cb1= Color.pink;
            }
            if ( .6 <= nb && nb < .8){
              cb1= Color.orange;
            }
            if ( .8 <= nb){
              cb1= Color.yellow;
            }
            if ( nbb < .2){
              cb2= Color.red;
            }
            if ( .2 <= nbb && nbb < .4){
              cb2= Color.blue;
            }
            if ( .4 <= nbb && nbb < .6){
              cb2= Color.green;
            }
            if ( .6 <= nbb && nbb < .8){
              cb2= Color.orange;
            }
            if ( .8 <= nbb){
              cb2= Color.yellow;
            }
            xb= b.getX();
            yb= b.getY();
            vxb= b.getVX();
            vyb= b.getVY();
            rb= b.getRadius();
            Color colorb= b.getColor();
            vb= v.indexOf( b);
            new Ballnas28 ( xb, yb, 0,0, rb, Color.white);
            v.set(vb, new Ballnas28( xb, yb, (-(double)vxb*(.9)), (-(double)vyb*(.9)), (int)(rb/1.2), cb1, nb));
            v.add(new Ballnas28( xb, yb, ((double)vxb*(.9)), ((double)vyb*(.9)), (int)(rb/1.2), cb2, nb));
            nofram++;
          }
        }
        q= v.size();
      }
      n= v.size();
    }
  }
}
