//Ajay Kulkarni  - 6.837 pset 2b
//9.23.99

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

	// ******* YOUR CODE HERE *********

	double vtop, vbottom, vleft, vright;
	int bitcode1, bitcode2, bit_and, bit_or; 
	double cx1 = 0, cx2 = 0, cy1 = 0, cy2 = 0;
	int cltype = 0, done = 0, isBorder = 0, isClip = 0;
	double oldx1 = 0, oldx2 = 0, oldy1 = 0, oldy2 = 0;
	double m;
	
	m = (y2 - y1) / (x2 - x1);

	vtop = vp.top;
	vbottom = vp.bottom;
	vleft = vp.left;
	vright = vp.right;

	//Loop through until line segment is properly clipped,
	//or until it is determined that line segment is external

	while (done == 0) {
	    //outcodes of two endpoints
	    bitcode1 = outcode(x1, y1, vtop, vbottom, vleft, vright);
	    bitcode2 = outcode(x2, y2, vtop, vbottom, vleft, vright);
	    
	    bit_and = bitcode1 & bitcode2;
	    bit_or = bitcode1 | bitcode2;
	    
	    	    
	    //REJECT immediately
	    if (bit_and != 0) {
		cltype = 2;
		done = 1;
	    }

	    //ACCEPT immediately
	    else if (bit_or == 0) {
		cltype = 0;
		cx1 = x1;
		cx2 = x2;
		cy1 = y1;
		cy2 = y2;
		done = 1;
	    }

	    //External, but not obvious
	    else if ((x2 == oldx1) && (x1 == oldx2) && (y1 == oldy2) && (y2 == oldy1)) { 
		//i.e., if clipping becomes just swapping between same two points
		done = 1;
		cltype = 2;
		isClip = 0;
	    }

	    //Other cases... i.e., clipping to determine which one of above
	    //cases apply
	    else { 
		done = 0;
		isClip = 1;
		oldx1 = x1;
		oldx2 = x2;
		oldy1 = y1;
		oldy2 = y2;

		if ((bitcode1 & 1) != 0) {
		    x1 = vleft;
		    y1 = y2 + m*(x1-x2);
		}
		if ((bitcode1 & 2) != 0) {
		    x1 = vright; 
		    y1 = y2 + m*(x1-x2);
		}
		if ((bitcode1 & 4) != 0) {
		    y1 = vtop;
		    x1 = x2 + (y1-y2)/m;
		}
		if ((bitcode1 & 8) != 0) {
		    y1 = vbottom;
		    x1 = x2 + (y1-y2)/m;
		}
		if ((bitcode2 & 1) != 0) {
		    x2 = vleft;
		y2 = y1 + m*(x2-x1);
		}
		if ((bitcode2 & 2) != 0) {
		x2 = vright;
		y2 = y1 + m*(x2-x1);
		}
		if ((bitcode2 & 4) != 0) {
		    y2 = vtop;
		    x2 = x1 + (y2-y1)/m;
		}
		if ((bitcode2 & 8) != 0) {
		    y2 = vbottom;
		    x2 = x1 + (y2-y1)/m;
		}
	    }
	}
    
	//if went through clipping loop, and is not external, then want
	//to say "Clipped"
	if (isClip == 1) {
	    cltype = 1;
	}
	
	//for debugging:
	System.out.println("Entering Cohen-Sutherland");

	LineSegment ls = new LineSegment();
	ls.x1 = cx1;
	ls.y1 = cy1;
	ls.x2 = cx2;
	ls.y2 = cy2;

	switch (cltype) {
	case 0: 
	    ls.setClipType("internal");
	    break;
	case 1:
	    ls.setClipType("clipped");
	    break;
	case 2:
	    ls.setClipType("external");
	    break;
	}

	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 (x < left) {
	    result = result + LEFT;     //LEFT = 1
	}
	if (x > right){ 
	    result = result + RIGHT;    //RIGHT = 2
	}
	if (y > top) {
	    result = result + TOP;      //TOP = 4
	}
	if (y < bottom) {
	    result = result + BOTTOM;   //BOTTOM = 8
	}
	return result;
    }
}






