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

package rec.simulate.widgets;
// -*-Mode: Java-*- 
// WSimPinJoint.java -- 
// Author: Christine Alvarado <calvarad@ai.mit.edu> 
// Maintainer: Christine Alvarado <calvarad@ai.mit.edu> 
// Version: 
// Created: <Fri Jun  4 14:15:01 1999> 
// Time-stamp: <2001-09-10 18:30:17 moltmans> 
// Keywords: 

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

public abstract class WSimPinJoint extends WSimConstraint
{

  public WSimPinJoint( WSimCircle c )
  {
    setDefaultColor( "pin", "sim_constraint" );
    setEnglishName( "Pin Joint" );

    double radius = 10.0;
    m_body1 = null;
    m_body2 = null;

    m_Components = new GShape[1];
   
    m_Components[0] = new GCircle( c.getCenter(), radius );

    m_Name = "PinJoint" + getId();
  }

  public boolean attach( WSimBody b )
  {
    if( (m_body1 != null) && (m_body2 != null) ) {
      Console.writeln( "Joint already attached to two bodies." );
      return false;
    }
    // if the joint 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();
      
  }

  public WSimBody getBody1() 
  {
    return m_body1;
  }

  public WSimBody getBody2()
  {
    return m_body2;
  }
  

  public Collection isa()
  {
    Class c = null;
    try {
      c = Class.forName( "rec.simulate.widgets.WSimPinJoint" );
    }
    catch( ClassNotFoundException e ) {

      Assert.error( "bad/unrecognized widget class name" );
    }

    Collection types = super.isa();
    types.add( c );
    
    return types;

  }


  protected WSimBody m_body1;
  protected WSimBody m_body2;
     
}
