/************************************************}
{                                                }
{   JDK 1.1, 1.2, 1.3, 1.4                       }
{   Extensions graphiques compatibles QuickDraw  }
{   P.Chassignet, Ecole Polytechnique, 1998-2004 }
{                                                }
{   dernie`re mise a` jour:  28/5/01             }
{                                                }
{************************************************/
import java.awt.Rectangle;

/**
 * This class implements QuickDraw-like definitions for rectangles.
 * Implements also object methods for these rectangles.
 * @version  28 may 2001
 * @author   Philippe Chassignet, Ecole Polytechnique
 * @see      MacLib
 * @see      java.awt.Rectangle
 */
public class Rect {

  /**
   * The <em>x</em> coordinate of the top left corner.
   */
  public short left = 0;

  /**
   * The <em>y</em> coordinate of the top left corner.
   */
  public short top = 0;

  /**
   * The <em>x</em> coordinate of the bottom right corner.
   */
  public short right = 0;

  /**
   * The <em>y</em> coordinate of the bottom right corner.
   */
  public short bottom = 0;

  /**
   * Constructs and initializes an empty rect with coordinates 
   * <code>(0,0,0,0)</code>.
   */
  public Rect() {
  }

  /**
   * Constructs and initializes a rectangle with the given coordinates.
   * @param       left  the <em>left</em> coordinate of the new rectangle.
   * @param       top  the <em>top</em> coordinate of the new rectangle.
   * @param       right  the <em>right</em> coordinate of the new rectangle.
   * @param       bottom  the <em>bottom</em> coordinate of the new rectangle.
   */
  public Rect(int left, int top, int right, int bottom) {
    this.left = (short)left;
    this.top = (short)top;
    this.right = (short)right;
    this.bottom = (short)bottom;
  }

  /**
   * Constructs and initializes a rectangle as the smallest one which 
   * encloses the two given points.
   * @param       p1  the first Point object used to specify the coordinates.
   * @param       p2  the second Point object used to specify the coordinates.
   */
  public Rect(Point p1, Point p2) {
    left = (short)Math.min(p1.h, p2.h);
    top = (short)Math.min(p1.v, p2.v);
    right = (short)Math.max(p1.h, p2.h);
    bottom = (short)Math.max(p1.v, p2.v);
  }

  /**
   * Constructs and initializes a rectangle as the smallest one which 
   * encloses the two given rectangles.
   * @param       src1  the first Rect object used to specify the 
   *                    coordinates.
   * @param       src2  the second Rect object used to specify the 
   *                    coordinates.
   */
  public Rect(Rect src1, Rect src2) {
    left = (short)Math.min(src1.left, src2.left);
    top = (short)Math.min(src1.top, src2.top);
    right = (short)Math.max(src1.right, src2.right);
    bottom = (short)Math.max(src1.bottom, src2.bottom);
  }

  /**
   * Returns the top left corner of this rectangle.
   * @return      a new Point object located at the top left corner.
   */
  public Point topLeft() {
    return new Point(left, top);
  }

  /**
   * Returns the bottom right corner of this rectangle.
   * @return      a new Point object located at the bottom right corner.
   */
  public Point botRight() {
    return new Point(right, bottom);
  }

  /**
   * Converts this rectangle as a <code>java.awt.Rectangle</code> object.
   * @return      a new Rectangle object.
   * @see         java.awt.Rectangle
   */
  public Rectangle getRectangle() {
    return new Rectangle(left, top, right-left, bottom-top);
  }
  
  /**
   * Sets the coordinates of this rectangle as specified.
   * @param       left  the new <em>left</em> coordinate.
   * @param       top  the new <em>top</em> coordinate.
   * @param       right  the new <em>right</em> coordinate.
   * @param       bottom  the new <em>bottom</em> coordinate.
   */
  public Rect setRect(int left, int top, int right, int bottom) {
    this.left = (short)left;
    this.top = (short)top;
    this.right = (short)right;
    this.bottom = (short)bottom;
    return this;
  }
  
  /**
   * Sets the coordinates of this rectangle as specified by the given 
   * <code>Rect</code> object.
   * @param       src  the Rect object used to specify the coordinates.
   */
  public Rect setRect(Rect src) {
    left = src.left;
    top = src.top;
    right = src.right;
    bottom = src.bottom;
    return this;
  }

  /**
   * Sets the coordinates of this rectangle as specified by the given 
   * <code>java.awt.Rectangle</code> object.
   * @param       rec  the Rectangle object used to specify the coordinates.
   * @see         java.awt.Rectangle
   */
  public Rect setRect(Rectangle rec) {
    left = (short)rec.x;
    top = (short)rec.y;
    right = (short)(rec.x + rec.width);
    bottom = (short)(rec.y + rec.height);
    return this;
  }

