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

package rec.simulate.widgets;
// -*-Mode: Java-*- 
// WSimPart.java -- 
// Author: Christine Alvarado <calvarad@ai.mit.edu> 
// Maintainer: Christine Alvarado <calvarad@ai.mit.edu> 
// Version: 
// Created: <Mon Apr 19 16:48:43 1999> 
// Time-stamp: <2000-05-23 21:07:08 moltmans> 
// Keywords: 

import rec.sys.*;
import rec.geo.*;
import rec.util.*;
import java.util.*;
import java.awt.Graphics;
import java.awt.Rectangle;


public abstract class WSimConstraint extends WSimObject
{
  protected GShape[] m_Components;
  protected double m_Size;
  //protected GPoint m_Center;
  protected double m_Angle;
  
  public abstract boolean attach( WSimBody b );
  public abstract GPoint getAttachmentPoint( WSimBody b );
  public abstract void detach();
  public abstract int numAttached();
  public abstract List getBodies();

  public WSimConstraint()
  {
    setDefaultColor( "sim_constraint" );
    m_Components = null;
    m_Size = 0;
    //m_Center = null;
    m_Angle = 0;
  }

  protected GShape[] copyComponents( GShape[] comp )
  {
    GShape[] ret = new GShape[comp.length];
    for( int i = 0; i < comp.length; ++i ) {
      ret[i] = (GShape)comp[i].clone();
    }
    
    return ret;
  }
  
  public double size()
  {
    return m_Size;
  }

  public double angle()
  {
    return m_Angle;
  }
  
  public void resize( double scaleFactor )
  {
    // ada: added resize method.
    // scale all the components and update their sizes
    for( int i = 0; i < m_Components.length; ++i ) {
      m_Components[i].resize(scaleFactor);
      m_Size = m_Size * scaleFactor;
    }
  }

  public void move( GPoint p )
  {
    GPoint center = getLocation().getCenter();

    for( int i = 0; i < m_Components.length; ++i ) {
      m_Components[i].translate( center, p );
    }

  }

  public void rotate( GPoint p, double angle )
  {
    for( int i = 0; i < m_Components.length; ++i ) {
      m_Components[i].rotate( p, Radian.reduce( angle ) );
    }

    // ada: fixed code to correctly update the angle 
    m_Angle = Radian.reduce( m_Angle - angle );
  }

  public Location getLocation()
  {
    return( new Location( getBounds() ) );
  }

  public Rectangle getBounds()
  {
    Rectangle r = m_Components[0].getBounds();

    // Top left corner point.
    int tlx = r.x;
    int tly = r.y;

    // Bottom right corner point.
    int brx = r.x + r.width;
    int bry = r.y + r.height;

    for( int i = 1; i < m_Components.length; ++i ) {

      r = m_Components[i].getBounds();

      tlx = Math.min( tlx, r.x );
      tly = Math.min( tly, r.y );
      brx = Math.max( brx, r.x + r.width );
      bry = Math.max( bry, r.y + r.height );
    }

    return( new Rectangle( tlx, tly, brx - tlx, bry - tly ) );
  }


  public void draw( Graphics g )
  {
    //    g.setColor( getColor() );

    for( int i = 0; i < m_Components.length; ++i ) {
      m_Components[i].display( g );
    }
  }

    //public Color getColor( )
    //{
    //Color c = Colors.getColor( "sim_constraint" );

    //if ( c == null )
    //  return super.getColor();

    //return c;
    //}

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

  public boolean includes( GPoint p, double offset )
  {
    for( int i = 0; i < m_Components.length; ++i ) {
      if( m_Components[i].includes( p, offset ) )
	return( true );
    }

    return( false );
  }

  /**
   * care should be taken to override this since contains is not as
   * compositional as includes.  It should return true if the point is
   * in the region defined byt the constraint.
   **/
  public boolean contains( GPoint p )
  {
    for( int i = 0; i < m_Components.length; ++i ) {
      if( m_Components[i].contains( p ) )
	return( true );
    }

    return( false );
  }

  ///////////////////////////////////////////////////////////////////////////
}

