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.
    */

    public static LineSegment ClipSegment(double x1, double y1, 
				       double x2, double y2, 
				       Viewport vp) {

	//for debugging:
	System.out.println("Entering Cohen-Sutherland");

	double m = (y2 - y1) / (x2 - x1);
	double ytemp, xtemp;


	LineSegment ls = new LineSegment();
	
	// this is the default; we don't want it to draw anything if it's 
	// external

     	ls.x1 = 0.0;
	ls.y1 = 0.0;
	ls.x2 = 0.0;
	ls.y2 = 0.0;
	ls.setClipType("external");
	


	// get the outcodes for the endpoints
	int endpoint1 = outcode(x1, y1, vp.top, vp.bottom, vp.left, vp.right);
	int endpoint2 = outcode(x2, y2, vp.top, vp.bottom, vp.left, vp.right);
	
	// trivial case: if both points inside clipbox, return internal
	if ((endpoint1 + endpoint2) == 0){
	    ls.x1 = x1;
	    ls.x2 = x2;
	    ls.y1 = y1;
	    ls.y2 = y2;
	    ls.setClipType("internal");
	}
	
	// this recursively calls ClipSegment to clip (in order)
	// LEFT, RIGHT, BOTTOM, TOP
	// until all that remains is internal or external by our
	// previous tests
	else if ((endpoint1 & endpoint2) == 0){ //non-trivial case
	   if(((endpoint1 | endpoint2) & LEFT) != 0)
	       {
		   int blah = endpoint1 & LEFT;
		   System.out.println("blah " + blah);
		   if((endpoint1 & LEFT) != 0){ // (x1, y1 to left of clipbox)
		       ytemp = y1 + m * (vp.left - x1);
		       xtemp = vp.left;
		       ls = ClipSegment(xtemp, ytemp, x2, y2, vp);       
		   }
		   else {
		       ytemp = y2 + m * (vp.left - x2);
		       xtemp = vp.left;
		       ls = ClipSegment(x1, y1, xtemp, ytemp, vp);  
		   }
	       }
	     else{
	       if(((endpoint1 | endpoint2) & RIGHT) != 0){
		   if((endpoint1 & RIGHT) != 0){ // (x1, y1 to right 
		                                 // of clipbox)
		       ytemp = y1 + m * (vp.right - x1);
		       xtemp = vp.right;
		       ls = ClipSegment(xtemp, ytemp, x2, y2, vp);       
		   }
		   else {
		       ytemp = y2 + m * (vp.right - x2);
		       xtemp = vp.right;
		       ls = ClipSegment(x1, y1, xtemp, ytemp, vp);  
		   }
	       }

	       else{
		   if(((endpoint1 | endpoint2) & BOTTOM) != 0){
		       if((endpoint1 & BOTTOM) != 0){ // (x1, y1 to bottom 
		                                 // of clipbox)
		       ytemp = vp.bottom;
		       xtemp = (ytemp - y1) / m + x1;
		       ls = ClipSegment(xtemp, ytemp, x2, y2, vp);       
		   }
		   else {
		       ytemp = vp.bottom;
		       xtemp = (ytemp - y2) / m + x2;
		       ls = ClipSegment(x1, y1, xtemp, ytemp, vp);  
		   }
		   }
		   else{
		       if((endpoint1 & TOP) != 0){ // (x1, y1 to top 
		                                 // of clipbox)
		       ytemp = vp.top;
		       xtemp = (ytemp - y1) / m + x1;
		       ls = ClipSegment(xtemp, ytemp, x2, y2, vp);       
		   }
		   else {
		       ytemp = vp.top;
		       xtemp = (ytemp - y2) / m + x2;
		       ls = ClipSegment(x1, y1, xtemp, ytemp, vp);  
		   }
		   }}}

	   if(ls.clipType.equals("internal"))  // if the recursive call is 
	       {ls.setClipType("clipped");} // made and "internal" is returned
	                                    // that means that it's internal
	                                    // AFTER clipping, so change it
	                                    // to clipped 
	}

	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) {

	
	// adds the appropriate ints (TBRL) to create the proper 4-bit code
	int result = 0;
	if(y > top) {result += TOP;}
	if(y < bottom) {result += BOTTOM;}
	if(x < left) {result += LEFT;}
	if(x > right) {result += RIGHT;}
	

	return result;
    }	
}





