import java.awt.*;
import javax.swing.*;

/** Do this:
      b1= new Ballsps27(20,30,20);
      b2= new Ballsps27(40, -30, 30);
      Ballsps27.inMotion3d(b1, b2, 20, 30);
    to have two balls bounce in a 200x200x200 cube!
  */
public class Ballsps27 extends Turtle {
  private int radius;
  private int vx;
  private int vy;
  
  /** getRadius() returns the radius of a Ball. */
  public int getRadius() {
    return radius;
  }
  
  /** getvx() returns the horizontal velocity of a Ball. */
  public int getvx() {
    return vx;
  }
  
  /** getvy() returns the vertical velocity of a Ball. */
  public int getvy() {
    return vy;
  }
  
  /** Constructor: a ball with radius r1, starting at (x1,y1), angle 0,
   * velocity (vx1,vy1), and color c1. */
  public Ballsps27(int x1,int y1,int vx1,int vy1,int r1,Color c1) {
    super(x1,y1,0);
    vx = vx1;
    vy = vy1;
    radius = r1;
    pause(100);
    setColor(c1);
    fillCircle(radius*2);
  }
  /** Constructor: a ball with radius r1 starting at the midpoint
   * at angle 0, velocity (vx1,vy1), color black. */
  public Ballsps27(int vx1,int vy1, int r1) {
    super();
    vx = vx1;
    vy = vy1;
    radius= r1;
    fillCircle(radius*2);
  }
  /** Constructor: a ball with radius r1 starting at (x1,y1)
    * at angle 0, velocity (vx1, vy1), and color c1 as given in Turtle.tColor */
  public Ballsps27(int x1,int y1, int vx1, int vy1, int r1, int c1) {
    super(x1,y1,0);
    vx = vx1;
    vy = vy1;
    radius = r1;
    pause(100);
    tColor(c1);
    fillCircle(radius*2);
  }

  /** Constructor: a  with radius r1 starting at the midpoint
    * at angle 0, velocity (vx1, vy1), and color c1 as given in Turtle.tColor*/
  public Ballsps27(int vx1, int vy1, int r1, int c1) {
    super();
    vx= vx1;
    vy= vy1;
    radius = r1;
    tColor(c1);
    fillCircle(radius*2);
  }
  
  /** Moves the ball once on the screen, erasing the old ball as it moves. The ball
   * moves with velocity vx,vy. */
  public void moveBallOnce() {
    Color save = getColor(); //save stores the color of the ball so it isnt lost when the ball is erased in white.
    setColor(Color.white);
    fillCircle(radius*2);
    moveTo(getX()+vx,getY()+vy,0);
    
    //these if statements reflect the ball off the wall if it has gotten too close.
    if( getX() < radius) {
      vx = -vx;
      moveTo(2*radius - getX(),getY(),0);
    }
    if( getX() > getWidth() - radius) {
      vx = -vx;
      moveTo(2*getWidth()-2*radius-getX(),getY(),0);
    }
    if( getY() < radius) {  
      vy = -vy;
      moveTo(getX(),2*radius - getY(),0);
    }
    if ( getY() > getHeight() - radius) {
      vy = -vy;
      moveTo(getX(),2*getHeight()-2*radius-getY(),0);
    }
    setColor(save);
    fillCircle(radius*2);
    
  }
  
  /** Sets the ball in motion forever. There is a pause of 0.1 seconds between each
   * movement. */
  public void inMotion() {
   
    for (;;){
      pause(100);
      moveBallOnce();
    }
  }
  
  /** Sets two balls in motion forever.  Each ball is moved and then there is a pause
   * of 0.1 seconds.*/
  public static void inMotion(Ballsps27 b1, Ballsps27 b2) {
    for (;;){
      b1.pause(100);
      b1.moveBallOnce();
      b2.moveBallOnce();
    }
  }
  
