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 int GenerateOutcode(double x, double y, Viewport vp) {
        
        int     outcode = 0;
                
        if (y > vp.top) {
            outcode |= TOP;
        }
        else if (y < vp.bottom) {
            outcode |= BOTTOM;
        }
        if (x > vp.right) {
            outcode |= RIGHT;
        }
        else if (x < vp.left) {
            outcode |= LEFT;
        }
        
        return outcode;
    }
    
    public static boolean CheckOutcodes(LineSegment ls, Viewport vp) {
        
        if (GenerateOutcode(ls.x1, ls.y1, vp) == 0 && GenerateOutcode(ls.x2, ls.y2, vp) == 0) {
            ls.setClipType("clipped");
            return true;
        }
        return false;
    }

    
    // I changed these from x1 to inx1 so they won't be confused with member variables
    // of LineSegment.
    
    public static LineSegment ClipSegment(double inx1, double iny1, 
				       double inx2, double iny2, 
				       Viewport vp) {

	// ******* YOUR CODE HERE *********
	
	
	
	LineSegment ls = new LineSegment();    
    ls.setEndPoints(inx1, iny1, inx2, iny2);	
    	
	// From now on, I'm only operating on member variables of ls.  
	
	int     pt1_Outcode = GenerateOutcode(ls.x1, ls.y1, vp);
	int     pt2_Outcode = GenerateOutcode(ls.x2, ls.y2, vp);
		    
    if ((pt1_Outcode == 0) && (pt2_Outcode == 0)) {     // both endpoints internal -- simple
        ls.setClipType("internal");       
    }
    else if ( (pt1_Outcode & pt2_Outcode) != 0) {     
        ls.setClipType("external");
        ls.setEndPoints(0, 0, 0, 0);
    }
    else {      // Clipped.  We need to clip each line, and recheck if trivially in or out.
                // These four chunks of code are similar, but different.
    
        // clip left
        if (ls.x1 < vp.left) {
              ls.y1 = (ls.y2 - ls.y1) * (vp.left - ls.x2) / (ls.x2 - ls.x1) + ls.y2;
              ls.x1 = vp.left;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
        }                             
        if (ls.x2 < vp.left) {
              ls.y2 = (ls.y2 - ls.y1) * (vp.left - ls.x2) / (ls.x2 - ls.x1) + ls.y2;
              ls.x2 = vp.left;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
        }                                     
        if (CheckOutcodes(ls, vp)) {
            return ls;
        }
               
        // clip right
        if (ls.x1 > vp.right) { 
              ls.y1 = (ls.y2 - ls.y1) * (vp.right - ls.x2) / (ls.x2 - ls.x1) + ls.y2;
              ls.x1 = vp.right;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
        }                             
        if (ls.x2 > vp.right) {
              ls.y2 = (ls.y2 - ls.y1) * (vp.right - ls.x2) / (ls.x2 - ls.x1) + ls.y2;
              ls.x2 = vp.right;                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  
        }                             
        if (CheckOutcodes(ls, vp)) {
            return ls;
        }
                
        // clip bottom
        if (ls.y1 < vp.bottom) {
            ls.x1 = (ls.x2 - ls.x1) * (vp.bottom - ls.y2) / (ls.y2 - ls.y1) + ls.x2;
            ls.y1 = vp.bottom;
        }
        if (ls.y2 < vp.bottom) {
            ls.x2 = (ls.x2 - ls.x1) * (vp.bottom - ls.y2) / (ls.y2 - ls.y1) + ls.x2;
            ls.y2 = vp.bottom;
        }
        if (CheckOutcodes(ls, vp)) {
            return ls;
        }
        
        // clip top
        if (ls.y1 > vp.top) {
            ls.x1 = (ls.x2 - ls.x1) * (vp.top - ls.y2) / (ls.y2 - ls.y1) + ls.x2;
            ls.y1 = vp.top;
        }
        if (ls.y2 > vp.top) {
            ls.x2 = (ls.x2 - ls.x1) * (vp.top - ls.y2) / (ls.y2 - ls.y1) + ls.x2;
            ls.y2 = vp.top;
        }
        if (CheckOutcodes(ls, vp)) {
            return ls;
        }
                    
        // if we've made it this far, then we really are external                    
        ls.setClipType("external");   
        ls.setEndPoints(0, 0, 0, 0);
    }
    return ls;      // Should never get here, but compiler complains if there's no return statement    
    }
}




