package primitives.machines;
import primitives.geomtry.*;
import java.awt.*;
/**
*An abstract class which is ancestor to all machines.
*The class defines the information on the machine's joints and anchors.
*Provide common methods shared by all machine objects.
*@author Dori Eldar.
*/
public abstract class  Machine implements MachineListener{
   /**
   *The array of the location of the machine's joints.
   */
   protected Coordinate[] dJoints;
   /**
   *The array of the location of the machine's anchors.
   */
   protected Coordinate[] dAnchors;
   /**
   *stores the last joints locations for if restore is needed.
   */
   protected Coordinate[] tempJoints;
   /**
   *The integer location of the anchors.
   *Used in the calls to the Graphic methods.
   */
   public ExtPoint[] anchors;
   /**
   *The integer location of the joints.
   *Used in the calls to the Graphic methods.
   */
   public ExtPoint[] joints;
   /**
   *The length of the rigid bar.
   *All bars are presumed to be of same length.
   *machines with differnt bar length should define its own fields.
   */
   public int barLength=0;
   /**
   *Each joint can take to bending positions.
   *These values should be only 1 and -1.
   */
   public int[] bendStates;
   /**
   *The dimension of the rectangle the machine is being drawn in.
   */
   protected Dimension d;
   /**
   *@param joints number of joints in the machine.
   *@param anchors number of anchor in the machine.
   *@param d the dimension of the rectangle the machine should be drawn in.
   */
   public Machine(int joints,int anchors,Dimension d){
	   dJoints = new Coordinate[joints];
	   dAnchors = new Coordinate[anchors];
	   tempJoints = new Coordinate[joints];
	   for(int i=0;i<joints;i++)
		   tempJoints[i] = new Coordinate(); 
	   this.anchors = new ExtPoint[anchors];
	   this.joints = new ExtPoint[joints];
	   bendStates = new int[joints];			
	   this.d = d;
   }
   /**
   *Sets object fields to null.
   @exception java.lang.Throwable .
   */
   public void finalize() throws Throwable{
	   dJoints = null;
	   tempJoints = null;
	   joints = null;
	   dAnchors = null;
	   d = null;
	   anchors = null;
	   bendStates = null;
   }
   /**
   *Rounds the location of the anchors to the nearest integer location.
   *Since anchors do not change there position, there real location should be integral.
   */
   protected void integrizeAnchors(){
	   for (int i=0;i<dAnchors.length;i++)
		   if (dAnchors[i]!=null) dAnchors[i].move(Math.rint(dAnchors[i].x),Math.rint(dAnchors[i].y));
   }
   /**
   *sets the tempJoints array to the current location of the dJoints array.
   */
   protected void savePoints(){
	   for(int i=0;i<dJoints.length;i++)
		   if(dJoints[i]!=null)
			tempJoints[i].move(dJoints[i].x,dJoints[i].y);
	       
   }
   /**
   * Restores the location of the joints by setting its location to the locations saved
   *in tempJoints.
   */
   protected void restorePoints(){
	   for(int i=0;i<dJoints.length;i++)
		   if(dJoints[i]!=null)
				dJoints[i].move(tempJoints[i].x,tempJoints[i].y);

   }
   /**
   *Draws the anchors of this machine.
   *@param g the graphic context to draw on.
   */
   protected void drawAnchors(Graphics g){    
	   Color old = g.getColor();
	   g.setColor(Color.red);
	   for(int i=0;i<anchors.length;i++)
		   if (anchors[i]!=null) Geomtry.drawAnchor(g,anchors[i]);
	   g.setColor(old);
   }
   /**
   *Implementation of the MachineListener interface.
   *Draws the joints and anchors of the machine. 
   */
   public void redraw(Graphics g){
	   updatePoints(dJoints,joints);
	   drawJoints(g);
	   g.setColor(Color.red);
	   drawAnchors(g);
   }
	/**
	*rotates specified joint c2 around joint c1 in dalpha radians.
	*@param c1 the joint at the origin.
	*@param c2 the joint to rotate.
	*@param dalpha the angle to rotata.
	*@return the new angle between c1 and c2.
	*/
   protected  double   rotateJoint(Coordinate c1,Coordinate c2,double dalpha){
		double alpha = Geomtry.getAngle(c1,c2);
		double d = Geomtry.distance(c1,c2);
		alpha = alpha+dalpha;
		Coordinate temp = Geomtry.getPointByVector(c1,d,alpha);
		c2.move(temp.x,temp.y);
		return alpha;
	}
   /**
   *copies the locations of array of Coordinate to an array of ExtPoint.
   *The locations are rounded to the nearest integer values.
   *@param src the source.
   *@param dst the destination array of Point.
   *@see #redraw
	*/
   protected static void updatePoints(Coordinate[] src,ExtPoint[] dst){
	   for (int i=0;i<src.length;i++){
		   if (src[i]!=null)
			   if(dst[i]==null)dst[i]=src[i].toPoint();
			   else dst[i].move((int)Math.rint(src[i].x),(int)Math.rint(src[i].y));	
   			else dst[i] = new ExtPoint(1,1);
	   }
   }
   /**
   *Draws the machine's joints.
   *@param g the graphic context to draw on.
   */
   protected void drawJoints(Graphics g){
	   Color old = g.getColor();
	   g.setColor(Color.green);
	   for(int i=0;i<joints.length;i++)
		   if (joints[i]!=null) Geomtry.drawJoint(g,joints[i]);
		g.setColor(old);
   }
	/**
	*Draws a line between to locations.
	*The color of the line should be set before calling this method.
	*@param g the graphic context to draw on.
	*@param p1, p2 the endpoints of the line.
	*/
	public static void drawLine(Graphics g,Point p1,Point p2){
		if ((p1!=null)&&(p2!=null))g.drawLine(p1.x,p1.y,p2.x,p2.y);
		else g.drawLine(1,1,10,10);
	}
	/**
	*Returns the second possible location of of <code>mid</code>.
	*mid is supposed to be an adjacent joint of c1 and c2.
	*@exception java.lang.ArithmeticException never throws this exception.
	*/
	protected static Coordinate switchBend(Coordinate c1,Coordinate c2,Coordinate mid)throws ArithmeticException{
		Coordinate[] temp = Geomtry.getTriPoint(c1,Geomtry.distance(c1,mid),c2,Geomtry.distance(c2,mid));
		if (Geomtry.distance(temp[0],mid)<Geomtry.distance(temp[1],mid)) return temp[1];
		else return temp[0];
	}
   
 }
