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

// -*-Mode: Java-*- 
// WSimSpring.java -- 
// Author: Christine Alvarado <calvarad@ai.mit.edu> 
// Maintainer: Christine Alvarado <calvarad@ai.mit.edu> 
// Version: 
// Created: <Sat Apr 17 18:40:32 1999> 
// Time-stamp: <2001-09-10 18:31:04 moltmans> 
// Keywords: 
package rec.simulate.widgets;

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

public abstract class WSimSpring extends WSimConstraint
{
  
  protected WSimBody m_headBody;
  protected WSimBody m_tailBody;

  protected double m_restLength = Double.NaN;

  public WSimSpring( WMSpring s )
  {
    setDefaultColor( "spring", "sim_constraint" );
    setEnglishName( "Spring" );
    m_Components = copyComponents( s.getComponents() );
    m_Size = s.size();
    m_Angle = s.getAngle();
    m_Name = "Spring" + getId();
    m_headBody = null;
    m_tailBody = null;
  }
  
  public GPoint getHead()
  {
    return( ((GSegment)m_Components[0]).getHeadPoint() );
  }

  public GPoint getTail()
  {
    return( ((GSegment)m_Components[10]).getTailPoint() );
  }

  public WSimBody getHeadBody() 
  {
    return m_headBody;
  }

  public WSimBody getTailBody()
  {
    return m_tailBody;
  }
  
  public double getLength() 
  {
    return Geometry.distance( getHead(), getTail() );
  }

  public double getRestLength()
  {
    if( Double.isNaN( m_restLength ) )
      m_restLength = getLength();
    return m_restLength;
  }

  public void adjustSpringRestLength(double percent)
  {
    setRestLength(percent * getLength());
  }
      
  public void setRestLength( double restLength ) 
  {
    m_restLength = restLength;
  }

  public void makeInCompression()
  {
    m_restLength  = m_restLength * 0.8;
  }

  public void makeInTension()
  {
    m_restLength = m_restLength * 1.2;
  }

  public void makeAtRest()
  {
    resetRestLength();
  }

  public void resetRestLength() 
  {
    m_restLength = getLength();
  }

  /** check to see if we can attach this spring to the body **/
  public boolean attach( WSimBody b )
  {

    // check to see if head is touching or inside the body
    if ( b.includes( getHead(), 10 ) || b.contains( getHead() ) ) {
      Assert.check( m_headBody == null,
		    "Spring has two bodies at it's head" );
      m_headBody = b;
      return true;
    }
    
    // check to see if tail is touching or inside the body
    if ( b.includes( getTail(), 10 ) || b.contains( getTail() ) ) {
      Assert.check( m_tailBody == null,
		    "Spring has two bodies at it's tail" );
      m_tailBody = b;
      return true;
    }

    return false;
  }

  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 getHead();
    else if( body.equals( m_tailBody ) )
      return getTail();
    else
      return null;
  }

  ////////////////////////////////////////////////////////////////////
  
  /**
   * @return true if the body at the head is immobile.
   **/
  public boolean isHeadRigid() 
  {
    return isFixed( getHeadBody() );
  }
  /**
   * @return true if the body at the tail is immoblie.
   **/
  public boolean isTailRigid() 
  {
    return isFixed( getTailBody() );
  }

  
  protected boolean isFixed( WSimBody b )
  {
    if( b == null )
      return true;
    else
      return b.isAnchored();
  }

  ////////////////////////////////////////////////////////////////////

  
  public Collection isa()
  {
    Class c = ClassFinder.find( "rec.simulate.widgets.WSimSpring" );
    Collection types = super.isa();
    types.add( c );
    
    return types;
  }



  /*  public Color getColor( )
  {

    Color c = super.getColor();

    //    Console.writeln( "snarf color : " + c );

    if ( c == null )
      return Colors.getColor( "spring" );
  */

  
}
