import java.awt.*;
import java.util.*;
import java.lang.Math;

public class ParamSurface //superclass
{
	public double x(double u, double v){return 0;}	
	public double y(double u, double v){return 0;}	
	public double z(double u, double v){return 0;}
	
	public double[][][] getShape(){return null;}
	public void setShape(double Matrix[][][]){}
	public double[] getCenter(){return null;}
	public void setCenter(double Array[]){}	
	public double getRadius(){return 0;}

	final int COORD_X = 0;
	final int COORD_Y = 1;
	final int COORD_Z = 2;	

	final int LINES_OFF = 0;
	final int LINES_ON = 1;
	final int LINES_MESH = 2;
	
	static final int ROTATE_X = 0;
	static final int ROTATE_Y = 1;
	static final int ROTATE_Z = 2;

	double focus = 400;
	int iWidth, iHeight;
	
	double dEpsilon;
	int iEpsInv;
	boolean bToggle = true;
	
	static Matrix3D Matrix3D = new Matrix3D();
	
	public ParamSurface()
	{

	}

	public void draw(Graphics g, double dEpsilon, Color clr, int iLines)
		//will draw the entire parametric surface
		//keep a counter starting at 0, whenever drawquad is called, increment
		
		//this will not loop through u and v, this will go through the sphere
		//matrix and 
	{	
		iEpsInv = (int)(1/dEpsilon);
		
		double vector1[], vector2[], vector3[], vector4[];
		
		for (int i=0; i<iEpsInv+1; i++)
		{
			for (int j=0; j<iEpsInv; j++)
			{
				vector1	= getShape()[i][j];
				vector2	= getShape()[i+1][j];
				vector3 = getShape()[i+1][(j+1)%iEpsInv];
				vector4	= getShape()[i][(j+1)%iEpsInv];
				
		 		drawQuad(vector1, vector2, vector3, vector4, g, clr, dEpsilon, iLines);
		 	}
		}
	}
	
	public void drawQuad(double[] Point1, double[] Point2, double[] Point3,
			double[] Point4, Graphics g, Color clr, double dEpsilon, int iLines)
		//change this so it takes in four vectors instead of this hippy BS =D
		//points are vectors with [X][Y][Z][1]
	{
		int CoordX[] = {(int)Point1[0], (int)Point2[0], (int)Point3[0], (int)Point4[0]};
		int CoordY[] = {(int)Point1[1], (int)Point2[1], (int)Point3[1], (int)Point4[1]};
		int CoordZ[] = {(int)Point1[2], (int)Point2[2], (int)Point3[2], (int)Point4[2]};
		
		for (int i=0; i<4; i++)
		{
			CoordX[i] = (int)ViewPort(Perspective(CoordX[i], CoordZ[i]), COORD_X);
			CoordY[i] = (int)ViewPort(Perspective(CoordY[i], CoordZ[i]), COORD_Y);
		}

		g.setColor(clr);
		switch (iLines)
		{
			case LINES_OFF:
			{
				g.fillPolygon(CoordX, CoordY, 4);
				break;
			}							
			case LINES_ON:
			{
				g.fillPolygon(CoordX, CoordY, 4);
				g.setColor(Color.white);
				g.drawPolygon(CoordX, CoordY, 4);
				break;
			}
			case LINES_MESH:
			{
				g.drawPolygon(CoordX, CoordY, 4);
				break;
			}
		}
	}
	
	public double ViewPort(double Coord, int column)
		//this will copy an array passed in, in this case it will be an array of
		//X or Y coordinates
	{
		double TempCoord = Coord;
		if (column == COORD_X)
			TempCoord += iWidth/2;
		else if (column == COORD_Y)
			TempCoord += iHeight/2;

		return TempCoord;
	}
	
	public double Perspective(double Coord, double z)
	{
		Coord = (focus * Coord)/(focus - z);
		return Coord;
	}
	
	public static void Translate(double Matrix[][], double a, double b, double c)
	{
		Matrix3D.Translate(Matrix, a, b, c);
	}
	
	public static void Rotate(double Matrix[][], double theta, int DirRotate)
	{
		if (DirRotate == ROTATE_X)
			Matrix3D.RotateX(Matrix, theta);
		if (DirRotate == ROTATE_Y)
			Matrix3D.RotateY(Matrix, theta);
		if (DirRotate == ROTATE_Z)
			Matrix3D.RotateZ(Matrix, theta);
	}
	
	public static void Scale(double Matrix[][], double a, double b, double c)
	{
		Matrix3D.Scale(Matrix, a, b, c);
	}

	public static void Multiply(double MatrixA[][], double MatrixB[][])
	{
		Matrix3D.MultiplyMatrix(MatrixA, MatrixB);
	}
	
	public void Transform(double Matrix[][], double MatrixShape[][][])
	{
		double Center[] = getCenter();
		
		for (int i=0; i<iEpsInv+1; i++)
			for (int j=0; j<iEpsInv; j++)
				Matrix3D.Transform(Matrix, MatrixShape[i][j]);
				
		setShape(MatrixShape);
		
		Matrix3D.Transform(Matrix, Center);
		setCenter(Center);
	}
	
	public void setBounds(int iHeight, int iWidth, double dEpsilon)
	{
		this.iHeight = iHeight;
		this.iWidth = iWidth;
		this.dEpsilon = dEpsilon;
		iEpsInv = (int)(1/dEpsilon);
	}
}