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

// -*-Mode: Java-*- 
// $Id: MovementCauseRecognizer.java,v 1.2 2003/03/06 00:40:43 moltmans Exp $
// MovementCauseRecognizer.java -- 
// Author: Michael Oltmans <moltmans@ai.mit.edu> 
// Created: <Fri Apr 14 11:15:25 2000> 
// Time-stamp: <2000-04-18 16:23:29 moltmans> 
package rec.annotate.recognizers;

import java.util.*;
import rec.sys.*;
import rec.core.*;
import rec.core.widgets.*;
import rec.util.*;
import rec.simulate.widgets.*;
import rec.annotate.*;
import rec.annotate.widgets.*;

public class MovementCauseRecognizer extends Recognizer implements Command
{

  public boolean recognize( Surface s, Widget w )
  {
    WAnnotation wa = (WAnnotation)w;
    MovementAnnotation effect = (MovementAnnotation)wa.getAnnotation();
    AnnotationNotebook book = s.getAnnotationNotebook();

    DebugWindow.addLine( "MO", "find cause of: " + effect );

    // if there is already a cause, don't bother
    if( effect.getCause() != null )
      return false;

    LinkedList adjusters = new LinkedList();
    Adjuster adjuster = null;

    adjuster = causedBySpring( effect );
    if( adjuster != null ) {
      adjusters.add( adjuster );
    }
    
    // get potential causing events
    LinkedList events = book.getEvents();
    Iterator it = events.iterator();
    int counter = 0;
    while ( it.hasNext() && counter < 3) {
      counter++;
      Annotation cause = (Annotation)it.next();

      if( cause instanceof MovementAnnotation ) {
	adjuster = causedByMovement( (MovementAnnotation)cause, effect );
	if( adjuster != null ) {
	  adjusters.add( adjuster );
	}
      }
    }

    it = adjusters.iterator();
    while( it.hasNext() ) {
      adjuster = (Adjuster)it.next();
      WCommand wadjuster = new WCommand( this, adjuster );
      s.replaceWidget( w, wadjuster );
    }

    return false;
  }

  public void performAction( Surface s, Object arg ) 
  {
    DebugWindow.addLine( "MO", "Adjusting: " + arg );

    Adjuster adjuster = (Adjuster)arg;
    Annotation cause = adjuster.getCause();
    Annotation effect = adjuster.getEffect();
    cause.setEffect( effect );
    effect.setCause( cause );
    adjuster.adjust();
  }
  
  public void performUndo( Surface s, Object arg ) 
  {
    Assert.error( "Can't undo causes just yet!" );
  }
    
  protected Adjuster causedBySpring( MovementAnnotation effect ) 
  {
    return effect.getAdjuster();
//      SpringAdjuster adjuster = new SpringAdjuster( effect );
//      if( adjuster.hasSpring() ) {
//        return adjuster;
//      }
//      return null;
  }

  protected Adjuster causedByMovement( MovementAnnotation cause,
				       MovementAnnotation effect ) 
  {
    SpatialWidget w = (SpatialWidget)effect.getMovee().getWidget();
    if( cause.getArrow().intersects( w ) ) {
      Adjuster adjuster = cause.getAdjuster();
      if( adjuster == null )
	return null;
      adjuster.setGoal( effect );
      return adjuster;
    }
  
    return null;
  }

  protected Adjuster causedByExternalForce( MovementAnnotation a ) 
  {
    //    return new PathAdjuster( a );
    return null;
  }
  
  public Iterator getInputTypes()
  {
    Vector v = new Vector();

    v.addElement( "rec.annotate.widgets.WMovementAnnotation" );

    return( v.iterator() );
  }

  public Iterator getOutputTypes()
  {
    Vector v = new Vector();
    v.addElement( "rec.core.widgets.WCommand" );
    v.addElement( "rec.annotate.widgets.WMovementAnnotation" );

    return( v.iterator() );
  }
}


