/************************
 * 6.837 Assignment 2
 * Part B - CohenSutherland.java
 * Lawrence C. Wang
 ************************/

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=0;
	double[] bounds = {vp.left, vp.right, vp.bottom, vp.top};
	PointDouble[] p = {new PointDouble(x1,y1), new PointDouble(x2,y2)};
	String[] code = new String[2];
	LineSegment ls = new LineSegment();

	 System.out.println("(x1,y1) = (" + p[0].x() + "," + p[0].y() + ")");
	 System.out.println("(x2,y2) = (" + p[1].x() + "," + p[1].y() + ")");
	
	for (int edge=0; edge<4; edge++)
	    {
		code[0] = outcodeString(p[0].x(), p[0].y(), vp.top, vp.bottom, vp.left, vp.right);
		code[1] = outcodeString(p[1].x(), p[1].y(), vp.top, vp.bottom, vp.left, vp.right);

		 System.out.println("code1 = " + code[0]);
		 System.out.println("code2 = " + code[1]);
		 System.out.println("Clipping edge " + edge + ":");

		ls.setClipType("clipped");
		
		if (trivialAccept(code[0], code[1]))
		    {
			if (edge == 0) 
			    ls.setClipType("internal");
			break;
		    }
		else if (trivialReject(code[0], code[1]))
		    {
			ls.setClipType("external");
			break;
		    }
		else
		    {
			if (p[0].x() != p[1].x()) 
			    m = (p[1].y() - p[0].y()) / (p[1].x() - p[0].x());
			for (int i=0; i<2; i++)
			    {
				if (code[i].charAt(3-edge)=='1')
				    {
					if (edge<2)
					    {
						p[i].sety( p[i].y() + (bounds[edge]-p[i].x())*m );
						p[i].setx( bounds[edge] );
					    }
					else
					    {
						if (p[0].x()!=p[1].x()) 
						    p[i].setx( p[i].x() + (bounds[edge]-p[i].y())/m );
						p[i].sety( bounds[edge] );
					    }
					 System.out.println("(x" + i + ",y" + i + ")->(" + p[i].x() + "," + p[i].y() + ")");
				    }
			    }
		    }
	    }
	
	
	ls.x1 = p[0].x();
	ls.y1 = p[0].y();
	ls.x2 = p[1].x();
	ls.y2 = p[1].y();
	
	return ls;
    }




    // This method tests whether the two points with the given clip codes
    // should be trivially accepted.
    public static boolean trivialAccept(String oc1, String oc2)
    {
	if (oc1.equals("0000") && oc2.equals("0000"))
	    return true;
	return false;
    }

    // This method tests whether the two points with the given clip codes
    // should be trivially rejected.
    public static boolean trivialReject(String oc1, String oc2)
    {
	for (int i=0; i<4; i++)
	    {
		if ((oc1.charAt(i)=='1') && (oc2.charAt(i)=='1'))
		    return true;
	    }
	return false;
    }


    /*
      This method, given a point (x,y) and some clip region
      boundaries, should produce the binary clip codes for the
      Cohen-Sutherland algorithm in string format, ie, "0101".
    */
    public static String outcodeString(double x, double y,
				 double top, double bottom, 
				 double left, double right) {
	String result = String.valueOf(outcode(x,y,top,bottom,left,right));
	while (result.length() < 4) 
	    result = "0" + result;
	return result;
    }

    public static int outcode(double x, double y,
			      double top, double bottom, 
			      double left, double right) {

	int result = 0;
	
	if (y >= top) result += 1000;
	else if (y <= bottom) result += 100;
	if (x >= right) result += 10;
	else if (x <= left) result += 1;

	return result;
    }	
}





