import java.lang.*;

import Drawable;
import Vertex2D;

class Triangle implements Drawable
{
	protected Vertex2D v[];
	protected int color;
	public Triangle()
	{
	}

	public Triangle(Vertex2D v0, Vertex2D v1, Vertex2D v2)
	{
		v = new Vertex2D[3];
		v[0] = v0;
		v[1] = v1;
		v[2] = v2;
		
		/*
		This is an elementary version of Triangle--we tackle continuous colors
		in GradTriangle.java 
        ... I will assign the triangle the average of it's vertex colors ...
        */
        int a = ((v0.argb >> 24) & 255) + ((v1.argb >> 24) & 255) + ((v2.argb >> 24) & 255);
        int r = ((v0.argb >> 16) & 255) + ((v1.argb >> 16) & 255) + ((v2.argb >> 16) & 255);
        int g = ((v0.argb >> 8) & 255) + ((v1.argb >> 8) & 255) + ((v2.argb >> 8) & 255);
        int b = (v0.argb & 255) + (v1.argb & 255) + (v2.argb & 255);
           
        a = (a + a + 3) / 6;	//how is this the average?
        r = (r + r + 3) / 6;
        g = (g + g + 3) / 6;
        b = (b + b + 3) / 6;
           
        color = (a << 24) | (r << 16) | (g << 8) | b;
	}
		
