package threearms;
import java.awt.*;
import primitives.geomtry.ExtPoint;
import primitives.geomtry.Coordinate;
import primitives.machines.MachineException;
public class Machine {
	public ExtPoint[] anchors;
	public int[] state ;//only valus of +1,-1  !
	public Point[] joints;
	public ExtPoint center;
		private double line;
	//public double[] constraints;
	private Point border;
	public int legs;
	public Machine(int legs,Dimension border){
		anchors = new ExtPoint[legs];
		joints = new Point[legs];
		state = new int[legs];
		this.legs=legs;
		this.border = new Point(border.width,border.height);
		center = new ExtPoint((border.width)/2,(border.height)/2);
		line=(Math.min(border.width,border.height))/4;
		for (int angle=0;angle<legs;angle++){
			state[angle]=-1;
			anchors[angle]=Geomtry.getPointByVector(center.toCoordinate(),(double)(line*1.9),2*(double)(Math.PI*angle/legs+0.1)).toPoint();
			joints[angle] = getJoint(center,anchors[angle],state[angle]);
		}
	}
	public Coordinate getConstraints(int a,int b){
		double ratio = 2*this.line/Geomtry.distance(anchors[a],anchors[b]);
		return Geomtry.getMidPoint(anchors[b],anchors[a],ratio);
			//(new coordinate(ratio*(anchors[a].x)+(1-ratio)*anchors[b].x,ratio*anchors[a].y+(1-ratio)*anchors[b].y).toPoint());
	}
	
	public void moveCenter(int x,int y)throws MachineException{
		ExtPoint oldCenter = new ExtPoint(center.x,center.y);
		center.move(x,y);
		for(int index=0;index<legs;index++){
		   joints[index]=getJoint(center,anchors[index],state[index]);
		   if (joints[index]==null){
			   this.center=oldCenter;
			   throw (new MachineException("illegalmove")) ;
		   }
		}
	}
	public void moveCenterEx(int x,int y){
		ExtPoint oldCenter = new ExtPoint(center.x,center.y);
		center.move(x,y);
		for(int index=0;index<legs;index++){
		   joints[index]=getJointEx(center,anchors[index],state[index]);
		}
	}
	Coordinate shipoa = new Coordinate();
	private Point getJoint(Point point1,Point point2,int state){
		Coordinate mid = Geomtry.getMidPoint(point1,point2,(double)0.5);
		shipoa.move(point1.x-point2.x,point1.y-point2.y);
		double l;
		double lsqr=line*line-((point1.x-mid.x)*(point1.x-mid.x)+(point1.y-mid.y)*(point1.y-mid.y));
		l=Math.sqrt(lsqr);
		if (lsqr<-2) return null;// (new Point(0,0));
		else{
			if (lsqr<0) l=0;
			double dy;double dx;
			if (shipoa.y!=0){
				double K=-shipoa.x/shipoa.y;
				dy=(double)(l*K/Math.sqrt(1+Math.pow(K,2)));
				if (K==0) dx=l;
				else dx=dy/K;
			}else{
				dy=l;
				dx=0;
			}
			mid.move(mid.x+(dx*state),mid.y+(dy*state));
			return mid.toPoint();
		}
	}
	Coordinate shipoa1 = new Coordinate();
	private Point getJointEx(Point point1,Point point2,int state){
		Coordinate mid = Geomtry.getMidPoint(point1,point2,(double)0.5);
		shipoa1.move(point1.x-point2.x,point1.y-point2.y);
		double l;
		double lsqr=line*line-((point1.x-mid.x)*(point1.x-mid.x)+(point1.y-mid.y)*(point1.y-mid.y));
		l=Math.sqrt(lsqr);
	//	if (lsqr<-1) return null;// (new Point(0,0));
	//	else{
			if (lsqr<0) l=0;
			double dy;double dx;
			if (shipoa1.y!=0){
				double K=-shipoa1.x/shipoa1.y;
				dy=(l*K/Math.sqrt(1+Math.pow(K,2)));
				if (K==0) dx=l;
				else dx=dy/K;
			}else{
				dy=l;
				dx=0;
			}
			mid.move(mid.x+(dx*state),mid.y+(dy*state));
			return mid.toPoint();
	//	}
	}				
			
	public void finalize() throws Throwable{
		anchors = null;
		joints = null;
		border = null;
		center = null;
		state = null;
	}
	public void rotateLeg(int leg,double alpha)throws MachineException{
		Point[] oldJoints = new Point[legs];
		System.arraycopy (joints,0,oldJoints,0,legs);
		ExtPoint oldCenter = center;
	//	double angle = Geomtry.getAngle(center,anchors[leg]);
//		double d = Math.floor(Geomtry.distance(anchors[leg],center));
		Coordinate newCenter = Geomtry.getPointByVector(anchors[leg].toCoordinate(),(double)(2*line),(double)(alpha));
		moveCenterEx(newCenter.toPoint().x,newCenter.toPoint().y);
		boolean legalMove = true;
		for(int i=0;i<legs-1;i++) if ((int)Geomtry.distance(center,joints[i])>line) legalMove=false;
		if (!legalMove){
			System.arraycopy (oldJoints,0,joints,0,legs);
			center = oldCenter;
			throw (new MachineException("illegal Move"));
		}
	}
			

}
