package primitives.machines;
import primitives.geomtry.*;
import java.awt.*;
import java.awt.event.*;
/**
* A linkage used to calculate the square of a complex number by using the formula: <img src="images/comp3.gif">
*@see FunctiionalLinkage
*@see Translator1
*@see ScalarMultiplier1
*@see Inversor1
*@see Adder
*@author Dori Eldar
*/
public class Multiplier implements FunctionalLinkage{
	/**
	*array of the 3 Translator1 objects used by this object.
	*/
	Translator1[] translators = new Translator1[3];
	/**
	*Array of the 3 Inversor1 objects used by this object
	*/
	Inversor1[] inversors = new Inversor1[3];
	/**
	*Preforms multiplication by -1
	*/
	ScalarMultiplier1 anti;
	Adder adder;
	/**
	*An enumeration of the 8 <code>FunctionalLinkage</code> objects, memebers of <code>Multiplier</code>
	*The array points to the following objects:
	*<pre>
	*linkages[0-1]=translators[0-1]
	*linkages[2-3] = inversors[0-1];
	*linkages[4] = anti;
	*linkages[5] = adder;
	*linkages[6] = inversors[2];
	*linkages[7] = translators[2];
	*</pre>
	*/
	final FunctionalLinkage[] linkages = new FunctionalLinkage[8];
	Coordinate[] inputs = new Coordinate[2];
	/**
	*@param d the rectangle in which to draw the Squaring Linkage.
	*/
	public Multiplier(Rectangle d){
		for(int i=0;i<3;i++){
			inversors[i] = new Inversor1(new Rectangle(d.x+d.width/2,d.y+d.height/2,d.width/2,d.height/2));
			inversors[i].radius = 100;
			linkages[i+2] = inversors[i];
		}
		
		translators[0] = new Translator1(new Point(d.x+d.width,d.y+d.height),new Coordinate(-50,0));
		translators[1] = new Translator1(new Point(d.x+d.width,d.y+d.height),new Coordinate(50,0));
		adder = new Adder(d);
		translators[2] = new Translator1(new Point(d.x,d.y),new Coordinate(25,0));
		anti = new ScalarMultiplier1(d,-1,true);
		inputs[0] = new Coordinate(anti.origin.x+100,anti.origin.y-90);
		/*Setting linkages enumeration*/
		linkages[0] = translators[0];
		linkages[1] = translators[1];
		linkages[4] = anti;
		linkages[5] = adder;
		linkages[6] = inversors[2];
		linkages[7] = translators[2];
		/*end */
		forceInputJoints(inputs);
		for(int i=0;i<3;i++){
			translators[i].heights[0]  = translators[i].heights[0]*3/2; 
			translators[i].heights[1]  = translators[i].heights[1]*3/2;
		}
		adder.a2scalar.tBar = adder.a2scalar.tBar*2;
		adder.a2scalar.sBar = adder.a2scalar.sBar*2;
		adder.average.tBar = adder.average.tBar*2/3;
		adder.average.sBar = adder.average.sBar*2/3;
		translators[0].origin = anti.origin;
		translators[2].origin = anti.origin;
		try{
		setInputJoints(inputs);
		}catch(Exception e){}
	}
		Coordinate[] transInputs = new Coordinate[2];
		Coordinate[] inversInputs =  new Coordinate[2];
		Coordinate[] antiInputs = new Coordinate[2];
		Coordinate[] adderInputs = new Coordinate[2];
		Coordinate[] inver3Inputs = new Coordinate[2];
		Coordinate[] trans3Inputs = new Coordinate[2];
	/**
	*@see FunctionalLinkage#forceInputJoints
	*/
	public Coordinate[] forceInputJoints(Coordinate[] input){
		transInputs[0]= new Coordinate(input[0]);
		inversInputs[0]= new Coordinate(translators[0].forceInputJoints(transInputs)[0]);
			adderInputs[0]= new Coordinate(inversors[0].forceInputJoints(inversInputs)[0]);
		inversInputs[0]= new Coordinate(translators[1].forceInputJoints(transInputs)[0]);
		antiInputs[0]= new Coordinate(inversors[0].dAnchors[0]);	 
		antiInputs[1]= new Coordinate(inversors[1].forceInputJoints(inversInputs)[0]);
		adderInputs[1]= new Coordinate(anti.forceInputJoints(antiInputs)[0]);
	    inver3Inputs[0]= new Coordinate(adder.forceInputJoints(adderInputs)[0]);
		trans3Inputs[0]= new Coordinate(inversors[2].forceInputJoints(inver3Inputs)[0]);
		return translators[2].forceInputJoints(trans3Inputs);
	}
	/**
	*Used internaly by setInputJoints method
	*/
	private int i=0;
	public Coordinate[] setInputJoints(Coordinate[] input)throws MachineException{
		transInputs[0].move(input[0]);
		/*Backing-up the location of the input joint, if a restore is required*/
		this.inputs[0].move(translators[0].getInputJoints()[0]);
		try{
		inversInputs[0].move(translators[0].setInputJoints(transInputs)[0]);
		adderInputs[0].move(inversors[0].setInputJoints(inversInputs)[0]);
		inversInputs[0].move(translators[1].setInputJoints(transInputs)[0]);
		antiInputs[0].move(inversors[0].dAnchors[0]);	 
		antiInputs[1].move(inversors[1].setInputJoints(inversInputs)[0]);
		adderInputs[1].move(anti.setInputJoints(antiInputs)[0]);
	    inver3Inputs[0].move(adder.setInputJoints(adderInputs)[0]);
		trans3Inputs[0].move(inversors[2].setInputJoints(inver3Inputs)[0]);
		return translators[2].setInputJoints(trans3Inputs);
		/* If the requested location is not valid, the method is called recursivly using the
		*  last valid input location. To avoid an infinite recursion setInputJoints is called
		*  only if i<=4
		*/
		}catch(MachineException m){
		
			if(i++<4)setInputJoints(this.inputs);
			i=0;
			throw m;	
		}
	}
	/**
	*@see FunctionalLinkage#getInputJoints
	*/
	public Coordinate[] getInputJoints(){
		return translators[0].getInputJoints();
	}
	/**
	*@see FunctionalLinkage#getOutputJoints
	*/
	public Coordinate[] getOutputJoints(){
		 return translators[2].getInputJoints();
	}
	/**
	*Not implemented.
	*/
	public void setParameters(double[] parameters) {}
	/**
	*Not implemeted
	*@return null
	*/
	public double[] getParameters(){
		return null;
	} 
	/**
	*Draws a Squaring Linkage.
	*@param g the graphic context to draw to.
	*@see MachineListener
	*/
	public void redraw(Graphics g){
		/*Draw X and Y axis*/
		g.drawLine(anti.origin.x-400,anti.origin.y,anti.origin.x+400,anti.origin.y);
		g.drawLine(anti.origin.x,anti.origin.y-400,anti.origin.x,anti.origin.y+400);
		for(int i=-2;i<3;i++){
			g.drawLine(anti.origin.x+100*i,anti.origin.y-5,anti.origin.x+100*i,anti.origin.y+5);
			g.drawLine(anti.origin.x-5,anti.origin.y+100*i,anti.origin.x+5,anti.origin.y+100*i);
		}
		/*End Draw X,Y axis*/
		g.setColor(Color.gray);
		for(int i=0;i<8;i++)
			if(i!=activeLinkage||i==0)linkages[i].redraw(g);
		g.setColor(Color.yellow) ;
		/*Preforming draw fixes*/
		for(int i=0;i<3;i++)
			Geomtry.drawJoint(g,inversors[i].joints[2]);
		Geomtry.drawJoint(g,anti.joints[anti.input2]);
        Geomtry.drawJoint(g,adder.average.joints[adder.average.input2]);
		Geomtry.drawJoint(g,adder.average.joints[adder.average.input1]);
		Geomtry.drawJoint(g,translators[2].joints[2]);	
		/*Now we draw the active Linkage*/
		g.setColor(Color.black);
		if((activeLinkage>-1)&&(linkages[activeLinkage]!=null))
			if(activeLinkage>0||translators[0].activeJoint!=2){
			   int tactive = linkages[activeLinkage].getActiveJoint();
			   if(linkages[activeLinkage]instanceof Inversor1){
				   if(tactive>1)linkages[activeLinkage].setActiveJoint(-1);
				}else if(linkages[activeLinkage]instanceof Translator1){
				   if(tactive!=0)linkages[activeLinkage].setActiveJoint(-1);
				}else if	(activeLinkage==4){
				   if (tactive!=5)anti.activeJoint=-1;
				  
			   }else{
				   if(tactive!=5&&tactive!=11) adder.activeJoint = -1;
				 }
			   linkages[activeLinkage].redraw(g);
			}
	}
	/**
	*The active linkage is the linkage which owns the joint the mouse pointer is over.
	*/
	int activeLinkage = -1;
	/**
	*@see FunctionalLinkage#mouseMoved
	*/
	public int mouseMoved(MouseEvent m){
		activeLinkage = -1;
		for(int i=0;i<8;i++){
			int d = linkages[i].mouseMoved(m);
			if(d>-1){
				activeLinkage = i;
				return (d);
			}
		}
		return -1;
	} 
	/**
	*@exception MachineException if the new location of the active joint is not valid
	*@see FunctionalLinkage#mouseDragged
	*/
	public void mouseDragged(MouseEvent m)throws MachineException{
		 if(activeLinkage>-1){
			 int active = linkages[activeLinkage].getActiveJoint();
			 /*We are asked to move the input joint*/
			 if (activeLinkage==0&&active==2){
				 inputs[0].move(m.getX(),m.getY());
					setInputJoints(inputs);
			 /*We are asked to resize a sub-linkage*/
			 }else if ((linkages[activeLinkage]instanceof Inversor1&&active<2)||
				   (linkages[activeLinkage]instanceof Translator1&&active==0)||
				   (activeLinkage==4&&active==5)||
				   activeLinkage==5&&active==11){
				   linkages[activeLinkage].mouseDragged(m);
			 }else if (activeLinkage==5&&active==5){
					adder.average.fixed = true;
					adder.mouseDragged(m);
					adder.average.fixed = false;
			 }
		 }
	}
	final static String def = "Squaring Linkage"; 
	/**
	*@see FunctionalLinkage#getActiveStr
	*/
	public String getActiveStr(int activeJoint){
		try{
			if((activeLinkage==0&&activeJoint==2)||(activeLinkage==7&&activeJoint==3))
			return linkages[activeLinkage].getActiveStr(activeJoint);
			return linkages[activeLinkage].getActiveStr(-1);
		}catch(RuntimeException e){
			return def;
		}
	}
	/**
	*@return -1
	*/
	public int getActiveJoint(){
		   return -1;
	}
	
 	/**
	*Not implemented.
	*@see FunctionalLinkage#setActiveJoint
	*/
	public void setActiveJoint(int activeJoint){
	}

}


