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

package rec.house;

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

public class Door extends VisibleWidget implements Registerable
{
  public static int WIDTH = 20;
  public static int HEIGHT = 7;

  Wall wall;
  double where;

  static {
    Colors.setDefaultColor( "door", "stroke" );
  }

  public Door( Surface s, Wall w, double where )
  {
    setSurface( s );

    this.wall = w;
    s.register( this, wall );
    this.where = where;
  }

  public double size()
  {
    throw new RuntimeException( "Door size() called erroniously." );
  }

  public void resize( double scaleFactor )
  {
    throw new RuntimeException( "Door resize() called erroniously." );
  }


  public GPoint findLocation( )
  {
    GPoint p1 = wall.getHead();
    GPoint p2 = wall.getTail();
    GPoint c = new GPoint( p1.x + ( p2.x - p1.x ) * where,
			   p1.y + ( p2.y - p1.y ) * where );

    return c;
  }

  public void draw( Graphics g )
  {
    double length = wall.getLength();
    GPoint p1 = wall.getHead();
    GPoint p2 = wall.getTail();
    GPoint c = new GPoint( p1.x + ( p2.x - p1.x ) * where,
			   p1.y + ( p2.y - p1.y ) * where );
    double dx = ( p2.x - p1.x ) / length;
    double dy = ( p2.y - p1.y ) / length;

    GPoint A = new GPoint( c.x - WIDTH * dx - HEIGHT * dy,
			   c.y - WIDTH * dy + HEIGHT * dx );

    GPoint B = new GPoint( c.x - WIDTH * dx + HEIGHT * dy,
			   c.y - WIDTH * dy - HEIGHT * dx );

    GPoint C = new GPoint( c.x + WIDTH * dx + HEIGHT * dy,
			   c.y + WIDTH * dy - HEIGHT * dx );

    GPoint D = new GPoint( c.x + WIDTH * dx - HEIGHT * dy,
			   c.y + WIDTH * dy + HEIGHT * dx );

    int[] x = new int[ 4 ];
    int[] y = new int[ 4 ];
    x[0] = (int)A.x;
    x[1] = (int)B.x;
    x[2] = (int)C.x;
    x[3] = (int)D.x;
    y[0] = (int)A.y;
    y[1] = (int)B.y;
    y[2] = (int)C.y;
    y[3] = (int)D.y;

    
    Color cc = getColor();
    if ( cc == null )
      cc = Colors.getColor( "door" );

    g.setColor( Colors.getBackground() );
    g.fillPolygon( x, y, 4 );
    g.setColor( cc );
    g.drawPolygon( x, y, 4 );
    g.drawLine( (int)A.x, (int)A.y, (int)C.x, (int)C.y );
    //    g.drawLine( (int)B.x, (int)B.y, (int)C.x, (int)C.y );
    g.drawLine( (int)B.x, (int)B.y, (int)D.x, (int)D.y );
    //    g.drawLine( (int)D.x, (int)D.y, (int)A.x, (int)A.y );
  }


  public boolean includes( GPoint gp, double offset )
  {
    return ( Geometry.distance( gp, getLocation().getCenter() )
	     < ( 25 + offset ) );
  }

  public boolean contains( GPoint gp, double offset )
  {
    return ( Geometry.distance( gp, getLocation().getCenter() )
	     < ( 25 + offset ) );
  }

  public boolean contains( GPoint gp )
  {
    return contains( gp, 0 );
  }


  public void move( GPoint gp )
  {
    ;
  }

  public void rotate( GPoint gp, double angle )
  {
    throw new RuntimeException( "door rotate() called erroniously" );
  }

  public Location getLocation()
  {
    GPoint p1 = wall.getHead();
    GPoint p2 = wall.getTail();
    GPoint c = new GPoint( p1.x + ( p2.x - p1.x ) * where,
			   p1.y + ( p2.y - p1.y ) * where );
    
    return( new Location( c, WIDTH ) );
  }

  public Rectangle getBounds()
  {
    GPoint p1 = wall.getHead();
    GPoint p2 = wall.getTail();
    GPoint c = new GPoint( p1.x + ( p2.x - p1.x ) * where,
			   p1.y + ( p2.y - p1.y ) * where );
    
    return new Rectangle( (int)c.x - WIDTH, (int)c.y - WIDTH,
			  (int)c.x + WIDTH, (int)c.y + WIDTH );
  }


  public void translate( int dx, int dy )
  {
    ;
  }

  public Object clone()
  {
    Door ret = new Door( getSurface(), wall, where );

    getSurface().register( ret, wall );
    return( ret );
  }


  
  public void removed( Widget widget )
  {
    Console.writeln( "Door following parent " + widget + " into oblivion." );
    getSurface().removeWidget( this );
  }
  
  public void replaced( Widget ow, Collection nws )
  {
    Iterator it = nws.iterator();
    GPoint p = findLocation();
    
    while( it.hasNext() )
      {
	Wall w = (Wall)it.next();
	if ( w.includes( p, 5 )
	     && ( Geometry.distance( p, w.getHead() ) > WIDTH )
	     && ( Geometry.distance( p, w.getTail() ) > WIDTH ) )
	  {
	    // put door on this wall
	    wall = w;
	    getSurface().register( this, wall );

	    // find our spot
	    where = Geometry.distance( p, w.getHead() ) / w.getLength();

	    // bail!
	    return;
	  }
	else
	  getSurface().unregister( this, w );
      }
    
    // if we are here, delete self
    Console.writeln( "Door split and sad--dying." );
    getSurface().removeWidget( this );
  }

  public void replaced( Widget ow, Widget nw )
  {
    if ( nw instanceof Wall )
      {
	wall = (Wall)nw;
	getSurface().register( this, wall );
      }
    else
      {
	Console.writeln( "Door dying, parent changing into " + nw );
	getSurface().unregister( this, nw );
	getSurface().removeWidget( this );
      }
  }

  public void altered( Widget widget, Transition t )
  {
  }

}