	public void Draw(Raster raster)
	{
		int v0c, v1c, v2c;
		float v0x, v1x, v2x, v0y, v1y, v2y;
		int v0a, v1a, v2a, v0r, v1r, v2r, v0g, v1g, v2g, v0b, v1b, v2b;
		float b, h, a;
		float Aa, Ba, Ca;	//alpha coefficients
		float Ar, Br, Cr;	//redness coefficients
		float Ag, Bg, Cg;	//greenness coefficients
		float Ab, Bb, Cb;	//blueness coefficients
		
		v0c = Triangle.v[0].argb;	//assigning vertex colors
		v1c = Triangle.v[1].argb;
		v2c = Triangle.v[2].argb;
		
		//what follows is the assignments of colors to more specific variables 
		
		v0a = (v0c & 0xff000000) >> 24;
		v1a = (v1c & 0xff000000) >> 24;
		v2a = (v2c & 0xff000000) >> 24;
		v0r = (v0c & 0xff0000) >> 16;
		v1r = (v1c & 0xff0000) >> 16;
		v2r = (v2c & 0xff0000) >> 16;
		v0g = (v0c & 0xff00) >> 8;
		v1g = (v1c & 0xff00) >> 8;
		v2g = (v2c & 0xff00) >> 8;
		v0b = v0c & 0xff;
		v1b = v1c & 0xff;
		v2b = v2c & 0xff;
		
		//below are assignments of x and y coordinates of the vertices
		
		v0x = Triangle.v[0].x;
		v1x = Triangle.v[1].x;
		v2x = Triangle.v[2].x;
		v0y = Triangle.v[0].y;
		v1y = Triangle.v[1].y;
		v2y = Triangle.v[2].y;
		
		//these are arrays that are used to help sort the vertices 
		
		float Mins[] = new float[2];
		float Mids[] = new float[2];
		float Maxs[] = new float[2];
		
		//all scenarios have the following variables
		
		float yStartPt = Maxs[1];	//where we begin at the top
		float xStartPt;
		float yEndPt = Mins[1]; 	//where we end at the bottom
		float xEndPt; 
		
		///////////////////////////////////////////////
		//if the y-coords of two vertices equal the max y-coord... 
		
		/*
		this is the case:
		-------------
		\           /
		 \         /
		  \       /
		   \     /
 		    \   /
 		     \ /
 		      |
 		*/
		
		
		if (((yStartPt == v0y) && (yStartPt == v1y)) ||
		    ((yStartPt == v0y) && (yStartPt == v2y)) ||
		    ((yStartPt == v1y) && (yStartPt == v2y)))
		{
			float yStartPt2 = Maxs[1];	//here are more variables to keep
			float xStartPt2;			//track of the other top vertex
			
			if (v0y == yStartPt)		//assigning x-coords...
			{
				xStartPt = v0x;
				if (v1y == yStartPt)
				{
					xStartPt2 = v1x;
				}
				else
				{
					xStartPt2 = v2x;
				}
			}		
			else
			{
				xStartPt = v1x;
				xStartPt2 = v2x;
			}
			if (xStartPt > xStartPt2)	//make sure that xStartPt is to the
			{							//left of xStartPt2
				float temp;
				temp = xStartPt2;
				xStartPt2 = xStartPt;
				xStartPt = temp;
			}
			if (yEndPt == v0y)			//assign more x-coords
			{
				xEndPt = v0x;
			}
			else
			{
				if (yEndPt == v1y)
				{
					xEndPt = v1x;
				}
				else
				{
					xEndPt = v2x;
				}
			}
			//slope from bottom to left top
			float m = (yStartPt - yEndPt)/(xStartPt - xEndPt);
			//slope from bottom to right top	 
			float n = (yStartPt2 - yEndPt)/(xStartPt2 - xEndPt);
			
			//the amounts we should subtract from our x-coords every time we increase
			//y by 1
			float dxm = 1/m;
			float dxn = 1/n;
			
			//go from top to bottom -- SuperCede refused to let me use ceil and floor
			//so I settled for my own close (but not perfect) approximations of them	
			for (int j = (int)(yStartPt + .5); j <= (int)(yEndPt - .5); j++)
			{
				//each time we increase y by 1, we change x accordingly
				xStartPt -= dxm;
				xStartPt2 -= dxn;

				//go from left to right incrementally
				//with each following row, xStartPt and xStartPt2 become closer
				for(int i = (int)(xStartPt + .5); i <= (int)(xStartPt2 - .5); i++)
				{
					//draw a pixel 
					raster.setPixel(color, i, j);
				}
			}
		}
		/////////////////////////////////////////////////
		//if the y-coords of 2 vertices are equal to the min y-coord...
		/*
		of this form:
		
		        /\
			   /__\	
				
		*/
		 
		if (((yEndPt == v0y) && (yEndPt == v1y)) ||
		    ((yEndPt == v0y) && (yEndPt == v2y)) ||
		    ((yEndPt == v1y) && (yEndPt == v2y)))
		{	
			float xStartPt2;
			float xEndPt2;
			float yEndPt2 = yEndPt;
			
			if (v0y == yEndPt)
			{
				xEndPt = v0x;
				if (v1y == yEndPt)
				{
					xEndPt2 = v1x;
				}
				else
				{
					xEndPt2 = v2x;
				}
			}		
			else
			{
				xEndPt = v1x;
				xEndPt2 = v2x;
			}
							
			if (xEndPt > xEndPt2)
			{
				float temp;
				temp = xEndPt2;
				xEndPt2 = xEndPt;
				xEndPt = temp;
			}
			if (v0y > v1y)
			{
				yStartPt = v0y;
				xStartPt2 = xStartPt = v0x;
			}
			else
			{
				if (v1y > v2y)
				{
					yStartPt = v1y;
					xStartPt2 = xStartPt = v1x;
				}
				else
				{
					yStartPt = v2y;
					xStartPt2 = xStartPt = v2x;
				}
			}
			//slope from left bottom to top
			float m = (yStartPt - yEndPt)/(xStartPt - xEndPt);
			//slope from right bottom to top
			float n = (yStartPt - yEndPt2)/(xStartPt - xEndPt2);
			
			float dxm = 1/m;
			float dxn = 1/n;
						
			for (int j = (int)(yStartPt + .5); j <= (int)(yEndPt - .5); j--)
			{
				xStartPt -= dxm;
				xStartPt2 -= dxn;
				
				//on the first iteration, xStartPt = xStartPt2, afterwards, 
				//they grow farther apart 
				for(int i = (int)(xStartPt + .5); i <= (int)(xStartPt2 - .5); i++)
				{
					raster.setPixel(color, i, j);
				}
			}

		}
	//////////////////////////////////////////////////////////
		//if all y's are distinct...	
		if (!(v0y == v1y || v1y == v2y || v2y == v0y))
		{
			float yBreakPt = Mids[1];	//yBreakPt is the middle y-coord
			float xBreakPt;
			float xStartPt2;
			boolean toLeft;				//if the bp is to the left, this is true
			if (yStartPt == v0y)
			{
				xStartPt2 = xStartPt = v0x;
			}
			if (yStartPt == v1y)
			{
				xStartPt2 = xStartPt = v1x;
			}
			else
			{
				xStartPt2 = xStartPt = v2x;
			}		

			if (v0y == yBreakPt)
			{
				xBreakPt = v0x;
			}
			if (v1y == yBreakPt)
			{
				xBreakPt = v1x;
			}
			else
			{
				xBreakPt = v2x;
			}
			if (yEndPt == v0y)
			{
				xEndPt = v0x;
			}
			if (yEndPt == v1y)
			{
				xEndPt = v1x;
			}
			else
			{
				xEndPt = v2x;
			}
			//slope from the bottom to the top...			
			float m = (yStartPt - yEndPt)/(xStartPt - xEndPt);
			//slope from the bottom to the breakpoint...
			float n = (yBreakPt - yEndPt)/(xBreakPt - xEndPt);
	
			//if the slope from bottom to top is less than the slope from the bottom
			//to breakpoint, then the breakpoint is a left one
			if (m < n)
			{
				toLeft = true;
			}
			else 
			{
				toLeft = false;
			}
			
			float dxm = 1/m;
			float dxn = 1/n;
			
			//the code that follows is a little tricky
			//depending on which side the breakpoint is on, we fill in pixels
			//from top to bottom, following the top two edges until we hit the 
			//breakpoint at which point we switch the appropriate edge out and 
			//put the new low one in
			if (toLeft)
			{
				//slope from breakpoint to top
				float o = (yStartPt - yBreakPt)/(xStartPt - xBreakPt);
				float dxo = 1/o;
			 
				for (int j = (int)(yStartPt + .5); j > (int)(yBreakPt - .5); j--)
				{
					xStartPt -= dxo;
					xStartPt2 -= dxm;

					for(int i = (int)(xStartPt + .5); i <= (int)(xStartPt2 - .5); i++)
					{
						raster.setPixel(color, i, j);
					}
				}
				for (int j = (int)(yBreakPt + .5); j >= (int)(yEndPt - .5); j--)
				{
					xStartPt -= dxn;
					xStartPt2 -= dxm;

					for(int i = (int)(xStartPt + .5); i <= (int)(xStartPt2 -.5); i++)
					{
						raster.setPixel(color, i, j);
					}
				}
			}
			else
			{
				float o = (yStartPt - yBreakPt)/(xStartPt - xBreakPt);
				float dxo = 1/o;
			 
				for (int j = (int)(yStartPt + .5); j > (int)(yBreakPt - .5); j--)
				{
					xStartPt -= dxm;
					xStartPt2 -= dxo;

					for(int i = (int)(xStartPt + .5); i <= (int)(xStartPt2 - .5); i++)
					{
						raster.setPixel(color, i, j);
					}
				}
				for (int j = (int)(yBreakPt + .5); j >= (int)(yEndPt - .5); j--)
				{
					xStartPt -= dxm;
					xStartPt2 -= dxn;

					for(int i = (int)(xStartPt + .5); i <= (int)(xStartPt2 - .5); i++)
					{
						raster.setPixel(color, i, j);
					}
				}
			}
		}
	}
				
	public float span(float i1, float i2, float i3, float min[], float mid[], float max[], int par)
	{
		if (i1 < i2)
		{
			if (i1 < i3)
			{
				min[par] = i1;
				if (i2 < i3)
				{
					mid[par] = i2;
					max[par] = i3;
					return(i3-i1);
				}
				else
				{
					mid[par] = i3;
					max[par] = i2;
					return(i2-i1);
				}
			}
			else
			{
				min[par] = i3;
				mid[par] = i1;
				max[par] = i2;
				return(i2-i3);
			}
		}
		else
		{
			if (i2 < i3)
			{
				min[par] = i2;
				if (i1 < i3)
				{
					mid[par] = i1;
					max[par] = i3;
					return(i3-i2);
				}
				else
				{
					mid[par] = i3;
					max[par] = i1;
					return(i1-i2);
				}
			}
			else
			{
				min[par] = i3;
				mid[par] = i2;
				max[par] = i1;
				return(i1-i3);
			}
		}	
	}
}
