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

// $Id: SpringAdjuster.java,v 1.2 2003/03/06 00:40:48 moltmans Exp $
// SpringAdjuster.java -- 
// Author: Michael Oltmans <moltmans@ai.mit.edu> 
// Created: <Sat Jul 22 20:31:49 2000> 
// Time-stamp: <2001-03-09 15:53:35 moltmans> 
package rec.annotate.rules;

import rec.sys.*;
import rec.util.*;
import rec.geo.*;
import rec.simulate.widgets.*;
import rec.core.widgets.WSquiggleArrow;
import java.util.Iterator;
import java.awt.Rectangle;


/**
 * This class helps springs set their parameters such that they can
 * achieve their desired effects.
 **/
public class SpringAdjuster
{
  /**
   * Set the rest length so that it moves the mover in the direction
   * indicated by the arrow far enough that it hits movee.
   **/
  protected static double getRestLength( WSimSpring spring, WSimBody mover,
					 WSimBody movee, WSquiggleArrow arrow )
  {
    // verify attachment of mover to spring
    if( !mover.getConstraints().contains( spring ) ) {
      Assert.error("Spring not connected to body: " + spring + " " + mover);
    }
    
    double restLength;
    double compression = getCompression( spring, mover, arrow );
	
    Rectangle b1 = movee.getBounds();
    Rectangle b2 = mover.getBounds();

    // if they intersect just do what getCompression does
    if( b1.intersects( b2 ) ) {
      restLength = spring.getLength() * compression;
    }
    else {
      double dist = Geometry.distance( movee.getLocation().getCenter(),
				       mover.getLocation().getCenter() );
      if( compression > 0 )
	restLength = spring.getLength() + dist;
      else
	restLength = spring.getLength() - dist;
    }
    
    return restLength;
  }

//    /**
//     * Set the rest length so that it moves the body in the direction
//     * indicated by the arrow.
//     **/   
//    protected static void setRestLength( WSimSpring spring, WSimBody movee,
//  				       WSquiggleArrow arrow ) 
//    {
//      // verify attachment of movee to spring
//      if( !movee.getConstraints().contains( spring ) ) {
//        return;
//      }
    
//      double compression = getCompression( spring, movee, arrow );
    
//      spring.setRestLength( spring.getLength() * compression );
//    }
  
  /**
   * Check if the arrow points in the same direction as angle.
   * (within PI/4 degrees in either direction.
   *
   * @return -1 if in tension.
   *          0 if at rest.
   *          1 if in compression.
   **/
  public static int getCompression( WSimSpring spring,
				       WSimBody body,
				       WSquiggleArrow arrow ) 
  {
    DebugWindow.addLine("Java", "getCompression( " + spring + " " +
			body + " " + arrow + ");");
    double angle = 0.0;
    if( body.equals( spring.getHeadBody() ) ) {
      angle = Geometry.angle( spring.getTail(),
			      spring.getHead() );
    }
    else if( body.equals( spring.getTailBody() ) ) {
      angle = Geometry.angle( spring.getHead(),
			      spring.getTail() );
    }
    else {
      Assert.error( "Calling setCompression with bad body" );
    }

    double diff = Math.abs( angle - arrow.getTailAngle() );

    if( Radian.isBetween( -0.25 * Math.PI, 0.25 * Math.PI, diff ) ) {
      return 1;
    }
    else if( Radian.isBetween( 0.75 * Math.PI, 1.25 * Math.PI, diff ) ) {
      return -1;
    }

    return 0;
  }

  public static WSimSpring findSpringAttachedTo( Widget w )
  {
    if( (w != null) && (w instanceof WSimBody) ) {
      Iterator it = ((WSimBody)w).getConstraints().iterator();

      while( it.hasNext() ) {
	WSimConstraint constraint = (WSimConstraint)it.next();
	if( constraint instanceof WSimSpring ) {
	  return(WSimSpring)constraint;
	}
      }
    }
    return null;
  }

}
