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 SimGearRecognizer extends Recognizer
{
    public SimGearRecognizer()
    {
    }

    public boolean recognize( Surface s, Widget w )
    {

	Vector circles = new Vector();
	Vector trains = new Vector();

	if (w instanceof WCircle){
	    
	    WCircle inputCircle = (WCircle) w;
	    
	    GeometryCalculator gc = new GeometryCalculator(s);
	    Iterator it = gc.getVisibleWidgets().iterator();
	
	    while (it.hasNext()){
		VisibleWidget vw = (VisibleWidget) it.next();

		if(vw instanceof WCircle){
		    WCircle circle = (WCircle) vw;

		    if(circlesTangent(circle.getCircle(), inputCircle.getCircle())){
			circles.add(circle);
		    }
		}
	    }
	    it = gc.getSurfaceWidgets().iterator();
	    while (it.hasNext()){
		VisibleWidget vw = (VisibleWidget) it.next();		

		if (vw instanceof WSimGearTrain){

		    WSimGearTrain train = (WSimGearTrain) vw;

		    WSimGear[] trainGears = train.getGears();

		    for(int i = 0; i < train.numGears(); i++){
			
			if(circlesTangent((GCircle)trainGears[i].getShape(),
					  inputCircle.getCircle())){
			    if(!trains.contains(train)){
				trains.add(train);
			    }
			}
		    }
		}
	    }
	    
	    if(trains.size() > 0 || circles.size() > 0){
		
		SimulateSurface SimS = (SimulateSurface) s;

		Vector gears = new Vector();
		WSimGear gearArray[];
		WSimGearTrain trainArray[] = new WSimGearTrain[trains.size()];

		HashSet oldSet = new HashSet();
		HashSet newSet = new HashSet();

		WSimGear newGear = SimS.makeSimGear(inputCircle);

		s.replaceWidget(inputCircle, newGear);

		for(int i = 0; i < trains.size(); i ++){
		    
		    WSimGearTrain train = (WSimGearTrain) trains.get(i);

		    trainArray[i] = train;

		    oldSet.add(train);
		    
		}

		int numGearsToAdd = circles.size();

		for(int i = 0; i < circles.size(); i ++){
		    
		    boolean alreadyAGear = false;

		    WCircle circle = (WCircle) circles.get(i);

		    for(int j = 0; j < trains.size(); j++){

			if(trainArray[j].isMyGear(circle)){
			    alreadyAGear = true;			    
			}
		    }
		    
		    if(!alreadyAGear){

			WSimGear gearToAdd = SimS.makeSimGear((WCircle)circles.get(i));
			
			gears.add(gearToAdd);

			s.replaceWidget(circle,gearToAdd);
		    }
		    else{
			numGearsToAdd--;
		    }

		}


		gearArray = new WSimGear[numGearsToAdd];

		for (int i = 0; i < numGearsToAdd; i++){
		    gearArray[i] = (WSimGear) gears.get(i);
		}
		
		//gearArray[numGearsToAdd-1] = newGear;

		WSimGearTrain newTrain = SimS.makeSimGearTrain(gearArray,
							       trainArray,
							       newGear,
							       true);
		

		newGear.setTrain(newTrain);
		
		for(int i = 0; i < numGearsToAdd; i++){
		    gearArray[i].setTrain(newTrain);
		}

// 		for(int i = 0; i < trains.size(); i++){
// 		    WSimGearTrain thisTrain = trainArray[i];
// 		    WSimGear[] thisTrainsGears = thisTrain.getGears();
// 		    for(int j = 0; j < thisTrain.numGears(); j++){
// 			thisTrainsGears[j].setTrain(newTrain);
// 		    }
// 		}

		newSet.add(newTrain);

		s.replaceWidget(oldSet, newSet);
		
		return true;		
	    }
	}
	return false;
    }
	
    private boolean circlesTangent(GCircle circle1, GCircle circle2){
	GPoint center1 = circle1.getCenter();
	GPoint center2 = circle2.getCenter();
	
	double distance = Geometry.distance(center1,center2);
	
	double radius1 = circle1.getRadius();
	double radius2 = circle2.getRadius();
	
	return (Math.abs(distance - (radius1 + radius2)) < 10);

    }

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

	v.addElement( "rec.core.widgets.WCircle" );

	return(v.iterator());
    }
    public Iterator getOutputTypes()
    {
	Vector v = new Vector();
	return(v.iterator());
    }
}
