/**
  *
  * See the end of the file for the log of changes.
  *
  * $Author: mtsezgin $
  * $Date: 2000/06/03 01:52:33 $
  * $Revision: 1.9 $
  * $Headers$
  * $Id: Motor.java,v 1.9 2000/06/03 01:52:33 mtsezgin Exp $
  * $Name:  $
  * $Locker:  $
  * $Source: /mit/mtsezgin/CVS/Repository/REC/Motor.java,v $
  *
  **/


import java.awt.Color;
import java.awt.Graphics;

import java.util.Vector;

/**
  *
  * A basic motor with a body and a rotor
  *
  **/

class      Motor
implements Rotatable,
           NonTerminal
{
    /**
    *
    * Original body of the motor.
    *
    **/
    private Rectangle body;
    
    /**
    *
    * Original rotor of the motor.
    *
    **/
    private Line rotor;
    
    /**
    *
    * Modified rotor of the motor to be parallel to major axis.
    *
    **/
    private Line new_rotor;
    
    /**
    *
    * Rotor length of the rotor.
    *
    **/
    private int rotor_length;
    
    /**
    *
    * Angle that the line from the center of the body to the tip 
    * rotor makes with the x axis.
    *
    **/
    private double relative_rotor_angle;
    
    /**
    *
    * The position of the tip relative to the center of the body.
    *
    **/
    private Point tip_position;
    
    /**
    *
    * children
    *
    **/
    private Vector children;

    /**
    *
    * Graphics context for this Geometric object.
    *
    **/
    public Graphics graphics;
    
    
    /**
    *
    * The constructor.
    *
    **/    
    Motor( Rectangle body, Line rotor )
    {
        this.body    = body;
        this.rotor   = rotor;
        rotor_length = (int)Point.distance( rotor.x1, rotor.y1, 
                                            rotor.x2, rotor.y2 );
        
        Point center = body.getCenter();
        
        if ( Point.distance( center.x, center.y, rotor.x1, rotor.y1 ) > 
             Point.distance( center.x, center.y, rotor.x2, rotor.y2 ) ) {
            tip_position = new 
                Point( ((int)rotor.x1), ((int)rotor.y1) );
        } else {
            tip_position = new         
                Point( ((int)rotor.x2), ((int)rotor.y2) );
        }
        
        relative_rotor_angle  = Math.atan2( tip_position.y, tip_position.y );
        
        int    major_axis_length = (int)body.getMajorAxisLength();
        double major_axis_angle  = body.getMajorAxisAngle();
        Point  new_rotor_tip1    = new 
            Point( (int)(center.x + Math.cos( major_axis_angle )*
                   (major_axis_length/2 + rotor_length   )), 
                   (int)(center.y + Math.sin( major_axis_angle )*
                   (major_axis_length/2 + rotor_length   )) );
        Point  new_rotor_tip2    = new 
            Point( (int)(center.x + Math.cos( major_axis_angle-Math.PI )*
                   (major_axis_length/2 + rotor_length   )), 
                   (int)(center.y + Math.sin( major_axis_angle-Math.PI )*
                   (major_axis_length/2 + rotor_length   )) );
        if ( tip_position.distance( new_rotor_tip1 ) <
            tip_position.distance( new_rotor_tip2 ) ) {
            tip_position = new_rotor_tip1; 
            new_rotor    = new 
                Line( (int)(center.x + Math.cos( major_axis_angle )*
                            major_axis_length/2),
                      (int)(center.y + Math.sin( major_axis_angle )*
                            major_axis_length/2),
                      tip_position.x,
                      tip_position.y );
        } else {
            tip_position = new_rotor_tip2; 
            new_rotor    = new 
                Line( (int)(center.x + Math.cos( major_axis_angle-Math.PI )*
                            major_axis_length/2),
                      (int)(center.y + Math.sin( major_axis_angle-Math.PI )*
                            major_axis_length/2),
                      tip_position.x,
                      tip_position.y );
        }
        
        children = new Vector();
        
        children.addElement( body  );
        children.addElement( rotor );
    }

    /**
    *
    * Returns the angle of the motor WRT the x axis in radians.
    * This should be made more general by adding an angle field 
    * to the class.
    * 
    **/
    public double
    getAngle()
    {
        return relative_rotor_angle;
    }


    /**
    *
    * Draw the Motor
    *
    **/
    public void
    paint()
    {
        if ( graphics == null ) // Draw only if g
            return;             // is valid
        graphics.setColor( Color.black );
        body.paint( graphics );
        new_rotor.paint( graphics );
    }


    /**
    *
    * Draw the Motor
    *
    **/
    public void
    paint( Graphics g )
    {
        body.paint( g );
        new_rotor.paint( g );
    }
    
    
    /**
    *
    * This method is used to paint the original data points that
    * forms this GeometricObject
    *
    **/
    public void
    paintOriginal( Graphics g )
    {
        body.paintOriginal( g );
        rotor.paintOriginal( g );
    }


       /**
    *
    * Set graphics context for this Motor object.
    * Must be set at least once before doing any drawing.
    *
    **/
    public void
    setGraphicsContext( Graphics g )
    {
        graphics = g;
    }


    /**
    *
    * Implement Paintable
    *
    **/    
    public String
    getType()
    {
        return "motor";
    }
    
    
    /**
    *
    * This method should return the Rectangular bounds of this 
    * non-terminal object.
    *
    **/
    public Rectangle
    getRectangularBounds()
    {
        return body.union( rotor.getRectangularBounds() );
    }
    
    
    /**
    *
    * This method should return the polygonal array bounds of this 
    * non-terminal object. This is a rough approximation of the
    * constituents of the object. 
    *
    **/
    public Polygon[]
    getPolygonalBoundsArray()
    {
        Polygon[] polygonal_bounds_array = new Polygon[2];
        
        polygonal_bounds_array[0] = body.getPolygonalBounds();
        polygonal_bounds_array[1] = rotor.getPolygonalBounds();
        
        return polygonal_bounds_array;
    }
    
    
    /**
    *
    * This method should return a vector containing the children of 
    * this object. Children are the Terminal or NonTerminal 
    * constituents of this object.
    *
    **/
    public Vector
    getChildren()
    {
        return children;
    }
}