  /** Sets two balls b1,b2 in motion forever inside a cube with dimenstions 200x200x200.
   * The cube is drawn in a window along with front, top, and side views of the cube.
   * b1 and b2 are put at 2/5 of their position in the x,y plane, and at z = 100. The 2/5
   * is because the cube is 2/5 the size of the original 500x500 windows that most Balls
   * are in.  The position is kept in both 3d and 2d, and the velocity also has 3 components.
   * vz1 and vz2 are the initial z velocities of the two balls.  3 lines are drawn through each
   * of the balls, perpindicular to the sides of the cube, with length 200, stretching from one
   * end of the cube to the other, so that it is easier to see where the balls are inside the cube.*/
  public static void inMotion3d(Ballsps27 b1, Ballsps27 b2, int vz1, int vz2) {
    
    //the 3 components of the velocity for each of the 2 balls.
    int vx13d = b1.getvx();
    int vy13d = b1.getvy();
    int vz13d = vz1;
    int vx23d = b2.getvx();
    int vy23d = b2.getvy();
    int vz23d = vz2;
    
    //the 3 components of position for each of the 2 balls.
    int x13d = b1.getX()*2/5;
    int x23d = b2.getX()*2/5;
    int y13d = b1.getY()*2/5;
    int y23d = b2.getY()*2/5;
    int z13d = 100;
    int z23d = 100;
    
    //the 2d positions of the two balls, used for the graphics.
    int x12d;
    int x22d;
    int y12d;
    int y22d;
    
    Turtle t = new Turtle(); //the turtle is used to draw all the necissary lines.
    for (;;) {
      
      //erase balls
      Color save = b1.getColor(); //save is used to store the color of a ball when the ball is erased in white.
      b1.setColor(Color.white);
      b1.fillCircle(2*b1.getRadius());
      b1.setColor(save);
      save = b2.getColor();
      b2.setColor(Color.white);
      b2.fillCircle(2*b2.getRadius());
      b2.setColor(save);
      
      //draw the cube.
      t.moveTo(50,423,0);
      t.putPenDown();
      t.move(200);
      t.addAngle(90);
      t.move(200);
      t.addAngle(90);
      t.move(200);
      t.addAngle(90);
      t.move(200);
      t.moveTo(150,250,0);
      t.move(200);
      t.addAngle(90);
      t.move(200);
      t.addAngle(90);
      t.move(200);
      t.addAngle(90);
      t.move(200);
      t.setAngle(240);
      t.move(200);
      t.moveTo(150,50,240);
      t.move(200);
      t.moveTo(350,50,240);
      t.move(200);
      t.moveTo(350,250,240);
      t.move(200);
      
      //fix directions on edeges
      if (x13d < b1.getRadius() || x13d > 200 - b1.getRadius())
        vx13d = -vx13d;
      
      if (x23d < b2.getRadius() || x23d > 200 - b2.getRadius())
        vx23d = -vx23d;
      
      if (y13d < b1.getRadius() || y13d > 200 - b1.getRadius())
        vy13d = -vy13d;
      
      if (y23d < b2.getRadius() || y23d > 200 - b2.getRadius())
        vy23d = -vy23d;
      
      if (z13d < b1.getRadius() || z13d > 200 - b1.getRadius())
        vz13d = -vz13d;
      
      if (z23d < b2.getRadius() || z23d > 200 - b2.getRadius())
        vz23d = -vz23d;
      
      //update 3d position, then 2d position   
      x13d = x13d + vx13d;
      y13d = y13d + vy13d;
      z13d = z13d + vz13d;
      x23d = x23d + vx23d;
      y23d = y23d + vy23d;
      z23d = z23d + vz23d;
      x12d= (int) (-1*x13d*.5 + y13d + 150);
      y12d= (int) (x13d*.866 - z13d + 250);
      x22d= (int) (-1*x23d*.5 + y23d + 150);
      y22d= (int) (x23d*.866 - z23d + 250);
      
      //draw balls
      b1.moveTo(x12d,y12d,0);
      b2.moveTo(x22d,y22d,0);
      b1.fillCircle(2*b1.getRadius());
      b2.fillCircle(2*b2.getRadius());
      
      //draw traces
      t.setColor(b1.getColor());
      t.moveTo((int) (-1*x13d*.5 + 0 + 150),(int) (x13d*.866 - z13d + 250),0);
      t.move(200);
      t.moveTo((int) (-1*0*.5 + y13d + 150),(int) (0*.866 - z13d + 250),240);
      t.move(200);
      t.moveTo((int) (-1*x13d*.5 + y13d + 150),(int) (x13d*.866 - 0 + 250),90);
      t.move(200);
      
      t.setColor(b2.getColor());
      t.moveTo((int) (-1*x23d*.5 + 0 + 150),(int) (x23d*.866 - z23d + 250),0);
      t.move(200);
      t.moveTo((int) (-1*0*.5 + y23d + 150),(int) (0*.866 - z23d + 250),240);
      t.move(200);
      t.moveTo((int) (-1*x23d*.5 + y23d + 150),(int) (x23d*.866 - 0 + 250),90);
      t.move(200);
      
      //draw boxes for other views.
      t.setColor(Color.black);
      t.moveTo(380,150,0);
      t.move(100);
      t.addAngle(90);
      t.move(100);
      t.addAngle(90);
      t.move(100);
      t.addAngle(90);
      t.move(100);
      
      t.moveTo(380,300,0);
      t.move(100);
      t.addAngle(90);
      t.move(100);
      t.addAngle(90);
      t.move(100);
      t.addAngle(90);
      t.move(100);
      
      t.moveTo(380,450,0);
      t.move(100);
      t.addAngle(90);
      t.move(100);
      t.addAngle(90);
      t.move(100);
      t.addAngle(90);
      t.move(100);
      
      //draw the balls in the front, top, and size views.
      b1.moveTo(380+y13d/2,150-z13d/2,0);
      b1.fillCircle(b1.getRadius());
      b2.moveTo(380+y23d/2,150-z23d/2,0);
      b2.fillCircle(b2.getRadius());
      
      b1.moveTo(380+y13d/2,200+x13d/2,0);
      b1.fillCircle(b1.getRadius());
      b2.moveTo(380+y23d/2,200+x23d/2,0);
      b2.fillCircle(b2.getRadius());
      
      b1.moveTo(480-x13d/2,450-z13d/2,0);
      b1.fillCircle(b1.getRadius());
      b2.moveTo(480-x23d/2,450-z23d/2,0);
      b2.fillCircle(b2.getRadius());      
      
      
      b1.pause(100);
      
      //erase traces
      t.setColor(Color.white);
      t.moveTo((int) (-1*x13d*.5 + 0 + 150),(int) (x13d*.866 - z13d + 250),0);
      t.move(200);
      t.moveTo((int) (-1*0*.5 + y13d + 150),(int) (0*.866 - z13d + 250),240);
      t.move(200);
      t.moveTo((int) (-1*x13d*.5 + y13d + 150),(int) (x13d*.866 - 0 + 250),90);
      t.move(200);
      
      t.moveTo((int) (-1*x23d*.5 + 0 + 150),(int) (x23d*.866 - z23d + 250),0);
      t.move(200);
      t.moveTo((int) (-1*0*.5 + y23d + 150),(int) (0*.866 - z23d + 250),240);
      t.move(200);
      t.moveTo((int) (-1*x23d*.5 + y23d + 150),(int) (x23d*.866 - 0 + 250),90);
      t.move(200);
      t.setColor(Color.black);
      
      save = b1.getColor();
      b1.setColor(Color.white);
      b1.moveTo(380+y13d/2,150-z13d/2,0);
      b1.fillCircle(b1.getRadius());
      b1.moveTo(380+y13d/2,200+x13d/2,0);
      b1.fillCircle(b1.getRadius());
      b1.moveTo(480-x13d/2,450-z13d/2,0);
      b1.fillCircle(b1.getRadius());
      b1.setColor(save);
      
      save=b2.getColor();
      b2.setColor(Color.white);
      b2.moveTo(380+y23d/2,150-z23d/2,0);
      b2.fillCircle(b2.getRadius());
      b2.moveTo(380+y23d/2,200+x23d/2,0);
      b2.fillCircle(b2.getRadius());
      b2.moveTo(480-x23d/2,450-z23d/2,0);
      b2.fillCircle(b2.getRadius());  
      b2.setColor(save);
      
      b1.moveTo(x12d,y12d,0);
      b2.moveTo(x22d,y22d,0);
    }
    
  }
    
  /* Test code to type into interactions pane for inMotion3d()
   import java.awt.*;
   u = new Ballsps27(200,300,-4,3,10,Color.green);
   v = new Ballsps27(150,200,5,2,15,Color.red);
   u.pause(1000);
   u.clear();
   u.pause(1000);
   Ballsps27.inMotion3d(u,v,8,-4);
  */
  
  
}