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

// -*-Mode: Java-*- 
// SimAnchorRecognizer.java -- 
// Author: Christine Alvarado <calvarad@ai.mit.edu> 
// Maintainer: Christine Alvarado <calvarad@ai.mit.edu> 
// Version: 
// Created: <Wed May 26 16:06:48 1999> 
// Time-stamp: <2001-09-10 18:26:07 moltmans> 
// Keywords: 
package rec.simulate.recognizers;

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

public class DamperRecognizer extends Recognizer
{
    private WSimDamper isDamper( WLine l1, WLine l2, WLine l3, WLine l4, 
				 Surface s )
    {
	
	// make sure that the lines are about the same size and intersect
	GSegment s1 = new GSegment( l1.getHead(), l1.getTail() );
	GSegment s2 = new GSegment( l2.getHead(), l2.getTail() );
	GSegment s3 = new GSegment( l3.getHead(), l3.getTail() );
	GSegment s4 = new GSegment( l4.getHead(), l4.getTail() );
	
	GPoint intersection;
	GSegment longest;
	GSegment cross1;
	GSegment cross2;
	GSegment cross3;
	
	// find the longest segment
	longest = s1;
	cross1 = s2;
	cross2 = s3;
	cross3 = s4;
	double longsize = s1.size();
	if ( s2.size() > longsize ) {
	    longest = s2;
	    cross1 = s1;
	    longsize = s2.size();
	}
	if ( s3.size() > longsize ) {
	    longest = s3;
	    cross1 = s1;
	    cross2 = s2;
	    longsize = s3.size();
	}
	if ( s4.size() > longsize ) {
	    cross1 = s1;
	    cross2 = s2;
	    cross3 = s3;
	    longest = s4;
	}
	
	GSegment middleX;
	GSegment side1;
	GSegment side2;
	
	
	// check for the correct perpendicularities
	if ( Estimator.arePerpendicular( cross1, longest ) ) {
	    middleX = cross1;
	    side1 = cross2;
	    side2 = cross3;
	}
	else if ( Estimator.arePerpendicular( cross2, longest ) ) {
	    middleX = cross2;
	    side1 = cross1;
	    side2 = cross3;
	}
	else if ( Estimator.arePerpendicular( cross3, longest ) ) {
	    middleX = cross3;
	    side1 = cross1;
	    side2 = cross2;
	}
	else {
	    return null;
	}
	
	// now check the rest of the conditions
	if ( (Estimator.arePerpendicular( side1, middleX )) &&
	     (Estimator.arePerpendicular( side2, middleX )) &&
	     (middleX.getIntersectionOnSegment( longest ) != null) &&
	     (middleX.connects( side1, 10.0 ) != null) &&
	     (middleX.connects( side2, 10.0 ) != null) ) {
	    return( ((SimulateSurface)s).makeSimDamper( longest ));
	}
	else {

	    return null;
	}
	
    }    
  

    public DamperRecognizer()
    {
    }
    
