// (c) MIT 2003.  All rights reserved.

package rec.simulate.widgets.wm;

import java.util.*;
import rec.util.*;
import rec.sys.*;
import rec.core.widgets.*;
import rec.geo.*;
import rec.simulate.*;
import rec.simulate.widgets.*;

public class WMSimTorque extends WSimTorque
{
    public WMSimTorque(WToolkitArc arc, 
		       WLine line1, 
		       WLine line2, 
		       boolean clockwise ) 
    {
	super( arc, line1, line2, clockwise );
    }

    public String load( WMSimulatorRegistryBase reg ) 
    {
	GPoint newEnd1 = reg.convert( getCenter() );
	String output;
	
	if ( m_body1 != null ) {
		    
	    output = "Dim " + m_Name + " as WMConstraint\n";
	    
	    // attach the endpoints to bodies, if they are attached to bodies
	    // we assume at this point that the bodies have already been loaded
	    // otherwise this does not work.
	    
	    GPoint newBody1 = reg.convert( m_body1.getLocation().getCenter() );
	    newEnd1.x -= newBody1.x;
	    newEnd1.y -= newBody1.y;
	    
	    output += "Set " + m_Name + " = doc.NewConstraint(\"torque\")\n";
	    output +=  "Set " + m_Name + ".Point(1).Body = " + m_body1.getName() 
		+ "\n";
	    
	    double value;
	    
	    value = m_radius/100;

	    GPoint rotationalCenter = getCenterOfRotation();
	    GPoint torqueCenter = getCenter();

	    double distance = Geometry.distance(rotationalCenter, torqueCenter);

	    //System.out.println("distance is: " + distance);

	    value = value * distance/100;

	    if(m_clockwise){
		value = -value;
	    }
	    else{
		value = value;
	    }

	    //System.out.println("Value is: " + value);

	    output += m_Name + ".Torque.Value = " + value + "\n";
	    output += m_Name + ".Point(1).PX.value = " + newEnd1.x + "\n";
	    output += m_Name + ".Point(1).PY.value = " + newEnd1.y + "\n";
	    Console.writeln( "attatching " + m_Name 
			     + " to " + m_body1.getName() );
	}
    else {
	output = "";
      Console.writeln( "Torque is not in a body!" );
    }
	
	return output;
	
    }

    private GPoint getCenterOfRotation()
    {
	GeometryCalculator gc = new GeometryCalculator(getSurface());
	Iterator it = gc.getVisibleWidgets().iterator();
	Vector rotationPoints = new Vector();

	while(it.hasNext()){
	    VisibleWidget vw = (VisibleWidget)it.next();

	    if(vw instanceof WSimPinJoint ||
	       vw instanceof WSimRotationalDamper ||
	       vw instanceof WSimRotationalSpring){
		
		WSimConstraint constraint = (WSimConstraint) vw;

		List bodies = constraint.getBodies();
		

		// if there is one body, and it's this one add it to the list.
		// if there are more bodies, ignore it as it will move freely
		if (bodies.size() == 1 &&
		    ((WSimBody) bodies.get(0)).equals(m_body1)){

		    rotationPoints.add
			(constraint.getAttachmentPoint(m_body1));
		}
	    }
	}
	
	int length = rotationPoints.size();

	if(length == 1){
	    return (GPoint)rotationPoints.get(0);
	}

	// If there are more than one, it's not going to rotate anyway
	// Just use the average

	else if(length > 1){

	    double x = 0;
	    double y = 0;

	    for (int i = 0; i < length; i++){
		GPoint current = (GPoint) rotationPoints.get(i);
		
		x += current.x;
		y += current.y;

	    }
	    
	    x = x/length;
	    y = y/length;

	    return new GPoint(x,y);
	}


	else{ //rotationPoints.length == 0

	    //should be center of mass
	    return m_body1.getLocation().getCenter(); 
	}
    }
}

