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

// -*-Mode: Java-*- 
// $Id: ArrowRecognizer.java,v 1.5 2003/03/06 00:40:48 moltmans Exp $
// ArrowRecognizer.java -- 
// Author: Michael Oltmans <moltmans@ai.mit.edu> 
// Created: <Thu Mar 16 22:31:41 2000> 
// Time-stamp: <2000-03-17 12:27:17 moltmans> 
package rec.core.recognizers;

import java.util.*;

import rec.util.*;
import rec.geo.*;
import rec.sys.*;
import rec.core.widgets.*;
import rec.meche.Estimator;

public class ArrowRecognizer extends Recognizer
{

  public boolean recognize( Surface s, Widget w )
  {
    Collection litter = w.getLitter();

    if ( litter == null )
      return false;

    // throw the spark in too
    if( !litter.contains( w ) )
      litter.add( w );

    Iterator pups = litter.iterator();
    WLine stem = null;
    LinkedList lines = new LinkedList();
    double max = 0.0;

    // find the lines in the litter and keep the longest one separate
    while( pups.hasNext() ) {
      Widget pup = (Widget)pups.next();
      if ( pup instanceof WLine ) {
	lines.add( pup );
	if( ((WLine)pup).getLength() > max ) {
	  stem = (WLine)pup;
	  max = stem.getLength();
	}
      }
    }

    if( lines.size() < 3 )
      return false;


    // take out the stem since we don't want to consider in the arrow head
    lines.remove( stem );

    while( lines.size() > 1 ) {
      WLine line1 = (WLine)lines.removeFirst();

      // check if line1 goes with any other lines to make an arrow head
      Iterator it = lines.iterator();
      while( it.hasNext() ) {
	WLine line2 = (WLine)it.next();
	GSegment body = makeArrow( stem, line1, line2 );
	if( body != null ) {
	  WArrow arrow = new WArrow( body );
	  HashSet everyone = new HashSet();
	  everyone.addAll( w.getLitter() );
	  everyone.add( w );
	  s.replaceWidget( everyone, arrow, true );
	  return true;
	}
      }
    }
    return false;
  }

  private GSegment makeArrow( WLine stem, WLine l1,  WLine l2 )
  {
    GSegment s1 = l1.getLine();
    GSegment s2 = l2.getLine();
    double delta = s1.getLength() / 5.0;
    
    if( Estimator.isSameSize( s1.getLength(), s2.getLength() ) &&
	//	Estimator.arePerpendicular( s1, s2 ) &&
	( stem.getLength() > ( s1.getLength() * 2.0 ) ) )
    {

      GPoint c = Estimator.connects( s1, s2, delta );

      if( c != null ) {
	GPoint first = stem.getHead();
	GPoint last  = stem.getTail();

	if ( first.includes( c, delta) )
	  return new GSegment( first, last );
	else if ( last.includes( c, delta ) )
	  return new GSegment( last, first );
      }
    }

    return null;
  }

  public Iterator getInputTypes()
  {
    Vector v = new Vector();
    v.addElement( "rec.core.widgets.WLine" );
    return( v.iterator() );
  }

  public Iterator getOutputTypes()
  {
    Vector v = new Vector();
    v.addElement( "rec.meche.WMForce" );
    return( v.iterator() );
  }
}

