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

// -*-Mode: Java-*- 
// $Id: SimPulleyRecognizer.java,v 1.2 2003/03/06 00:40:41 moltmans Exp $
// SimPulleyRecognizer.java -- 
// Author: Michael Oltmans <moltmans@ai.mit.edu> 
// Maintainer: Michael Oltmans <moltmans@ai.mit.edu> 
// Copyright: Copyright (C) 1999 by Michael Oltmans 
// Created: <Fri Oct 15 16:59:41 1999> 
// Time-stamp: <2000-07-16 22:58:41 moltmans> 
// Keywords: 
package rec.simulate.recognizers;

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

public class SimPulleyRecognizer extends Recognizer
{
//    private List m_circles;
//    private List m_lines;
  

//    private boolean connects( WCircle c, WLine l )
//    {
//      return ( c.includes( l.getHead(), 20 ) ||
//  	     c.includes( l.getTail(), 20 ) );
//    }
  
//    /**
//     * Get the orientation of the segment relative to the circle.
//     *
//     * Take the dot product of the center of the circle and the point
//     * of the segment not on the circle.
//     **/
//    private double getOrientation( GCircle c, GSegment l ) 
//    {
//      GPoint a = null;
//      GPoint b = null;
//      GPoint p = c.getCenter();
//      GPoint p1 = l.getHeadPoint();
//      GPoint p2 = l.getTailPoint();

//      if ( c.includes( p1, 20 ) ) {
//        a = p1;
//        b = p2;
//      }
//      else if ( c.includes( p2, 20 ) ) {
//        a = p2;
//        b = p1;
//      }
//      else {
//        Assert.error( "Invalid configuration in SimPulleyRecognizer" );
//      }

//      double theta = Geometry.angleBetween( p, a, b );

//      if ( theta < Math.PI )
//        return 1;
//      else if ( theta == Math.PI )
//        return 0;
//      else
//        return -1;
    
//      //    return b.minus( a ).dotProduct( p.minus( a ) );
//    }

//    private WLine findLine( GSegment seg ) 
//    {
//      Iterator it = m_lines.iterator();
//      while( it.hasNext() ) {
//        WLine line = (WLine)it.next();
//        if( sameLine( seg, line ) ) {
//  	return line;
//        }
//      }
//      return null;
//    }

//    private boolean sameLine( WLine l1, WLine l2 ) 
//    {
//      return sameLine( l1.getLine(), l2.getLine() );
//    }

//    private boolean sameLine( GSegment l1, WLine l2 ) 
//    {
//      return sameLine( l1, l2.getLine() );
//    }
//    private boolean sameLine( GSegment l1, GSegment l2 ) 
//    {
//      return ( ( (l1.getHeadPoint() == l2.getHeadPoint()) &&
//  	       (l1.getTailPoint() == l2.getTailPoint())  ) ||
//  	     ( (l1.getHeadPoint() == l2.getTailPoint()) &&
//  	       (l1.getTailPoint() == l2.getHeadPoint())  ) );
//    }
  
//    private LinkedList findWheels( Surface s, WLine l )
//    {
//      WCircle outer;
//      WCircle inner;
//      PulleyWheel wheel;
//      LinkedList list = new LinkedList();
//      Iterator it = m_circles.iterator();

//      // find the outer wheel
//      while( it.hasNext() ) {
//        outer = (WCircle)it.next();
//        if( connects( outer, l ) ) {
//  	Iterator centers = m_circles.iterator();
//  	while( centers.hasNext() ) {
//  	  inner = (WCircle)centers.next();
//  	  if( ( inner != outer ) &&
//  	      Estimator.connects( outer.getCenter(),
//  				  inner.getCenter(), 20 ) &&
//  	      (outer.getRadius() > inner.getRadius()) )
//  	  {
//  	    list.add( new PulleyWheel( outer, inner ) );
//  	  }
//  	}
//        }
//      }
//      return list;
//    }
  
//    private List findPulleysFromLine( Surface s, WLine l )
//    {
//      List wheels = findWheels( s, l );
//      List pulleys = new LinkedList();

//      if( wheels.isEmpty() ) {
//        return pulleys;
//      }

//      Iterator it = wheels.iterator();
//      while( it.hasNext() ) {
//        PulleyWheel wheel = (PulleyWheel)it.next();
//        Iterator lines = m_lines.iterator();
//        while( lines.hasNext() ) {
//  	WLine rope = (WLine)lines.next();
//  	if( isPulley( wheel, l, rope ) ) {
//  	  pulleys.add( new Pulley( wheel, l, rope ) );
//  	}
//        }
//      }
//      return pulleys;
//    }


//    private boolean isPulley( PulleyWheel wheel, WLine l1, WLine l2 )
//    {
//      return ( wheel.connects( l1 ) &&
//  	     wheel.connects( l2 ) &&
//  	     isViableOrientation( wheel.outer, l1, l2 ) );
//    }
  
//  //    private Pulley findPulley( Surface s, Pulley wheel, WLine l )
//  //    {
//  //      Iterator widgets = m_lines.iterator();

//  //      while( widgets.hasNext() ) {
//  //        WLine vw = (WLine)widgets.next();
//  //        if( ( vw != l ) &&
//  //  	  ( wheel.tryAddRope( (WLine)vw ) ) )
//  //        {
//  //  	return wheel;
//  //        }
//  //      }
//  //      return null;
//  //    }
    
//    public static List align( List l1, List l2 ) 
//    {
//      Object first1 = l1.get(0);
//      Object first2 = l2.get(0);
//      Object last1 = l1.get(l1.size() - 1 );
//      Object last2 = l2.get(l2.size() - 2 );
    
//      LinkedList l = new LinkedList( l1 );
//      if( last1.equals( first2 ) ) {
//        // just add 2 to the end of 1
//        l.remove( l.size() - 1 );
//        l.addAll( l2 );
//      }
//      else if( last1.equals( last2 ) ) {
//        // reverse the second list and tack it onto 1
//        l.remove( l.size() - 1 );
//        Collections.reverse( l2 );
//        l.addAll( l2 );
//      }
//      else if( first1.equals( last2 ) ) {
//        // stick 2 in before 1
//        l.remove(0);
//        l.addAll( 0, l2 );
//      }
//      else if( first1.equals( first2 ) ) {
//        // reverse the second list and stick it onto the front
//        l.remove(0);
//        Collections.reverse( l2 );
//        l.addAll( 0, l2 );
//      }
//      else {
//        Assert.error( "Unahdled case in aligning to lists: " +
//  		    l1 + " " + l2 );
//      }
    
//      return l;
//    }  
  
//    private void replacePulley( Surface s, Pulley pulley )
//    {
//      // all the things to replace
//      HashSet set = new HashSet();
//      List circles = new LinkedList();
//      Iterator it = pulley.wheels.iterator();
//      while( it.hasNext() ) {
//        PulleyWheel wheel = (PulleyWheel)it.next();
//        circles.add( wheel.outer );
//        set.add( wheel.inner );
//        set.add( wheel.outer );
//      }
//      set.addAll( pulley.ropes );
    
//      WSimPulley wpulley =
//        ((SimulateSurface)s).makeSimPulley( circles, pulley.ropes );
    
//      s.replaceWidget( set, wpulley, true );
//    }
  
//    private void replacePulley( Surface s, WLine link,
//  			      WSimPulley wpulley, Pulley pulley )
//    {
//      // all the things to replace
//      HashSet set = new HashSet();
//      LinkedList circles = new LinkedList();
//      // get the gcricles for the new pulley and save the wcircles so
//      // they can get replaced.
//      Iterator it = pulley.wheels.iterator();
//      while( it.hasNext() ) {
//        PulleyWheel wheel = (PulleyWheel)it.next();
//        circles.addLast( wheel.outer.getCircle() );
//        set.add( wheel.inner );
//        set.add( wheel.outer );
//      }
//      set.addAll( pulley.ropes );
//      set.add( wpulley );
//      set.remove( link );

//      LinkedList ropes = new LinkedList();
//      it = pulley.ropes.iterator();
//      while( it.hasNext() ) {
//        WLine line = (WLine)it.next();
//        ropes.addLast( line.getLine() );
//      }
    
//      List allRopes = align( ropes, wpulley.getRopes() );
//      List allWheels = align( circles, wpulley.getWheels() );

//      WSimPulley newPulley =
//        ((SimulateSurface)s).makeSimPulley( allWheels, allRopes );
    
//      s.replaceWidget( set, newPulley, true );
//    }

//    private Pulley recognizeWithPulley( Surface s, WSimPulley pulley )
//    {
//      GSegment rope1 = pulley.getRopeN(0);
//      WLine line = findLine( rope1 );
//      Assert.notNull( line, "Unmatched segment...: " + rope1 );

//      List pulleys = findPulleysFromLine( s, line );

//      Iterator it = pulleys.iterator();
//      while( it.hasNext() ) {
//        Pulley p = (Pulley)it.next();
//        if( !p.sameAttachment( line, pulley ) ) {
//  	replacePulley( s, line, pulley, p );
//  	return true;
//        }
//      }
//      return false;
//    }
  
