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

package rec.simulate.widgets;

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

public abstract class WSimMotor extends WSimConstraint
{

  public WSimMotor( GPoint center)
  {
      setDefaultColor( "motor", "sim_constraint" );
      m_body1 = null;
      setEnglishName( "Motor" );
      double radius = 10.0;
      
      m_Components = new GShape[2];
      m_Components[0] = new GCircle(new GPoint(0,0), radius);
      
      GPoint[] arrPoints = new GPoint[4];
      
      // Build Trapazoid Base

 
      arrPoints[0] = new GPoint(1.5*radius, radius);
      arrPoints[1] = new GPoint(3*radius, 2.5*radius);
      arrPoints[2] = new GPoint(-3*radius, 2.5*radius);
      arrPoints[3] = new GPoint(-1.5*radius, radius);
      
      m_Components[1] = new GPolygon(arrPoints);

      
      move( center );
      
      m_Name = "Motor" + getId();
      
  }

  // the motor can be attached to one or two bodies
    public boolean attach( WSimBody b )
    {
	if( (m_body1 != null) && (m_body2 != null) ) {
	    Console.writeln( "Motor already attached to two bodies." );
	    return false;
	}
	// if the motor is somewhere inside the body return true
	if ( b.contains( getLocation().getCenter(), 0 ) ) {
	    if ( m_body1 == null ) {
		m_body1 = b;
		return true;
	    }
	    else {
		m_body2 = b;
		return true;
	    }
	}
	// otherwise if it is along one of the edges return true
	if ( b instanceof WSimCircle ) {
	    if ( ((GCircle)m_Components[0]).overlaps( ((WSimCircle)b).getCircle())) {
		if ( m_body1 == null ) {
		    m_body1 = b;
		    return true;
		}
		else {
		    m_body2 = b;
		    return true;
		}
	    }
	}
	else if ( b instanceof WSimGear ) {
	    if ( ((GCircle)m_Components[0]).overlaps( ((WSimGear)b).getCircle())) {
		if ( m_body1 == null ) {
		    m_body1 = b;
		    return true;
		}
		else {
		    m_body2 = b;
		    return true;
		}
	    }
	}
	else {
	    if ( ((GCircle)m_Components[0]).overlaps( b.getPolygon() ) ) {
		if ( m_body1 == null ) {
		    m_body1 = b;
		    return true;
		}
		else {
		    m_body2 = b;
		    return true;
		}
	    }
	}
	return false;
    }
    
    public void detach() 
    {
	m_body1 = null;
	m_body2 = null;
    }
    
    public int numAttached()
    {
	int count = 0;
	if ( m_body1 != null ) {
	    count++;
	}
	if ( m_body2 != null ) {
	    count++;
	}

	return count;
	
    }
    
    public List getBodies() 
    {
	List list = new ArrayList( numAttached() );
	if( m_body1 != null )
	    list.add( m_body1 );
	if( m_body2 != null )
	    list.add( m_body2 );
	return list;
    }
    
    public GPoint getAttachmentPoint( WSimBody body ) 
    {
	if( body.equals( m_body1 )|| body.equals( m_body2  )){
	    return getAdjustedCenterPoint();
	}
	else{
	    return null;
	}
    }

    public GPoint getAdjustedCenterPoint(){
	
	double distancebody1 = Double.MAX_VALUE;
	double distancebody2 = Double.MAX_VALUE;
	
	
	if (m_body1 == null && m_body2 == null){
	    return getLocation().getCenter();
	}
	if (m_body1 != null){
	    distancebody1 = Geometry.distance(m_body1.getLocation().getCenter(),
					      getLocation().getCenter());
	}
	if (m_body2 != null){
	    distancebody2 = Geometry.distance(m_body2.getLocation().getCenter(),
					      getLocation().getCenter());
	}
	
	if (distancebody1 <= distancebody2){
	    if (distancebody1 < 10){
	      return m_body1.getLocation().getCenter();
	    }
	}
	else{
	    if (distancebody2 < 10){
		return m_body2.getLocation().getCenter();
	  }
	}
	
	return getLocation().getCenter();
      
    } 
    
    protected WSimBody m_body1;
    protected WSimBody m_body2;
    
}
