// Hau Hwang
// 6.837 Assignment #2

import display.*;

public class CohenSutherland {

    public static final int TOP = 8;
    public static final int BOTTOM = 4;
    public static final int RIGHT = 2;
    public static final int LEFT = 1;
    
    /*
      Inputs: the original line from (x1,y1) to (x2,y2), and a
      viewport The viewport object has four public instance variables,
      which can be accessed by: 
      var1 = viewport.top; 
      var2 = viewport.bottom; 
      var3 = viewport.left; 
      var4 = viewport.right;

      Output: a LineSegment object 
            You can create a LineSegment object by making the call
			      LineSegment ls = new LineSegment()

            Having created it, you must set five values: 
	    x1, y1, x2, y2    the coordinates of each of the
                              endpoints of the clipped line You set
                              these values by including the line
                              ls.setEndPoints(x1, y1, x2, y2); 
			      or alternatively, by setting each of
                              the endpoints individually: 
			      ls.x1 = x1;
                              ls.y1 = y1; 
			      etc.

	    clipType          The clip type can be set to three
	                      values:

			      "internal" if the input line segment
			      falls entirely within the clip region,
			      otherwise:

                              "clipped" if it was determined that
                              some part of the input line segment does
                              fall within the boundaries defined by the
                              clip region, otherwise:

			      "external" if NO part of the input
			      line segment falls within the clip region
			      (i.e. the entire line was clipped.)
                              
			      You can set these values by including
			      the java statements:
                                    ls.setClipType("internal");
			      OR
                                    ls.setClipType("clipped");
                              OR
                                    ls.setClipType("external");
    
	NOTE: If you want to have any auxiliary methods (helpers), you
	must make sure to declare them "static" as well.
    */

    public static LineSegment ClipSegment(double x1, double y1, 
				       double x2, double y2, 
				       Viewport vp) {
      int code1, code2;
      boolean first_time = true;
      double slope = 0;

      while (true) {
	code1 = outcode(x1, y1, vp.top, vp.bottom, vp.left, vp.right);
	code2 = outcode(x2, y2, vp.top, vp.bottom, vp.left, vp.right);
	
	if (code1 == 0 && code2 == 0) { // end points in viewport
	  LineSegment ls = new LineSegment();
	  if (first_time) {
	    ls.setClipType("internal");
	  } else {
	    ls.setClipType("clipped");
	  }
	  ls.setEndPoints(x1, y1, x2, y2);
	  return ls;
	} else if ((code1 & code2) != 0) { // end points not in viewport
	  LineSegment ls = new LineSegment();
	  ls.setClipType("external");
	  return ls;
	}

	if (code1 == 0) { // switch code1 & code2; working with 0 code is silly
	  int temp1 = code1;
	  code1 = code2;
	  code2 = temp1;
	  
	  double temp2 = x1;
	  x1 = x2;
	  x2 = temp2;
	  
	  temp2 = y1;
	  y1 = y2;
	  y2 = temp2;
	}
	if (x1 != x2) {
	  slope = (y2 - y1) / (x2 - x1);
	}
	if ((code1 & LEFT) != 0) {
	  y1 += (vp.left - x1) * slope;
	  x1 = vp.left;
	} else if ((code1 & RIGHT) != 0) {
	  y1 += (vp.right - x1) * slope;
	  x1 = vp.right;
	} else if ((code1 & BOTTOM) != 0) {
	  if (x1 != x2) {
	    x1 += (vp.bottom - y1) / slope;
	  }
	  y1 = vp.bottom;
	} else if ((code1 & TOP) != 0) {
	  if (x1 != x2) {
	    x1 += (vp.top - y1) / slope;
	  }
	  y1 = vp.top;
	}
	first_time = false;
      }
    }
    /*
      This method, given a point (x,y) and some clip region
      boundaries, should produce the binary clip codes for the
      Cohen-Sutherland algorithm.  
    */
    public static int outcode(double x, double y,
			      double top, double bottom, 
			      double left, double right) {

      int result = 0;
      //System.out.println(top + " " + bottom + " " + left + " " + right);
      //System.out.println(x + " " + y);

      if (x < left) {
	result += LEFT;
      } else if (x > right) {
	result += RIGHT;
      }

      if (y < bottom) {
	result += BOTTOM;
      } else if (y > top) {
	result += TOP;
      }

      return result;
    }	
}