  private boolean recognizeWithLine( Surface s, WLine l )
  {
    List pulleys = findPulleysFromLine( s, l.getLine() );
       
    if( pulleys.isEmpty() ) {
      return false;
    }

    if( pulleys.size() > 1 ) {
      Assert.note( "There were more than 1 pulleys for " + l );
    }
    
    replacePulley( s, (Pulley)pulleys.getFirst() );
    return true;
  }

//  //    private boolean recognizeWithWheel( Surface s, WCircle wheel )
//  //    {
//  //      WLine line1 = null;
//  //      WLine line2 = null;
    
//  //      Iterator it = s.getVisibleWidgets().iterator();
//  //      LinkedList lines = new LinkedList();

//  //      while ( it.hasNext() ) {
//  //        VisibleWidget vw = (VisibleWidget)it.next();
//  //        if( vw instanceof WLine )
//  //  	lines.add( vw );
//  //      }

//  //      ListIterator lines_it1 = lines.listIterator( 0 );
//  //      while ( lines_it1.hasNext() ) {
//  //        line1 = (WLine)lines_it1.next();

//  //        if ( isPulleyRope( wheel, line1 ) ) {
//  //  	ListIterator lines_it2 = lines.listIterator( lines_it1.nextIndex() );

//  //  	while ( lines_it2.hasNext() ) {
//  //  	  line2 = (WLine)lines_it2.next();
//  //  	  if ( isPulley( wheel, line1, line2 ) ) {
//  //  	    Assert.error( "not fixed yet need to find the inner circle." );
//  //  	    makePulley( s, wheel, null, line1, line2 );
//  //  	    return( true );
//  //  	  }
//  //  	}
//  //        }
//  //      }
//  //      return false;
//  //    }
    