    public boolean recognize( Surface s, Widget w)
    {
	WLine l1;
	WLine l2;
	WLine l3;
	WLine l4;
		
	//Get all the lines and polylines
	GeometryCalculator gc = new GeometryCalculator( s );
	Iterator it = gc.getVisibleWidgets().iterator();
	
	HashSet line_pool = new HashSet();
	HashSet polyLine2_pool = new HashSet();
	HashSet polyLine3_pool = new HashSet();

	int num_lines = 0;
	while (it.hasNext()){
	    VisibleWidget vw = (VisibleWidget) it.next();
	    if ( ((VisibleWidget)w).overlaps( vw ) ) {

		if( vw instanceof WLine && !vw.equals( w ) ) {
		    line_pool.add( vw );
		}
	    
		else if (vw instanceof WPolyLine
			 && !vw.equals(w)){

		    WLine lines[] = getPolyLineLines((WPolyLine) vw);
		    if (lines.length == 2){
			polyLine2_pool.add( vw );
		    }
		    else if (lines.length == 3){
			polyLine3_pool.add( vw );
		    }
		}
	    }
	}

	// input is either a line or a polyline

	if (w instanceof WPolyLine){
	    
	    WPolyLine pl = (WPolyLine) w;
	    
	    WLine lines[] = getPolyLineLines(pl);
	    
	    System.out.println("A Polyline of length " + lines.length);

	    if(lines.length == 3){
		
		l1 = lines[0];
		l2 = lines[1];
		l3 = lines[2];
		
		// A poly line of length three requires 1 more line,
		// the base.  Look in the line pool.
		
		Iterator lineIterator = line_pool.iterator();
		
		while (lineIterator.hasNext()){
		    l4 = (WLine) lineIterator.next();
		    
		    WSimDamper d = isDamper(l1, l2, l3, l4, s);
		    if (d != null){
			// Remove the input widget and
			// the last line
			s.removeWidget( w );
			s.removeWidget( l4 );
			
			s.addWidget( d );
			return( true );
		    }
		}
		return false; //couldn't find a line
	    }

	    else if(lines.length == 2){
		
		l1 = lines[0];
		l2 = lines[1];

		// A poly line of length two requires 2 more lines.
		// Look in the line pool twice.
		
		Iterator lineIterator = line_pool.iterator();
		Iterator lineIterator2 = line_pool.iterator();
		
		while (lineIterator.hasNext()){
		    l3 = (WLine) lineIterator.next();

		    while (lineIterator2.hasNext()){
			l4 = (WLine) lineIterator2.next();
			
			if(!l3.equals(l4)){

			    WSimDamper d = isDamper(l1, l2, l3, l4, s);
			    if (d != null){
				// Remove the input widget and
				// the last 2 lines
				s.removeWidget( w );
				s.removeWidget( l3 );
				s.removeWidget( l4 );
				
				s.addWidget( d );
				return( true );
			    }
			}
		    }
		}
		return false;
	    }

	    
	    else{ // if lines.length != 2 or 3
		return false;
	    }
		

	}
	
	else if (w instanceof WLine){
	    
	    l1 = (WLine) w;
	    
	    // if we have a line we need either:
	    // * 1 length 3 polyline,
	    // * 1 length 2 polyline and 1 line
	    // * 3 lines
	    
	    // try for length 3 polyline
	    
	    Iterator threeIterator = polyLine3_pool.iterator();
	    while(threeIterator.hasNext()){
		WPolyLine polyLine = (WPolyLine) threeIterator.next();
		
		WLine[] lines = getPolyLineLines(polyLine);
		l2 = lines[0];
		l3 = lines[1];
		l4 = lines[2];
		WSimDamper d = isDamper(l1, l2, l3, l4, s);
		
		if (d != null){
		    // Remove the input widget and
		    // the polyline
		    s.removeWidget( w );
		    s.removeWidget( polyLine );
		    
		    s.addWidget( d );
		    return( true );
		}
	    }

	    // try for lenth 2 poly line and line
	    Iterator twoIterator = polyLine2_pool.iterator();
	    Iterator lineIterator = line_pool.iterator();

	    while(twoIterator.hasNext()){
		WPolyLine polyLine = (WPolyLine) twoIterator.next();
		while(lineIterator.hasNext()){
		    
		    WLine[] lines = getPolyLineLines(polyLine);

		    l2 = lines[0];
		    l3 = lines[1];
		    l4 = (WLine) lineIterator.next();


		    WSimDamper d = isDamper(l1, l2, l3, l4, s);
		    
		    if (d != null){
			// Remove the input widget, the polyline,
			// and the last line
			
			s.removeWidget( w );
			s.removeWidget( polyLine );
			s.removeWidget( l4 );
		       
			s.addWidget( d );
			return( true );
		    }
		}
	    }


	    // try for 3 lines
	    Iterator lineIterator1 = line_pool.iterator();
	    Iterator lineIterator2 = line_pool.iterator();
	    Iterator lineIterator3 = line_pool.iterator();

	    while(lineIterator1.hasNext()){
		l2 = (WLine) lineIterator1.next();
		if (!l2.equals(l1)){
		    while(lineIterator2.hasNext()){
			l3 = (WLine) lineIterator2.next();
			if (!l3.equals(l2) &&
			    !l3.equals(l1)){
			    while(lineIterator3.hasNext()){
				l4 = (WLine) lineIterator3.next();
				if(!l4.equals(l3) &&
				   !l4.equals(l2) &&
				   !l4.equals(l1)){
				    
				    WSimDamper d = isDamper(l1, l2, l3, l4, s) ;
				    
				    if (d != null){
					// Remove the input widget, and
					// and the three line
					
					s.removeWidget( w );
					s.removeWidget( l2 );
					s.removeWidget( l3 );
					s.removeWidget( l4 );
					
					s.addWidget( d );
					return( true );
				    }
				}
			    }
			    
			}
		    }
		}
	    }

	    return false; //none of the three posibilities worked
	}


	return false; // if neither WPolyLine or WLine
    }

    private WLine[] getPolyLineLines(WPolyLine pl){
	
	Polygon polygon = pl.getPolyLine();
	
	int number = polygon.npoints;
	
	WLine[] lines = new WLine[number - 1];
	
	int xs[] = polygon.xpoints;
	int ys[] = polygon.ypoints;
	
	
	for (int i=0; i < number - 1; i++){
	    lines[i] = new WLine(new GPoint(xs[i], ys[i]), 
				 new GPoint(xs[i+1], ys[i+1])); 
	}	
	
	return lines;
    }  

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

	return( v.iterator() );
    }
    
}
