package coords;

public class Path {
	private Coords[] firstpoints = new Coords[2];//This is the one variable to hold the original path points...
	public Coords[] path;//This variable holds all points that are to be followed to.
	private double backgroundlayer = 0.0;
	private double defaultlayer = backgroundlayer + 1.0;
	private double h = 1.0;

	public Path(int[] x, int[] y)
	{
		Coords[] toss = new Coords[x.length];
		for (int a = 0; a<x.length; a++)
		{
			toss[a] = new Coords(x[a], y[a], defaultlayer, h);
		}
		firstpoints = toss;
		path = firstpoints;
	}
	
	public Path(int[] x, int[] y, int[] z)
	{
		Coords[] toss = new Coords[x.length];
		for (int a = 0; a<x.length; a++)
		{
			toss[a] = new Coords(x[a], y[a], z[a], h);
		}
		firstpoints = toss;
		path = firstpoints;
	}
	public Path(int[] x, int[] y, int[] z, int[] h)
	{
		Coords[] toss = new Coords[x.length];
		for (int a = 0; a<x.length; a++)
		{
			toss[a] = new Coords(x[a], y[a], z[a], h[a]);
		}
		firstpoints = toss;
		path = firstpoints;
	}
	
	public Path(double[] x, double[] y)
	{
		Coords[] toss = new Coords[x.length];
		for (int a = 0; a<x.length; a++)
		{
			toss[a] = new Coords(x[a], y[a], defaultlayer, h);
		}
		firstpoints = toss;
		path = firstpoints;
	}
	public Path(double[] x, double[] y, double[] z)
	{
		Coords[] toss = new Coords[x.length];
		for (int a = 0; a<x.length; a++)
		{
			toss[a] = new Coords(x[a], y[a], z[a], h);
		}
		firstpoints = toss;
		path = firstpoints;
	}
	public Path(double[] x, double[] y, double[] z, double[] h)
	{
		Coords[] toss = new Coords[x.length];
		for (int a = 0; a<x.length; a++)
		{
			toss[a] = new Coords(x[a], y[a], z[a], h[a]);
		}
		firstpoints = toss;
		path = firstpoints;
	}
	public Path(int[][]coords)
	{
		Coords[] toss = new Coords[coords.length];
		for (int a = 0; a<coords.length; a++)
		{
			toss[a] = new Coords(coords[a]);	
		}
		firstpoints = toss;
		path = firstpoints;
	}
	
	public Path(double[][]coords)
	{
		Coords[] toss = new Coords[coords.length];
		for (int a = 0; a<coords.length; a++)
		{
			toss[a] = new Coords(coords[a]);	
		}
		firstpoints = toss;
		path = firstpoints;
	}
	public Path(Coords coords1, Coords coords2)
	{
		firstpoints[0] = new Coords(coords1);
		firstpoints[1] = new Coords(coords2);
		path = firstpoints;
	}
	public Path(Coords[]coords)
	{
		Coords[] toss = new Coords[coords.length];
		for (int a = 0; a<toss.length; a++)
		{
			toss[a] = new Coords(coords[a]);	
		}
		firstpoints = toss;
		path = firstpoints;
		
	}
	public Coords[] getPath()
	{
		return path;
	}
	
	
	public void setPath(int userMoveLen)
	{
		int timesToMove = (int)((distance())/userMoveLen);
		if(timesToMove == 0)
		{
			return;
		}
		path = beizercurve(firstpoints, timesToMove);
		System.out.println("Done");
	}
	
	public void setPath(double userMoveLen)
	{
		int timesToMove = (int)((distance())/userMoveLen);
		if(timesToMove == 0)
		{
			return;
		}
		path = beizercurve(firstpoints, timesToMove);
//		System.out.println("Done");
//		for (int a = 0; a<path.length; a++)
//		{
//			System.out.println(path[a].getX() + " : " + path[a].getY());
//		}
	}
	
