package primitives.spaces;
import primitives.geomtry.*;
import primitives.machines.*;
import primitives.frames.*;
import java.awt.*;
import java.awt.event.*;
public class NarmsPatch implements MachineListener,MouseMotionListener{
//	Coordinate[] dVertices;
	Polygon vertices;
	Coordinate[] dVertices;
	double[] lengths;
	double[] angles;
	double[] machineVertices;
	NarmsMachine machine;
	Coordinate dCenter;
	Coordinate dState;
	Dimension d;
	double r;
	Frames controller;
//	public Graphics[] g;
	private int maxVertex;
	private int maxPolyVertex;
	boolean move;
	public NarmsPatch(Frames controller,Dimension d,NarmsMachine machine){
		if (machine.arms<3) throw new RuntimeException("machine has 3 legs");
		this.machine = machine;
		this.d = d;
		this.controller = controller;
		r = Math.min(d.width,d.height)/2-5;
		dCenter = new Coordinate(d.width/2,d.height/2);
		Coordinate[] machinePolygon = machine.findConstraintsEx();
		machineVertices = new double[machine.arms];
		vertices = new Polygon();
		dVertices = new Coordinate[machine.arms];
		lengths = new double[machine.arms];
		angles = new double[machine.arms];
		for(int j=0;j<machine.arms;j++){
			machineVertices[j] = Geomtry.getStandartAngle(
			Geomtry.getAngle(machine.origin,machinePolygon[j]));
			dVertices[j] = Geomtry.getPointByVector(dCenter,r,Math.PI*2*j/machine.arms+Math.PI/4);
			dVertices[j].move(Math.rint(dVertices[j].x),Math.rint(dVertices[j].y));
			vertices.addPoint((int)(dVertices[j].x),(int)(dVertices[j].y));
			angles[j] = Geomtry.getStandartAngle(Geomtry.getAngle(dCenter,dVertices[j]));
			lengths[j] = r;
		}
		maxVertex = getMaxVertex(machineVertices);
		maxPolyVertex = getMaxVertex(angles);
		dState = new Coordinate(0,0);
		changeState();
//		g = new Graphics[2];
	}
	protected int getMaxVertex(double[] objAngles){
		double maxAngle =  -0.1;
		int maxVertex = -1;
		for(int j=0;j<objAngles.length;j++)
			if(objAngles[j]>maxAngle){
				maxVertex = j;
				maxAngle = objAngles[j];
			}
		return maxVertex;
	}
	protected int findStateLowerVertex(double angle,double[] objAngles,int maxVertex){
		if((angle>=objAngles[maxVertex])||
			(angle<=objAngles[(maxVertex+1)%machine.arms]))
			return maxVertex;
		int j = (maxVertex+2)%machine.arms;
			while(angle>=objAngles[j])
				j = (j+1)%machine.arms;
		return (j-1+machine.arms)%machine.arms;
	}

	public void changeState(){
		double mAngle = Geomtry.getStandartAngle(machine.getCurrentAngle());
		int vertex = findStateLowerVertex(mAngle,machineVertices,maxVertex);
		int nextVertex = (vertex+1)%machine.arms;
		double nextMachineVertex = machineVertices[nextVertex];
		double angle = Geomtry.getStandartAngle(angles[nextVertex]-angles[vertex])*	
				Geomtry.getStandartAngle(mAngle-machineVertices[vertex])
				/Geomtry.getStandartAngle(nextMachineVertex-machineVertices[vertex])
				+angles[vertex];
			dState = Geomtry.findPointOnPolygon(dCenter,angle+Math.PI,vertices);
			dState = Geomtry.getMidPoint(dCenter,dState,1-machine.getRatioDistance(mAngle));
			//dState = Geomtry.getPointByVector(dCenter,angle,distance);
	}
	public final static char[] letters = {'A','B','C','D'};
	public void redraw(Graphics g){
		g.setColor(Color.black);
		g.drawPolygon(vertices);
		g.setColor(Color.green);
		Geomtry.drawJoint(g,dState.toPoint());
		g.setColor(Color.black);
		if(machine.arms==4){
			for(int i=0;i<4;i++)
				g.drawChars(letters,i,1,(vertices.xpoints[(i+1)%4]+vertices.xpoints[(i+2)%4])/2+(i-1)*15*((i+1)%2),
					(vertices.ypoints[(i+1)%4]+vertices.ypoints[(i+2)%4])/2+(i-2)*15*((i)%2));
		}
	}
	public void mouseMoved(MouseEvent e){
		if(move){
			Point p = e.getPoint();
			dState.move(p.x,p.y);
			if (!vertices.contains(p)){
				dState = Geomtry.findPointOnPolygon(dCenter,dState,vertices);
			}
			double angle = Geomtry.getStandartAngle(Geomtry.getAngle(dCenter,dState))+Math.PI;
 			int vertex = findStateLowerVertex(angle,angles,maxPolyVertex);
			int nextVertex = (vertex+1)%machine.arms;
			double mAngle = Geomtry.getStandartAngle(
				machineVertices[nextVertex]-machineVertices[vertex])*
				Geomtry.getStandartAngle(angle-angles[vertex])/
				Geomtry.getStandartAngle(angles[nextVertex]-angles[vertex])+
				machineVertices[vertex];
			double ratio = Geomtry.distance(dCenter,dState)/
						Geomtry.distance(dCenter,Geomtry.findPointOnPolygon(dCenter,
						angle,vertices));
			//	Coordinate t = Geomtry.getPointByVector(
			//		machine.origin,mAngle,machine.getMaxDistance(mAngle));
			Coordinate t = Geomtry.getMidPoint(machine.getMaxPoint(mAngle),
					machine.origin,ratio);
			machine.moveCenterEx(t.x-machine.center.x,t.y-machine.center.y);
			for(int j=0;j<controller.frames.length;j++){
			//	if(g[j]==null) g[j] = controller.frames[j].drawArea.getGraphics();
				controller.frames[j].drawArea.repaint();//(g[j]);
			}
					//controller.frames[1].drawArea.update(controller.g2);
		}
		move=!move;
	}
	public void	mouseDragged(MouseEvent e){
	mouseMoved(e);
	}
	
}