    public boolean recognize( Surface s, Widget w )
    {
      return false;
    }
  
//      // generate lists of lines and circles so we don't have to build
//      // them repeatedly
//      m_circles = new LinkedList();
//      m_lines = new LinkedList();
    
//      Iterator widgets = s.getVisibleWidgets().iterator();
//      while( widgets.hasNext() ) {
//        Widget widget = (Widget)widgets.next();
//        if( widget instanceof WLine ) {
//  	m_lines.add( widget );
//        }
//        if( widget instanceof WCircle ) {
//  	m_circles.add( widget );
//        }
//      }
      
//      if( w instanceof WLine ) {
//        return recognizeWithLine( s, (WLine)w );
//      }
//      else if( w instanceof WCircle ) {
//        return false;
//        //      return recognizeWithWheel( s, (WCircle)w );
//      }
//      else if( w instanceof WSimPulley ) {
//        return recognizeWithPulley( s, (WSimPulley)w );
//      }
//      else {
//        Assert.error( "Unnacceptable input type: " + w );
//        return false;
//      }
//    }
  
  public Iterator getInputTypes()
  {
    Vector v = new Vector();

    //    v.addElement( "rec.meche.WPulleyWheel" );
    v.addElement( "rec.core.widgets.WCircle" );
    v.addElement( "rec.core.widgets.WLine" );
    //    v.addElement( "rec.simulate.widgets.WSimPulley" );
    return( v.iterator() );
  }

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

    v.addElement( "rec.simulate.widgets.WSimPulley" );

    return( v.iterator() );
  }

//    private boolean isViableOrientation( WCircle c, WLine l1, WLine l2 )
//    {
//      double x1 = getOrientation( c.getCircle(), l1.getLine() );
//      double x2 = getOrientation( c.getCircle(), l2.getLine() );
//      if ( x1 * x2 < 0 ) {
//        return true;
//      }
//      return false;
//    }

