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

package rec.fun;


import java.util.*;
import rec.util.*;
import rec.sys.*;
import rec.core.widgets.*;
import rec.core.recognizers.*;
import rec.geo.*;


public class ArrowheadRecognizer extends Recognizer
{

  public ArrowheadRecognizer()
  {
  }

  /////////////////////////////////////////////////////////////////////////////
  
  /**
   * Each new stroke generated gets put into the pipe here.
   *     It will remove and add objects to the 'out' target
   *     as it deems fit.
   */
  public boolean recognize( Surface s, Widget w )
  {
    GPoint p = isArrowhead( (Squiggle)w );

    if ( p != null )
      {
	//Console.writeln( "Arrowhead found" );
	Arrowhead resp = attachArrowhead( s, p, (Squiggle)w );

	if ( resp != null )
	  {
	    Console.writeln( "Arrowhead online" );

	    s.replaceWidget( w, resp );
	    
	    return true;
	  }
      }

    return false;
  }

  /**
   * Return a point which is the tip of the arrowhead, or null
   * if the stroke is not an arrowhead.
   */
  static GPoint isArrowhead( Squiggle s )
    {
      int size = s.getNumberOfPoints();
      if ( size < 10 )
	return null;

      for ( int i = size / 3; i < 2 * size / 3; i++ )
	if ( LineRecognizer.isLine( s.getSub( 0, i ) )
	     && LineRecognizer.isLine( s.getSub( i, size-1 ) ) )
	  return s.getPointAt( i );

	/*
      if ( LineRecognizer.isLine( s.getSub( 0, size / 2 ) )
	   || LineRecognizer.isLine( s.getSub( size/2, size-1 ) ) )
	return s.getPointAt( size/2 );
	*/

      //return s.getPointAt( size / 2 );

      return null;
    }



  Arrowhead attachArrowhead( Surface b, GPoint p, Squiggle s )
  {
    WLine best = null;
    boolean head = true;
    double b_d, t;

    Iterator e = b.getWidgetsIterator();
    double size = s.getLength() / 2; // the length of arrowhead side
    size *= 2;  // we are looking for a line who is at least 2 x as long
    // as arrowhead side

    b_d = 10000;
    
    // find most likely Edge
    while ( e.hasNext() )
      {
	Object o = e.next();
	if ( !( o instanceof WLine ) )
	  continue;

	WLine l = (WLine)o;
	if ( l.getLength() > size ) // make sure line is bigger than arrowhead
	  {
	    if (  ( t = Geometry.distance( l.getHead(), p )) < b_d )
	      {
		best = l;
		b_d = t;
		head = true;
	      }
	    
	    if ( ( t = Geometry.distance( l.getTail(), p )) < b_d )
	      {
		best = l;
		b_d = t;
		head = false;
	      }
	  }
      }

    if ( ( best != null ) && ( b_d < 50 ) )  // size / 4 ) )
      //    if ( best != null )
      {
	// found a WLine
	Arrowhead res = new Arrowhead( best, head );

	return res;
      }

    
    return null;
  }


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

    v.addElement( "rec.sys.Squiggle" );

    return( v.iterator() );
  }

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

    v.addElement( "rec.fun.Arrowhead" );

    return( v.iterator() );
  }

}

////////////////////////////////////////////////////////////////////////////////
