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 *********
        int         id1, id2;
	double      b, m, b1, m1;
	boolean     bcomputed, b1computed;
	LineSegment ls = new LineSegment();
    
	//for debugging:
	System.out.println("Entering Cohen-Sutherland");

	bcomputed = b1computed = false;
	id1 = outcode (x1, y1, vp.top, vp.bottom, vp.left, vp.right);
        id2 = outcode (x2, y2, vp.top, vp.bottom, vp.left, vp.right);

	ls.x1 = x1; ls.y1 = y1;
	ls.x2 = x2; ls.y2 = y2;

	if (id1 == 0 && id2 == 0) 
	    { ls.setClipType ("internal"); return ls; }
        if ((((id1 & TOP) > 0) && ((id2 & TOP) > 0)) ||
	      (((id1 & BOTTOM) > 0) && ((id2 & BOTTOM) > 0)) ||
	      (((id1 & LEFT) > 0) && ((id2 & LEFT) > 0)) ||
	      (((id1 & RIGHT) > 0) && ((id2 & RIGHT) > 0)))
	    { ls.setClipType ("external"); return ls; }

	m = m1 = b = b1 = 0.0;

	if ((id1 & (LEFT | RIGHT)) > 0)
	    {
		b = (ls.y2 - ls.y1) / (ls.x2 - ls.x1);
		m = ls.y1 - ls.x1 * b;
		bcomputed = true;

		if ((id1 & LEFT) > 0) 
		    {
			ls.x1 = vp.left;
			ls.y1 = b * vp.left + m;
			id1 ^= LEFT;
		    }
		 else
		    {
			ls.x1 = vp.right;
			ls.y1 = b * vp.right + m;
			id1 ^= RIGHT;
		    }
		if ((id1 & TOP) > 0) id1 ^= TOP;
		   else if ((id1 & BOTTOM) > 0) id1 ^= BOTTOM;
		if (ls.y1 >= vp.top) 
		        {
			    id1 |= TOP; 
			    if ((id2 & TOP) > 0) { ls.setClipType ("external"); return ls; }
			}
			else if (ls.y1 <= vp.bottom) 
			    {
				id1 |= BOTTOM;
				if ((id2 & BOTTOM) > 0) { ls.setClipType ("external"); return ls; }
			    }
		  else if (id1 == 0 && id2 == 0)
		      { ls.setClipType ("clipped"); return ls; }
	    }
	if ((id1 & (TOP | BOTTOM)) > 0)
	    {
		b1 = (ls.x2 - ls.x1) / (ls.y2 - ls.y1);
		m1 = ls.x1 - ls.y1 * b1;
		b1computed = true;

		if ((id1 & TOP) > 0) 
		    {
			ls.y1 = vp.top;
			ls.x1 = b1 * vp.top + m1;
			id1 ^= TOP;
		    }
		 else
		    {
			ls.y1 = vp.bottom;
			ls.x1 = b1 * vp.bottom + m1;
			id1 ^= BOTTOM;
		    }
		if ((id1 & LEFT) > 0) id1 ^= LEFT;
		   else if ((id1 & RIGHT) > 0) id1 ^= RIGHT;
		if (ls.x1 <= vp.left) 
		        {
			    id1 |= LEFT; 
			    if ((id2 & LEFT) > 0) { ls.setClipType ("external"); return ls; }
			}
			else if (ls.x1 >= vp.right) 
			    {
				id1 |= RIGHT;
				if ((id2 & RIGHT) > 0) { ls.setClipType ("external"); return ls; }
			    }
		  else if (id1 == 0 && id2 == 0)
		      { ls.setClipType ("clipped"); return ls; }
	    }
           if ((id2 & (LEFT | RIGHT)) > 0)
	    {
		if (!bcomputed)
		    {
			b = (ls.y2 - ls.y1) / (ls.x2 - ls.x1);
			m = ls.y1 - ls.x1 * b;
		    }

		if ((id2 & LEFT) > 0) 
		    {
			ls.x2 = vp.left;
			ls.y2 = b * vp.left + m;
			id2 ^= LEFT;
		    }
		 else
		    {
			ls.x2 = vp.right;
			ls.y2 = b * vp.right + m;
			id2 ^= RIGHT;
		    }
		if ((id2 & TOP) > 0) id2 ^= TOP;
		   else if ((id2 & BOTTOM) > 0) id2 ^= BOTTOM;
		if (ls.y2 >= vp.top) id2 |= TOP;
		   else if (ls.y2 <= vp.bottom) id2 |= BOTTOM;
                      else if (id2 == 0)
		         { ls.setClipType ("clipped"); return ls; }
	    }

           if ((id2 & (TOP | BOTTOM)) > 0)
	    {
		if (!b1computed)
		    {
			b1 = (ls.x2 - ls.x1) / (ls.y2 - ls.y1);
			m1 = ls.x1 - ls.y1 * b1;
		    }

		if ((id2 & TOP) > 0) 
		    {
			ls.y2 = vp.top;
			ls.x2 = b1 * vp.top + m1;
		    }
		 else
		    {
			ls.y2 = vp.bottom;
			ls.x2 = b1 * vp.bottom + m1;
		    }
		ls.setClipType ("clipped"); return ls;
	    }
	      	
	ls.x1 = 0.0;
	ls.y1 = 0.0;
	ls.x2 = 0.0;
	ls.y2 = 0.0;
	ls.setClipType("external");
	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 |= TOP;
	  else if (y <= bottom) result |= BOTTOM;
	if (x <= left) result |= LEFT;
	  else if (x >= right) result |= RIGHT;

	return result;
    }	
}