//    class PulleyWheel
//    {
//      WCircle outer;
//      WCircle inner;

//      PulleyWheel( WCircle out, WCircle in )
//      {
//        outer = out;
//        inner = in;
//      }

//      public boolean equals( Object o )
//      {
//        if( o instanceof PulleyWheel ) {
//  	PulleyWheel w = (PulleyWheel)o;
//  	return ( (w.outer == outer) && (w.inner == inner) );
//        }
//        return false;
//      }

//      boolean connects( WLine l )
//      {
//        return ( outer.includes( l.getHead(), 20 ) ||
//  	       outer.includes( l.getTail(), 20 ) );
//      }
//    }

//    class Pulley
//    {
//      LinkedList wheels = new LinkedList();
//      LinkedList ropes = new LinkedList();

//      Pulley( PulleyWheel w, WLine r1, WLine r2 )
//      {
//        wheels.add( w );
//        ropes.add( r1 );
//        ropes.add( r2 );
//      }

//      // must be a full pulley already
//  //      boolean tryAddWheel( PulleyWheel w )
//  //      {
//  //        if( ropes.size() == 0 ) {
//  //  	wheels.add( w );
//  //        }

//  //        // make sure it isn't already there
//  //        if( wheels.contains( w ) ) {
//  //  	return false;
//  //        }
//  //        if( w.connects( getRope1() ) ) {
//  //  	wheels.addFirst( w );
//  //  	return true;
//  //        }
//  //        if( w.connects( getRope2() ) ) {
//  //  	wheels.addLast( w );
//  //  	return true;
//  //        }      
//  //        return false;
//  //      }
    
//  //      boolean tryAddRope( WLine l ) 
//  //      {
//  //        // make sure it isn't already there
//  //        if( ropes.contains( l ) ) {
//  //  	return false;
//  //        }

//  //        if( wheels.isEmpty() && ropes.isEmpty() ) {
//  //  	ropes.add( l );
//  //        }
      
//  //        PulleyWheel wheel = getWheel1();
//  //        if( wheel != null && wheel.ropeConnects( l ) ) {
//  //  	if( ropes.size() == 0 ||
//  //  	    isViableOrientation( wheel.outer, l, getRope1() ) )
//  //  	{
//  //  	  ropes.addFront( l );
//  //  	  return true;
//  //  	}
//  //  	return false;
//  //        }

//  //        wheel = getWheel2();
//  //        if( wheel != null && wheel.ropeConnects( l ) ) {
//  //  	if( ropes.size() == 0 ||
//  //  	    isViableOrientation( wheel.outer, l, getRope2() ) )
//  //  	{
//  //  	  ropes.addLast( l );
//  //  	  return true;
//  //  	}
//  //  	return false;
//  //        }

//  //        return false;
//  //      }
    
//      WLine getRope1() 
//      {
//        if( ropes.size() > 0 )
//  	return ropes.getFirst();
//        return null;
//      }
//      WLine getRope2()
//      {
//        if( ropes.size() > 1 )
//  	return ropes.getLast();
//        return null;
//      }
//      PulleyWheel getWheel1()
//      {
//        if( wheels.size() > 0 )
//  	return wheels.getFirst();
//        return null;
//      }
//      PulleyWheel getWhel2()
//      {
//        if( wheels.size() > 1 )
//  	return wheels.getLast();
//        return null;
//      }
//      boolean sameAttachment( WLine rope, WSimPulley p )
//      {
//        GCircle c1;
//        GCircle c2;      
      
//        if( sameLine( getRope1(), rope ) ) {
//  	c1 = getWheel1();
//        }
//        else if( sameLine( getRope2, rope ) ) {
//  	c1 = getWheel2();
//        }
//        else {
//  	return false;
//        }

//        if( sameLine( p.getRopeN(0), rope ) ) {
//  	c2 = p.getWheelN(0);
//        }
//        else if( sameLine( p.getRopeN( p.getNumRopes() - 1 ), rope ) ) {
//  	c2 = p.getWheelN( p.getNumWheels() - 1 );
//        }
//        else {
//  	return false;
//        }

//        return( c1.getCenter().equals( c2.getCenter() ) &&
//  	      c1.getSize() == c2.getSize() );
//      }
//    }
}
