import java.awt.*;

public class Line {

  Point A, B;  // this is the line between A and B

  boolean isStraight;

  // if it's a circle, then a center C and radius r are needed

  Point C;
  double r;

  // if it's is a straight line, then a point P and a direction D
  // are needed

  Point P;
  Point D;

  public Line (Point A, Point B) {
    this.A = A; this.B = B;
    // first determine if its a line or a circle
    double den = A.x*B.y - B.x*A.y;
    isStraight = (Math.abs(den) < 1.0e-14);
    if (isStraight) {
      P = A; // a point on the line}
      // find a unit vector D in the direction of the line}
      den = Math.sqrt((A.x-B.x)*(A.x-B.x) + (A.y-B.y)*(A.y-B.y)) ;
      D = new Point ((B.x - A.x) / den,
                     (B.y - A.y) / den);
    } else { // it's a circle
      // find the center of the circle thru these points}
      double s1 = (1.0 + A.x*A.x + A.y*A.y) / 2.0;
      double s2 = (1.0 + B.x*B.x + B.y*B.y) / 2.0;
      C = new Point ((s1*B.y - s2*A.y) / den,
                     (A.x*s2 - B.x*s1) / den);
      r = Math.sqrt(C.x*C.x+C.y*C.y - 1.0) ;
    } // if/else
  } // Line

  public String toString() {
    return "["+A+","+B+"]";
  }

  // Reflect the point R thru the this line to get Q the returned point}
  public Point reflect (Point R) {
    Point Q = new Point();
    if (isStraight) {
      double factor = 2.0 * ((R.x-P.x)*D.x + (R.y-P.y)*D.y) ;
      Q.x = 2.0 * P.x + factor * D.x - R.x ;
      Q.y = 2.0 * P.y + factor * D.y - R.y ;
    } else {  // it's a circle
      double factor = r*r / ((R.x-C.x)*(R.x-C.x) + (R.y-C.y)*(R.y-C.y)) ;
      Q.x = C.x + factor * (R.x - C.x) ;
      Q.y = C.y + factor * (R.y - C.y) ;
    } // if/else
    return Q;
  } // reflect

  // append screen coordinates to the list in order to draw the line
  public SCL appendScreenCoordinates (SCL list, Dimension d) {
    int x_center = d.width/2;
    int y_center = d.height/2;
    int radius = Math.min(x_center,y_center);
    int x = (int)Math.round(A.x*radius+x_center);
    int y = (int)Math.round(A.y*radius+y_center);
    if ((list == null || x != list.x || y != list.y) 
         && x!=Double.NaN && y!=Double.NaN)
      list = new SCL (list,x,y);
    if (isStraight) { // go directly to terminal point B
      x = (int)Math.round(B.x*radius+x_center);
      y = (int)Math.round(B.y*radius+y_center);
      if (x != list.x || y != list.y)
        list = new SCL (list,x,y);
    } else { // its an arc of a circle
	  // determine starting and ending angles
	  double alpha = Math.atan2((A.y-C.y),(A.x-C.x));
	  double beta  = Math.atan2((B.y-C.y),(B.x-C.x));
	  if (Math.abs(beta-alpha) > Math.PI)
	    if (beta < alpha)
		  beta  += 2.0*Math.PI;
		else
		  alpha += 2.0*Math.PI;
	  CircularCurve curve = new CircularCurve(C.x,C.y,r);
	  curve.setScreen(x_center,y_center,radius);
      list = curve.interpolate(list,alpha,beta);
    }
    return list;
  } // appendScreenCoordinates

  public void draw(Graphics g, Dimension d) {
      int x_center = d.width/2;
      int y_center = d.height/2;
      int radius = Math.min(x_center,y_center);
 // *** yet to write ***
  } // draw

} // Line