package primitives.spaces;
import java.awt.*;
import primitives.geomtry.*;
import primitives.machines.*;
public class MultiPolygons extends CircleSpace {
	private int arms;
	private Dimension realD;
	private Coordinate dCenter;
//	private Coordinate dt;
	public Polygon[] polygons;
	Polygon machinePolygon = null;
	private int demoType;
	boolean[] drawPolygon;
	private double[] machineVertices;
	private double[] polygonVertices;
	private Coordinate[] dtcenters;
	private NarmsMachine machine;
	public MultiPolygons(Dimension d,int arms,int demoType,NarmsMachine machine,int visiblePolygons){
		super(d,0,Math.PI*2);
		this.arms = arms;
		r = r/3;
		a = r;
		b = r;
		realD = d;
		this.demoType = demoType;
		dCenter = new Coordinate(Math.rint(d.width/2),Math.rint(d.height/2));
		polygons = new Polygon[4];
		for(int i=0;i<4;i++){
			polygons[i] = new Polygon();
			polygons[i].addPoint(realD.width/2,realD.height/2);
		}
		Coordinate[] vertexes = new Coordinate[arms-1];
		vertexes[0] = new Coordinate(realD.width/2-r*2,realD.height/2);
		dtcenters = new Coordinate[4];
		dtcenters[0] = Geomtry.getMidPoint(new Coordinate(realD.width/2-r*2,realD.height/2)
			,new Coordinate(realD.width/2,realD.height/2-r*2),0.5);
		for(int i=1;i<4;i++){
			dtcenters[i] = Geomtry.getPointByVector(dCenter,Geomtry.distance(dCenter,dtcenters[0]),
				Geomtry.getAngle(dCenter,dtcenters[i-1])+Math.PI/2);
		}
		double alpha = Geomtry.getAngle(dtcenters[0],new Coordinate(realD.width/2-r*2,realD.height/2));
		double dalpha = Math.PI/(arms-2);
		for(int i=1;i<arms-2;i++){
			vertexes[i] = Geomtry.getPointByVector(dtcenters[0],Math.sqrt(2)*r,alpha+dalpha*(i));
		}
		vertexes[arms-2] = new Coordinate(realD.width/2,realD.height/2-r*2); 
		for(int j=0;j<arms-1;j++){
			alpha = Geomtry.getAngle(dCenter,vertexes[j]);
			double dr = Geomtry.distance(dCenter,vertexes[j]);
			for(int i=0;i<4;i++){
			   Point t = Geomtry.getPointByVector(dCenter,dr,alpha+Math.PI*i/2).toPoint();
			   polygons[i].addPoint(t.x,t.y);
			   
			}
		}
		for(int shape=0;shape<2;shape++){
			Polygon t = new Polygon();
			t.addPoint(polygons[0].xpoints[0],polygons[0].ypoints[0]);
			for(int vertex=arms-1;vertex>0;vertex--)
				t.addPoint(polygons[1+2*shape].xpoints[vertex],polygons[1+2*shape].ypoints[vertex]);
			polygons[1+2*shape] = t;
		}
 		this.machine = machine;
		if (demoType==1){
			machinePolygon = machine.findConstraints();
			machineVertices = new double[arms];
			polygonVertices = new double[arms];
			for(int i=0;i<arms;i++){
			   machineVertices[i] = Geomtry.getAngle(machine.origin,
				   new Coordinate(machinePolygon.xpoints[i],machinePolygon.ypoints[i]));
			   polygonVertices[i] = Geomtry.getAngle(dtcenters[0],
				   new Coordinate(polygons[0].xpoints[i],polygons[0].ypoints[i]));
			   machineVertices[i] = Geomtry.getStandartAngle(machineVertices[i]);
			   polygonVertices[i] = Geomtry.getStandartAngle(polygonVertices[i]);
			}
		}
		drawPolygon = new boolean[4];
		for(int i=0;i<4;i++) drawPolygon[i] = false;
		for(int i=0;i<visiblePolygons;i++)
				drawPolygon[i]=true;

	}

