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

package rec.house;


import java.util.*;
import java.awt.*;
import rec.util.*;
import rec.sys.*;
import rec.core.*;

/**
 * This subtracts out any regions underneath the new region.
 */
public class RegionReducer extends RegionSplitter
{
  /**
   * This is the minimum area allowable by a region made from
   * region reduction.
   */
  public static double MINIMUM_AREA = 2500;

  public RegionReducer()
  {
  }

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

  /**
   * Recognizes on regions, not walls.
   */
  public boolean recognize( Surface s, Widget w )
  {
    Region new_r = (Region)w;

    Iterator wids = s.getWidgetsIterator();

    while( wids.hasNext() )
      {
	Object o = wids.next();
	if (! ( o instanceof Region ) )
	  continue;
	Region r = (Region)o;

	// check to see if this is us
	if ( r.equals( new_r ) )
	  continue;

	// check to see if this is sitting on the found region
	if ( ! new_r.overlaps( r ) )
	  continue;

	// it must have been!  hack old one!
	Console.writeln( "Hacking " + r + " using " + new_r );
	Region rest = r.getRemainder( new_r, BREAK );

	double ra = r.area(), resta = rest.area();
	Console.writeln( "clipping from " + ra + " to " + resta );
	if ( (ra - resta) <= MINIMUM_AREA )
	  continue;
	
	rest.makeLike( r );
	
	if ( rest != null )
	  {
	    // fix the walls
	    BasicModule mod = new CutterModule();
	    mod.add( new WallPickerUpper( rest, new_r ) );
	
	    s.addModule( mod, null );
	    
	    // dump old Region and put in new one.
	    s.replaceWidget( r, rest, true );

	    Iterator e = r.walls();
	    while( e.hasNext() )
	      {
		Wall wall = (Wall)e.next();

		// get rid of all this old region connection crappie!
		r.removeWall( wall );
		wall.removeRegion( r );

		s.rerecognizeWidget( wall );
	      }
	    e = new_r.walls();
	    while( e.hasNext() )
	      s.rerecognizeWidget( (Widget)e.next() );

	    // force all the walls to get cut up into little, itty bitty
	    // bits.
	    s.emptyQueue();

	    // pop off the wall cutter
	    s.removeModule();

	    return true;
	  }
	else
	  {
	    Console.writeln( "Strange- mother region remainder empty." );
	    s.removeWidget( r );
	  }
      }

    return false;
  }

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

    //    v.addElement( "rec.core.WLine" );
    v.addElement( "rec.house.Region" );
    return( v.iterator() );
  }

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

    v.addElement( "rec.house.Region" );

    return( v.iterator() );
  }


} // end RegionReducer






class WallPickerUpper extends Recognizer
{
  Region rest;
  Region new_r;

  WallPickerUpper( Region rest, Region new_r )
  {
    this.rest = rest;
    this.new_r = new_r;
  }

  public boolean recognize( Surface s, Widget wid )
  {
    Wall w = (Wall)wid;

    // if wall in the new region, but not on border, nuke it.
    if ( new_r.contains( w, RegionRecognizer.BREAK )
	 && !new_r.includes( w, RegionRecognizer.BREAK ) )
      {
	s.removeWidget( w );
      }

    if ( rest.includes( w, RegionRecognizer.BREAK ) )
      {
	Console.writeln( "picker-upper says " + w + " is in " + rest );
	Console.indent();
	((Wall)w).addRegion( rest );
	rest.addWall( w );
	Console.outdent();
      }
    return false;
  }

  public Iterator getInputTypes()
  {
    Vector v = new Vector();
    v.addElement( "rec.house.Wall" );
    return v.iterator();
  }

  public Iterator getOutputTypes() 
  {
    return getInputTypes();
  }
}



  /*
  public boolean recognize_failed( Surface s, Widget w )
  {
    final WLine l = (WLine)w;

    Iterator e = s.getWidgetssIterator();

    GeoFunction gf = new GeoFunction()
      {
	public boolean check( Widget vw )
	  {
	    if ( vw instanceof Region )
	      {
		Region r = (Region)vw;
		if ( r.contains( l.getMidpoint(), BREAK ) )
		  return v;
	      }

	    return null;
	  }
      };
    GeometryCalculator gc = new GeometryCalculator( s );
    Region r = (Region)gc.findWidget( gf );

    if ( r != null )
      {
	s.removeWidget( r );
      }

    return false;
  }
  */





