// (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.*;

import edu.mit.sketch.geom.GeneralPath;


public abstract class WSimRope extends WSimConstraint
{

    public WSimRope( VisibleWidget v )
    {

	Assert.check( (v instanceof WComplex) ||
		      (v instanceof WLine),
		      "Ropes must be made out of Lines or Complexes!");
	

	setDefaultColor( "rope", "sim_constraint" );
	setEnglishName( "Rope" );
	m_Components = new GShape[1];

	if(v instanceof WComplex){
	    WComplex c = (WComplex) v;
	    m_Components[0] = (GComplex) c.getComplexShape().copy();
	}
	else if (v instanceof WLine){
	    WLine l = (WLine) v;
	    m_Components[0] = l.getLine();
	}

	m_Name = "Rope" + getId();
	
	m_complex = true;
    }


    public WSimRope( WComplex c )
    {
	setDefaultColor( "rope", "sim_constraint" );
	setEnglishName( "Rope" );
	m_Components = new GShape[1];

	GComplex complex = (GComplex) c.getComplexShape().copy();

	m_Components[0] = complex;
	m_Name = "Rope" + getId();
	
	m_complex = true;
    }

    public WSimRope( WLine l )
    {	
	setDefaultColor( "rope", "sim_constraint" );
	setEnglishName( "Rope" );
	m_Components = new GShape[1];

	m_Components[0] = l.getLine();
	m_Name = "Rope" + getId();

	m_complex = false;
    }

    public boolean attach( WSimBody b )
    {
	if ( ( m_headBody != null ) && ( m_tailBody != null ) ) {
	    Console.writeln( "Rod already attached to two bodies.  Cannot attach to body" + b.getName() );
	    return false;
	}
	// check to see if one of the ends is touching or inside the body in 
	// question.
	// the offset is set to 10, meaning the end must be pretty close to 
	// the body
	if ( m_headBody == null ) {
	    if ( b.includes( getHeadPoint(), 10 ) || 
		 b.contains( getHeadPoint(), 0 ) ) {
		m_headBody = b;
		return true;
	    }
	}
	if ( m_tailBody == null ) {
	    if ( b.includes( getTailPoint(), 10 ) || 
		 b.contains( getTailPoint(), 0 ) ) {
		m_tailBody = b;
		return true;
	    }
	}
	return false;
    
    }

    public GPoint getHeadPoint() 
    {
	if(m_Components[0] instanceof GComplex){
	    return ((GComplex)m_Components[0]).getStartPoint();
	}
	else{
	    return ((GSegment)m_Components[0]).getHeadPoint();
	}
    }

    public GPoint getTailPoint() 
    {
	if(m_Components[0] instanceof GComplex){
	    return ((GComplex)m_Components[0]).getEndPoint();
	}
	else{
	    return ((GSegment)m_Components[0]).getTailPoint();
	}
    }

    public void detach() 
    {
	m_headBody = null;
	m_tailBody = null;
    }

    public int numAttached()
    {
	int count = 0;
    
	if ( m_headBody != null ) {
	    count++;
	}
	if ( m_tailBody != null ) {
	    count++;
	}
	return count;
    }

    public List getBodies() 
    {
	List list = new ArrayList( numAttached() );
	if( m_headBody != null )
	    list.add( m_headBody );
	if( m_tailBody != null )
	    list.add( m_tailBody );
	return list;
    }

    public GPoint getAttachmentPoint( WSimBody body ) 
    {
	if( body.equals( m_headBody ) )
	    return getHeadPoint();
	else if( body.equals( m_tailBody ) )
	    return getTailPoint();
	else
	    return null;
    }

    public void move(GPoint p){
	
	if(m_Components[0] instanceof GComplex){
	    ((GComplex)m_Components[0]).translate(p.getX(), p.getY());
	}
	else{
	    super.move(p);
	}
    }

    public WSimBody getHeadBody() 
    {
	return m_headBody;
    }

    public WSimBody getTailBody() 
    {
	return m_tailBody;
    }

    public double getLength(){
	if(m_Components[0] instanceof GSegment){
	    return ((GSegment) m_Components[0]).getLength(); 
	}

	if(m_Components[0] instanceof GComplex){
	    return ((GComplex) m_Components[0]).getLength(); 
	}
	else{
	    return 0;
	}
    }

    public GShape getGeo(){
	return (GShape) m_Components[0];
    }
    
    public Collection isa()
    {
	Class c = null;
	try {
	    c = Class.forName( "rec.simulate.widgets.WSimRope" );
	}
	catch( ClassNotFoundException e ) {

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

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

  
    protected WSimBody m_headBody;
    protected WSimBody m_tailBody;
    protected boolean m_complex;
}
