import display.*;

public class CohenSutherland {

    public static final int LEFT = 1;
    public static final int RIGHT = 2;
    public static final int TOP = 4;
    public static final int BOTTOM = 8;
    
    /*
      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.

	-----------------------------------------------

	The code below attempts to minimize the number of necessary Java statements.

	The main structure is a loop that computes the outcodes of the endpoints.
	In the first iteration, the return result if a line is found is "internal".
	In all subsequent rounds, any non-external line can only be "clipped".

	Each pass has a test for a trivial accept or trivial reject, based on
	the bit values. After that, it tries clipping on the left, right, bottom,
	and top sides in each different try through the loop. There is a single
	return part at the end of the code, with 

	We assume that endpoints don't really matter for an "external" segment 
	(if they do, they could easily be stored though -- right now, it's just
	storing the last endpoints tested). We are assuming that order of the
	endpoints matters, so it goes to the length of unswapping the endpoints
	if swapping was necessary in computation.

        We further leverage on the fact that the outcode bit values guarantee for 
        clipping that the divided by portion will not be 0, to avoid zero-checking.

    */

    public static LineSegment ClipSegment(double x1, double y1, 
				       double x2, double y2, 
				       Viewport vp) {
        String result="internal"; // default response value 
	boolean swapped=false; // used to normalize segment order
	int trynum = 0;  // used for left, right, bottom, top clipping

	while (true) {
	  int code1 = outcode(x1, y1, vp.top, vp.bottom, vp.left, vp.right);
	  int code2 = outcode(x2, y2, vp.top, vp.bottom, vp.left, vp.right);

	  if ((code1 + code2)==0) break; // trivially accept

	  if ((code1 & code2)!=0) {
	    result="external";
	    break;
	  }

	  // we want to clip segments in left, right, bottom, top order
	  switch ((++trynum)) {
	  case 1:  // LEFT clip
	    result="clipped"; // so now we're either clipped or external
	    // guarantee x order...
	    if (x2<x1) { double a=x2;x2=x1;x1=a; a=y2;y2=y1;y1=a; swapped=!swapped;}
	    // we don't have to check 0-divide because of constraints from outcodes
	    if (x1<vp.left) { y1=y1+((vp.left-x1)*(y2-y1)/(x2-x1)); x1=vp.left;}
	    break;
	  case 2: // RIGHT clip
	    if (x2>vp.right) { y2=y2+((vp.right-x2)*(y2-y1)/(x2-x1)); x2=vp.right;}
	    break;
	  case 3: // BOTTOM clip
	    // guarantee y order
	    if (y2<y1) { double a=x2;x2=x1;x1=a; a=y2;y2=y1;y1=a; swapped=!swapped;}
	    if (y1<vp.bottom) { x1=x1+((vp.bottom-y1)*(x2-x1)/(y2-y1));y1=vp.bottom;}
	    break;
	  case 4: // TOP clip
	    if (y2>vp.top) { x2=x2+((vp.top-y2)*(x2-x1)/(y2-y1)); y2=vp.top;}
	    break;
	  }
	}

	// we broke out of the loop, here's the return value
	// we are assuming that endpoints don't really matter for "external"
	LineSegment ls = new LineSegment();
	if (swapped) ls.setEndPoints(x2,y2,x1,y1); // put them back in orig. order
	else ls.setEndPoints(x1,y1,x2,y2);
	ls.setClipType(result);
	return ls;
    }

    /*
      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;
	if (y>top) result+=8;
	if (y<bottom) result+=4;
	if (x>right) result+=2;
	if (x<left) result++;
	return result;
    }	
}





