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

package rec.fsm;


import rec.core.*;

import java.awt.*;
import java.util.*;
import rec.core.*;
import rec.sys.*;
import rec.util.*;
import rec.geo.*;


public class CircleArranger extends Aligner
{

  public CircleArranger()
  {
  }
  
  /**
   * Each new stroke generated gets put into the pipe here.  It will
   * remove and add objects to the 'out' target as it deems fit.
   *
   * @return true if changes were made
   */
  public boolean recognize( Surface s, Widget w )
  {
    //Console.writeln( "Checking overlap of " + w );

    //    trans = new MultiTransition( s );
    boolean ignore = noCircleOverlap( s, (WCircle)w );
    return false;
  } // end recognizeThing

  public Iterator getInputTypes()
  {
    Vector v = new Vector();

    v.addElement( "rec.core.WCircle" );
    //    v.addElement( "rec.fsm.Node" );

    return v.iterator();
  }

  public Iterator getOutputTypes( )
  {
    Vector v = new Vector();

    v.addElement( "rec.core.WCircle" );
    //    v.addElement( "rec.core.Node" );

    return v.iterator();
  }




  /**
   * Check circle against all others and move apart if needed.
   */
  boolean noCircleOverlap( Surface b, WCircle c )
  {
    // hash of MoveTransitions
    Hashtable transTab = new Hashtable();
    MoveTransition main_t = null;

    Iterator e;
    Vector loops = new Vector();

    e = b.getWidgetsIterator();
    //Console.writeln( "Main Looking at " + c );

    while ( e.hasNext() )
      {
	Object o = e.next();
	//Console.writeln( "Looking at " + o );
	if ( ( o instanceof rec.core.WCircle ) && (! c.equals( o ) ) )
	{
	  //Console.writeln( "Adding " + o + " to loop list." );
	  loops.addElement( o );
	}
      }
    //Console.writeln( "Loops: " + loops );

    boolean changed = true;
    
    while( changed )
      {
	changed = false;

	e = loops.iterator();
	while( e.hasNext() )
	  {
	    WCircle c2 = (WCircle)e.next();

	    int amount;
	    if ( ( amount = overlap( c, c2 ) ) > -5 )
	      {
		//Console.writeln( "Overlap of " + amount );
		GPoint ce1, ce2;
		ce1 = c.getCenter();
		ce2 = c2.getCenter();
		int dx = (int)(ce1.x - ce2.x);
		int dy = (int)(ce1.y - ce2.y);
		
		amount += 10;
		if ( ( dx == 0 ) && ( dy == 0 ) )
		  dx = 1;
		  
		int l = 2 * (int)( Math.sqrt( dx * dx + dy * dy ) );

		c.translate( dx * amount / l, dy * amount / l );
		main_t = moveIt( b, c, main_t,
				 dx * amount / l, dy * amount / l );

		MoveTransition mt = (MoveTransition)transTab.get( c2.getId() );
		mt = moveIt( b, c2, mt, -dx * amount / l, -dy * amount / l );
		transTab.put( c2.getId(), mt );

		changed = true;
	      }
	  }
      }

    if ( main_t != null )	// we had some movement!
      {
	// add and remove the objects from the board all at once
	//Console.writeln( "Collecting all move transitions" );

	e = transTab.values().iterator();
	while( e.hasNext() )
	  {
	    MoveTransition t =  (MoveTransition)e.next();

	    b.alterWidget( t.getTargetWidget(), t, true );
	  }

	b.alterWidget( c, main_t );

	return true;
      }

    // no changes made.
    return false;
  }


  MoveTransition moveIt( Surface surf,
			 WCircle circ,
			 MoveTransition old_tr, 
			 double dx, double dy )
 {
   GPoint prev = circ.getCenter();
   circ.translate( dx, dy );

   if ( old_tr != null )
     prev = old_tr.getOldLocation();
   
   old_tr = new MoveTransition( surf, circ, 
				prev, circ.getCenter() );

   return old_tr;
 }

  int overlap( WCircle c, WCircle c2 )
  {
    return (int)( ( c.getRadius() + c2.getRadius() ) 
                  - Geometry.distance( c.getCenter(), c2.getCenter() ) );
  }

}