	//All below are functions interpreted from my attempt at applying principles from Math 130 to Python, now put to Java.
	//The main idea is that from these functions, you can calculate 'n' points along a line; where this is useful is when the application involves curved lines.
	public double distance(Coords point1, Coords point2)//From previous experiments in Python regarding Math 130: Geometry in Computer Graphics.
	{
		double x = Math.abs((point2.getX()/point2.getH()) - (point1.getX()/point1.getH()));
		double y = Math.abs((point2.getY()/point2.getH()) - (point1.getY()/point1.getH()));
		double z = Math.abs((point2.getZ()/point2.getH()) - (point1.getZ()/point1.getH()));
		double dist = Math.sqrt((Math.pow(x, 2.0)) + (Math.pow(y, 2.0)) + (Math.pow(z, 2.0)));
		return dist;
	}
	public double distance()
	{
		double a = 0.0;
		for (int b = 0; b<firstpoints.length-1; b++)
		{
			a += distance(firstpoints[b], firstpoints[b+1]);
		}
		return a;
	}
	public Coords[] beizercurve(Coords[] points, int tm)
	{
//		Coords[] apara = new Coords[tm+1];
//		apara[0] = points[0];
//		apara[tm] = points[points.length-1];
		Coords[] npoints = new Coords[tm+1];
		for (int a = 0; a<=tm; a++)
		{
			double fraction = ((double) (a))/((double)(tm));
			npoints[a] = (deCasteljau(points, fraction))[0];
			
		}
		return npoints;
	}
	public Coords[] deCasteljau(Coords[] points, double fractionOfLen)
	{
		
		Coords[] newa = do_deCast(points, fractionOfLen);
		
		while(newa.length > 1)
		{
			newa = deCasteljau(newa, fractionOfLen);
		}
//		System.out.println(newa[0].getX() + " na: " + newa[0].getY());
		return newa;
	}
	public Coords[] do_deCast(Coords[] points, double fractionOfLen)
	{
		Coords[] newa = new Coords[points.length-1];
		for (int a = 0; a<points.length-1; a++)
		{
			newa[a] = linInterpt(points[a], points[a+1], fractionOfLen);
		}
		return newa;
//Useless code:			
//		int[] pasca = pascals_ans(points.length-1);
//		Coords[] newa = new Coords[points.length-1];
//		for (int g = 0; g<points.length-1; g++)
//		{
////			double it = pasca[g]*(Math.pow((1-(fractionOfLen)), (((points.length-1)-g))))*(Math.pow(fractionOfLen, (g)))*points[(g)].getX();
////			double jt = pasca[g]*(Math.pow((1-(fractionOfLen)), (((points.length-1)-g))))*(Math.pow(fractionOfLen, (g)))*points[(g)].getY();
////			double kt = pasca[g]*(Math.pow((1-(fractionOfLen)), (((points.length-1)-g))))*(Math.pow(fractionOfLen, (g)))*points[(g)].getZ();
//
////			Goes in other direction - not recommended, just for bookeeping.
//			double it = pasca[g]*(Math.pow((1-(fractionOfLen)), (g)))*(Math.pow(fractionOfLen, ((points.length-1)-g)))*points[((points.length-1)-g)].getX();
//			double jt = pasca[g]*(Math.pow((1-(fractionOfLen)), (g)))*(Math.pow(fractionOfLen, ((points.length-1)-g)))*points[((points.length-1)-g)].getY();
//			double kt = pasca[g]*(Math.pow((1-(fractionOfLen)), (g)))*(Math.pow(fractionOfLen, ((points.length-1)-g)))*points[((points.length-1)-g)].getZ();
//			newa[g] = new Coords(it, jt, kt);
//			System.out.println(newa[g].getX() + " nr: " + newa[g].getY());
		
	}
	public Coords linInterpt(Coords point1, Coords point2, double fractionOfLen)
	{
		double pointi = ((1-fractionOfLen)*(point1.getX()/point1.getH())) + (fractionOfLen*(point2.getX()/point2.getH()));
	    double pointj = ((1-fractionOfLen)*(point1.getY()/point1.getH())) + (fractionOfLen*(point2.getY()/point2.getH()));
	    double pointk = ((1-fractionOfLen)*(point1.getY()/point1.getH())) + (fractionOfLen*(point2.getZ()/point2.getH()));
	    return (new Coords(pointi, pointj, pointk));
	}
	
	public int[] pascals_ans(int o)
	{
		int[] pasca = {1};
		if(o != 0)
		{
			for(int a = 0; a<o-1; a++)
			{
				pasca = pascals_increment(pasca);
			}
		}
		return pasca;
	}
	public int[] pascals_increment(int[] list)
	{
		int[] pas = (int[])list.clone();
		pas[0] = 1;
		for (int instance = 0; instance<list.length-1; instance++)
		{
		    pas[instance+1] = list[instance] + list[instance + 1];
		}
	    pas[list.length] = 1; 
		return pas;
	}//End of Math 130 conversion
}