	private int findStateLowerVertex(double angle){
		double maxAngle =  -0.1;
		int maxVertex = -1;
		for(int j=0;j<arms;j++)
			if(machineVertices[j]>maxAngle){
				maxVertex = j;
				maxAngle = machineVertices[j];
			}
		angle = Geomtry.getStandartAngle(angle);
		if((angle>=maxAngle)||(angle<=machineVertices[(maxVertex+1)%arms]))
			return maxVertex;
		int j = (maxVertex+2)%arms;
			while(angle>=machineVertices[j])
				j = (j+1)%arms;
		return (j-1+arms)%arms;
	}
	private double translateAngle(double angle,int j){
		switch(j){
		case 1:return Math.PI-angle;
		case 2:return angle+Math.PI;
		case 3:return Math.PI*2 -angle;
		default:return angle;
		}
	}
	public void changeState(){
		if(demoType==0)
			super.changeState(Math.PI/2);
		else{
			double angle = Geomtry.getStandartAngle(machine.getCurrentAngle());
			int vertex = findStateLowerVertex(angle);
			double nextMachineVertex = machineVertices[(vertex+1)%arms];
			if (nextMachineVertex<machineVertices[vertex]) nextMachineVertex = nextMachineVertex+Math.PI*2;
			double nextPolygonVertex = polygonVertices[(vertex+1)%arms];
			if (nextPolygonVertex<polygonVertices[vertex]) nextPolygonVertex = nextPolygonVertex+Math.PI*2;
			if(angle<machineVertices[vertex]) angle = angle+Math.PI*2;
			angle = polygonVertices[vertex]+(nextPolygonVertex-polygonVertices[vertex])*
				(angle-machineVertices[vertex])/(nextMachineVertex-machineVertices[vertex]);
			angle = translateAngle(angle,currentPolygon);
		if(currentPolygon<4)	state = Geomtry.findPointOnPolygon(dtcenters[currentPolygon],angle,polygons[currentPolygon]).toPoint();
		}
	}
	private 	int currentPolygon = 5;
	private boolean pass = false;
	public void update(Graphics g){
	
		if (demoType==1){
			if(machine.bendStates[0]==1){
				if(machine.bendStates[1]==1) currentPolygon=0;
				else currentPolygon=3;
			}else{
				if(machine.bendStates[1]==1) currentPolygon=1;
				else currentPolygon=2;
			}
			g.clearRect(0,0,d.width,d.height);
		}
		else super.update(g);
		g.setColor(Color.black);
		for(int i=0;i<polygons.length;i++)
			if(drawPolygon[i]==true) g.drawPolygon(polygons[i]);
			if(currentPolygon<4){
			
				g.drawString("U",polygons[0].xpoints[0]+5,
					(polygons[0].ypoints[0]+polygons[0].ypoints[arms-1])/2);
				g.drawString("D",(polygons[0].xpoints[0]+polygons[0].xpoints[1])/2,
					polygons[0].ypoints[0]+15);
				if (drawPolygon[1])
					g.drawString("D",(polygons[1].xpoints[0]+polygons[1].xpoints[1])/2,
					polygons[1].ypoints[0]+15);
				if (drawPolygon[2])
					g.drawString("U",polygons[2].xpoints[0]+5,
					(polygons[2].ypoints[0]+polygons[2].ypoints[arms-1])/2);

			for(int i=0;i<4;i++)
				if(drawPolygon[i]){
					g.drawString("B",polygons[i].xpoints[2]-12-8*(i-3)*i,
						(polygons[i].ypoints[2]+polygons[i].ypoints[1])/2);
					g.drawString("C",(polygons[i].xpoints[2]+polygons[i].xpoints[3])/2,
					   (int)(0.3*polygons[i].ypoints[2]+0.7*polygons[i].ypoints[3])-6+20*(i/2));
				}
		}
	}
	public void finalize() throws Throwable{
		dCenter = null;
		realD = null  ;
		for(int i=0;i<polygons.length;i++) polygons[i] = null;
		polygons = null;
		machinePolygon = null;
		machineVertices = null;
		polygonVertices = null;
		machine = null;
		dtcenters = null ;
		super.finalize();
	}
}