package primitives.machines;
import java.awt.*;
import java.awt.event.*;
import primitives.geomtry.*;
/**
*Kapovich & Milson's modification of the ScalarMultiplier Linkage around a degenerate input location
*(0,0)
*The Linkage uses the formula: <img src="images/main1.gif">
*/
public class ScMultForZero implements FunctionalLinkage{
	/**
	*An array containing the 2 Translator1 objects used by this linkage.
	*/
	Translator1[] translators = new Translator1[2];
	ScalarMultiplier1 scMult;
	/**
	*An enumeration of the 3 linkages composing this linkage:
	*<pre>
	*linkages[0]=translators[0]
	*linkages[1]=scMult;
	*linkages[2]=translators[1]
	*/
	final FunctionalLinkage[] linkages = new FunctionalLinkage[3];
	/**
	*The location on the canvas of the relative origin
	*/
	Point origin;
	/**
	*The real vector of translation
	*/
	int b;
	/**
	*The scalar multiplier
	*/
	double lamda;
	
	Coordinate[] inputs = new Coordinate[2];
	/**
	*@param d the rectangle to draw this object in
	*@param scalar the scalar multiplier to be used
	*/
	public ScMultForZero(Rectangle d,double scalar){
		b = (int)((d.width/2-10)/scalar);   
		lamda = scalar;
		origin = new Point(d.x+d.width/2,d.y+d.height/2);
		translators[0] = new Translator1(new Point(origin.x+b,origin.y),new Coordinate(-b,0));
		translators[1] = new Translator1(new Point(origin.x,origin.y),new Coordinate(lamda*b,0));		
		scMult = new ScalarMultiplier1(d,scalar,true);
		inputs[0] = new Coordinate(origin.x+10,origin.y+15);
		inputs[1] = new Coordinate();
		linkages[0] = translators[0];
		linkages[1] = scMult;
		linkages[2] =translators[1];
		forceInputJoints(inputs);
		scMult.tBar = Math.max(scMult.tBar,scMult.sBar)+20;
		for(int i=0;i<2;i++){
			translators[i].origin.move(origin.x,origin.y);
			translators[i].heights[0] = Math.max(translators[i].heights[1],translators[i].heights[0])+20;
		}
		
		try{
			setInputJoints(translators[0].getInputJoints());
		}catch(Exception m){}
	}
	/**
	*@see FunctionalLinkage#forceInputJoints
	*/
	public Coordinate[] forceInputJoints(Coordinate[] inputs){
		this.inputs[0].move(inputs[0]);
			this.inputs[1].move(linkages[0].forceInputJoints(this.inputs)[0]);
			this.inputs[0].move(linkages[1].forceInputJoints(this.inputs)[0]);
			this.inputs[0].move(linkages[2].forceInputJoints(this.inputs)[0]);
		return(inputs);
	}
	/**
	*used internaly by setInputJoints method
	*/
	private int i=0;
	Coordinate[] tInputs = {new Coordinate(),new Coordinate()};
	/**
	*@exception MachineException .
	*@see FunctionalLinkage#setInputJoints
	*/
	public Coordinate[] setInputJoints(Coordinate[] inputs)throws MachineException{
		/*Preforms a backup of the last valid location of the input joint*/	
		this.inputs[0].move(inputs[0]);
		tInputs[0].move(linkages[0].getInputJoints()[0]);
		try{	
			this.inputs[1].move(linkages[0].setInputJoints(this.inputs)[0]);
			this.inputs[0].move(linkages[1].setInputJoints(this.inputs)[0]);
			this.inputs[0].move(linkages[2].setInputJoints(this.inputs)[0]);
		return(inputs);
		/*If the required location is invalid this method is recursivly called with
		*the last valid location as parameter.
		*To avoid infinite recursion the value of i is checked.
		*/
		}catch(MachineException e){
			if(i++<4)setInputJoints(tInputs);
			i=0;
			throw(e);
		}
	}
	/**
	*@see FunctionalLinkage#getInputJoints
	*/
	public Coordinate[] getInputJoints(){
		return linkages[0].getInputJoints();
	}
	/**
	*@see FunctionalLinkage#getOutputJoints
	*/
	public Coordinate[] getOutputJoints(){
		return linkages[2].getOutputJoints();
	}
	/**
	*Not implemented
	*/
	public void setParameters(double[] paramaters){}
	/**
	@return null
	*/
	public double[] getParameters(){
		return null;
	}
	/**
	*Draws a Scalar Multiplier around Zero linkage
	*@param g the graphic context to draw to.
	*@see MachineListener
	*/
	public void redraw(Graphics g){
		    Color t = g.getColor();
			for(int i=0;i<3;i++)
				linkages[i].redraw(g);
			g.setColor(Color.yellow);
			Geomtry.drawJoint(g,scMult.joints[scMult.input2]);
			Geomtry.drawJoint(g,scMult.joints[scMult.output]);
			g.setColor(t);
	}
	/**
	*The enumerated joint the mouse pointer is over
	*/
	int activeJoint = -1;
	/**
	*@see FunctionalLinkage#mouseMoved
	*/
	public int mouseMoved(MouseEvent m){
		activeJoint = -1;
		for(int i=0;i<3;i++){
				activeJoint = linkages[i].mouseMoved(m);
				if (activeJoint>-1){
					activeJoint = activeJoint+10*i;
					return activeJoint;
				}
		}
		return activeJoint;
	}
	/**
	*@exception MachineException .
	*@see FunctionalLinkage#mouseDragged
	*/
	public void mouseDragged(MouseEvent m)throws MachineException{
		inputs[0].move(m.getX(),m.getY());
		if(activeJoint==2){
			setInputJoints(inputs);
		}else if(activeJoint==13){
			double d = Geomtry.distance(scMult.dJoints[0],inputs[0]);
			double total = scMult.scalar*scMult.sBar;
			if (total/d>4.0) throw new MachineException(0);
			linkages[1].mouseDragged(m);
			inputs[0].move(origin.x,origin.y);
			inputs[1].move(linkages[0].getOutputJoints()[0]);
			lamda = scMult.lamda;
			double[] parameters = linkages[2].getParameters();
			parameters[2] = lamda*b;
			linkages[2].setParameters(parameters);
			double t = scMult.tBar;
			double s = scMult.sBar;
			try{
				linkages[2].forceInputJoints(linkages[1].setInputJoints(inputs));
			}catch(MachineException e){
				linkages[2].forceInputJoints(linkages[1].forceInputJoints(inputs));
			}
		}
	}
	final static String def = "Scalar Multiplier around(0,0) a=";
	/**
	*@see FunctionalLinkage#getActiveStr
	*/
	public String getActiveStr(int activeJoint){
		if(activeJoint>-1){
			if (activeJoint!=2&&activeJoint!=23&&activeJoint!=13)
				return linkages[activeJoint/10].getActiveStr(-1);
			else return linkages[activeJoint/10].getActiveStr(activeJoint%10);
		}else{
			String str = lamda+"";
			str = str.substring(0,str.indexOf(dot)+2);
			return def+str;
		}
	}
	/**
	*@see FunctionalLinkage#getActiveJoint
	*/
	public int getActiveJoint(){
		   return activeJoint;
	}
	/**
	*@see FunctionalLinkage#setActiveJoint
	*/
	public void setActiveJoint(int activeJoint){
		this.activeJoint = activeJoint;
	}

}