  /**
   * Sets the coordinates of this rectangle to the smallest one which 
   * encloses the two given points.
   * @param       p1  the first Point object used to specify the coordinates.
   * @param       p2  the second Point object used to specify the coordinates.
   */
  public Rect pt2Rect(Point p1, Point p2) {
    left = (short)Math.min(p1.h, p2.h);
    top = (short)Math.min(p1.v, p2.v);
    right = (short)Math.max(p1.h, p2.h);
    bottom = (short)Math.max(p1.v, p2.v);
    return this;
  }

  /**
   * Translates this rectangle by the specified displacement.
   * Adds <code>dh</code> to each horizontal coordinate and <code>dv</code> 
   * to each vertical coordinate.
   * @param       dh  the horizontal displacement.
   * @param       dv  the vertical displacement.
   */
  public Rect offsetRect(int dh, int dv) {
    left += dh;
    top += dv;
    right += dh;
    bottom += dv;
    return this;
  }

  /**
   * Shrinks or expands this rectangle by the specified amounts.
   * Adds <code>dh</code> to the left coordinate and 
   * subtracts <code>dh</code> from the right coordinate.
   * Adds <code>dv</code> to the top coordinate and 
   * subtracts <code>dv</code> from the bottom coordinate.
   * @param       dh  the horizontal displacement.
   * @param       dv  the vertical displacement.
   */
  public Rect insetRect(int dh, int dv) {
    left += dh;
    top += dv;
    right -= dh;
    bottom -= dv;
    return this;
  }

  /**
   * Sets the coordinates of this rectangle to the smallest one which 
   * encloses the two given rectangles.
   * @param       src1  the first Rect object used to specify the 
   *                    coordinates.
   * @param       src2  the second Rect object used to specify the 
   *                    coordinates.
   */
  public Rect unionRect(Rect src1, Rect src2) {
    left = (short)Math.min(src1.left, src2.left);
    top = (short)Math.min(src1.top, src2.top);
    right = (short)Math.max(src1.right, src2.right);
    bottom = (short)Math.max(src1.bottom, src2.bottom);
    return this;
  }

  /**
   * Determines whether this rectangle and the given rectangle have the same 
   * coordinates.
   * @param       r  the Rect object to compare with.
   * @return      <code>true</code> if both rectangles have same coordinates;
   *              <code>false</code> otherwise.
   */
  public boolean equalRect(Rect r) {
    return (this.left == r.left) && (this.top == r.top) 
        && (this.right == r.right) && (this.bottom == r.bottom);
  }

  /**
   * Sets the coordinates of this rectangle to the rectangle that is the 
   * intersection of the two given rectangles.
   * Determines also whether they indeed intersect. Rectangles that "touch" 
   * at a line or a point are not considered intersecting.
   * If the rectangles do not intersect, this rectangle is set to 
   * <code>(0,0,0,0)</code>.
   * @param       src1  the first Rect object used to specify the 
   *                    coordinates.
   * @param       src2  the second Rect object used to specify the 
   *                    coordinates.
   * @return      <code>true</code> if the two rectangles really intersect;
   *              <code>false</code> otherwise.
   */
  public boolean sectRect(Rect src1, Rect src2) {
    left = (short)Math.max(src1.left, src2.left);
    top = (short)Math.max(src1.top, src2.top);
    right = (short)Math.min(src1.right, src2.right);
    bottom = (short)Math.min(src1.bottom, src2.bottom);
    if ( this.emptyRect() ) {
      this.setRect(0, 0, 0, 0);
      return false;
    } else {
      return true;
    }
  }

  /**
   * Determines whether the pixel below and to the right of the given point 
   * is enclosed in this rectangle.
   * @param       pt  the Point object to check with.
   * @return      <code>true</code> if so; <code>false</code> otherwise.
   * @see         Point#inRect(Rect)
   */
  public boolean ptInRect(Point pt) {
    return (left <= pt.h) && (right > pt.h) 
        && (top <= pt.v) && (bottom > pt.v);
  }

  /**
   * Determines whether this rectangle is empty or not.
   * A rectangle is considered empty if the bottom coordinate is equal to 
   * or less than the top or the right coordinate is equal to or less 
   * than the left.
   * @return      <code>true</code> if so; <code>false</code> otherwise.
   */
  public boolean emptyRect() {
    return (left >= right) || (top >= bottom);
  }

  /**
   * Returns a string representation for the location of this rectangle.
   * @return      the string representation of the coordinates.
   */
  public String toString() {
    return "[left=" + left + ",top=" + top 
         + ",right=" + right + ",bottom=" + bottom + "]";
  }

  /**
   * Returns a hash code for this rectangle.
   * @return      the hash code build up from the coordinates.
   */
  public int hashCode() {
    return (int)left ^ ((int)top*37) 
         ^ (((int)right-(int)left)*43) ^ (((int)bottom-(int)top)*47);
  }

}  // end class Rect

