/**
  *
  * See the end of the file for the log of changes.
  *
  * $Author: mtsezgin $
  * $Date: 2000/05/07 17:27:58 $
  * $Revision: 1.1 $
  * $Headers$
  * $Id: Pin.java,v 1.1 2000/05/07 17:27:58 mtsezgin Exp $
  * $Name:  $
  * $Locker:  $
  * $Source: /mit/mtsezgin/CVS/Repository/REC/Pin.java,v $
  *
  **/


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

/**
  *
  * A basic Spring
  *
  **/

class   Spring
extends Rectangle
{    

    /**
    *
    * The number of loops that the spring makes.
    *
    **/    
    int loops;


    /**
    *
    * The polygon that was used to construct the spring.
    *
    **/    
    Polygon polygon;
    
    /**
    *
    * End points of the spring stored in a line.
    *
    **/    
    Line end_points;
    
    
    /**
    *
    * The constructor constructs a spring that is approximated by 
    * the input polygon.
    *
    **/    
    Spring( Polygon polygon )
    {
        super( polygon.getRectangularBounds() );
        this.polygon = polygon;
        loops        = polygon.npoints/2;
        setDataPoints( polygon.getDataPoints() );
        end_points = new 
            Line( polygon.xpoints[0],
                  polygon.ypoints[0],
                  polygon.xpoints[polygon.npoints-1],
                  polygon.ypoints[polygon.npoints-1] );

    }


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


    /**
    *
    * Returns true if the input polygon looks like a Spring. 
    *
    **/
    public static boolean
    isSpring( Polygon polygon )
    {
        if ( polygon.npoints < 5 )
            return false;
            
        Rectangle bounds = polygon.getRectangularBounds();

        Line line = new 
            Line( bounds.x + 
                  bounds.getMinorAxisLength()*
                      Math.cos( bounds.getMinorAxisAngle() )/2,
                      
                  bounds.y + 
                  bounds.getMinorAxisLength()*
                      Math.sin( bounds.getMinorAxisAngle() )/2,
                      
                  bounds.x +
                  bounds.getMinorAxisLength()*
                      Math.cos( bounds.getMinorAxisAngle() )/2 +
                  bounds.getMajorAxisLength()*
                      Math.cos( bounds.getMajorAxisAngle() ),
                      
                  bounds.y + 
                  bounds.getMinorAxisLength()*
                      Math.sin( bounds.getMinorAxisAngle() )/2 +
                  bounds.getMajorAxisLength()*
                      Math.sin( bounds.getMajorAxisAngle() ) );
                   
        Tablet.debug_graphics.setColor( Color.red );
        line.paint( Tablet.debug_graphics );                               
        
        // evens true if we have a ccw turn for the 0th point
        int     ccw    = 0;  // Reminiscent of the old cwcc
        int     errors = 0;
        boolean evens  = line.relativeCCW( polygon.xpoints[0], 
                                           polygon.ypoints[0] ) == 1;
        boolean odds   = !evens;
        for ( int i=0; i<polygon.npoints; i++ ) {
            if ( line.relativeCCW( polygon.xpoints[i], 
                                   polygon.ypoints[i] ) == 1 ) {
                System.out.println( "Spring  ++ " );
                if ( ( ( i%2 == 0 ) && odds  ) || 
                     ( ( i%2 == 1 ) && evens ) ) {
                    errors++;
                    if ( errors > 1 )
                        return false;  // Wrong alternation
                }
                ccw++;
            } else {
                System.out.println( "Spring  -- " );
                if ( ( ( i%2 == 0 ) && evens ) || 
                     ( ( i%2 == 1 ) && odds  ) ) {
                    errors++;
                    if ( errors > 1 )
                        return false;  // Wrong alternation
                }
                ccw--;
            }
        }
        
        System.out.println( "Got a spring, ccw = " + ccw );
        
        return true;
    }


    /**
    *
    * Draw the Spring
    * Can be made faster by incrementing theta in larger chunks.
    *
    **/
    public void
    paint( Graphics g )
    {
        int radius = (int)getMinorAxisLength()/2;
        
        double x;
        double y;
        double old_x  = end_points.x1;
        double old_y  = end_points.y1;
        double length = end_points.length();
        double angle  = Math.atan2( end_points.y2-end_points.y1, 
                                    end_points.x2-end_points.x1 );
        double distance;
        double oscilation_angle;

        for ( int i=0; i<loops; i++ ) {
            for ( int theta=0; theta<360; theta++ ) {
                x = length*i/((double)loops) + 
                        GeometryUtil.degree2radian( theta )*
                            length/loops/Math.PI/2;
                y = radius*Math.sin(
                        GeometryUtil.degree2radian( theta ));

                distance         = Point.distance( 0, 0, x, y );
                oscilation_angle = Math.atan2( y, x ) + angle;
                // Oscilation angle is the final angle of the point
                // WRT the x axis for drawing.
                x = end_points.x1 + distance*Math.cos( oscilation_angle );
                y = end_points.y1 + distance*Math.sin( oscilation_angle );

                g.drawLine( (int)old_x, (int)old_y, (int)x, (int)y );
                
                old_x = x;
                old_y = y;
            }
        }
    }


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


    /**
    *
    * Implement Paintable 
    *
    **/    
    public String
    getType()
    {
        return "spring";
    }
    
    
    /**
    *
    * This method is used to paint the original data points that
    * forms this GeometricObject
    *
    **/
    public void
    paintOriginal( Graphics g )
    {
        super.paintOriginal( g );
    }
    
    
    /**
    *
    * This method should return the Rectangular bounds of this 
    * non-terminal object.
    *
    **/
    public Rectangle
    getRectangularBounds()
    {
        return super.getRectangularBounds();
    }
}
