/** A public class which models the 2-dimensional rectangles using the 
 screen coordinate system, thus, a Rectangle is identified by its upper
 -left corner (a TwoDPoint object), a horizontal length, and a vertical 
 width.  The class provides constructors and methods for returning values 
 of the instance variables, for returning a rectangle's area, for creating 
 a rectangle after shifting,  for testing if a rectangle interesct another 
 rectangle (9/21/01) */

public class Rectangle {
  private TwoDPoint upperLeft;
  private int length;
  private int width;

  // Two constructors of the Rectangle object
  /** create a Rectangle object with the specified upper-left corner, 
   integer length len, and integer width wid */
  public Rectangle(TwoDPoint p, int len, int wid) {  
    upperLeft = new TwoDPoint(p);  // create a TwoDPoint
    length = len;
    width = wid;
  }
  /** create a new Rectangle object identical to r */
  public Rectangle(Rectangle r) {
    this(r.getUpperLeft(), r.getLength(), r.getWidth());
  }

  // public methods
  /**  return a reference to the upper-left corner TwoDPoint object */
  public TwoDPoint getUpperLeft() {
    return upperLeft;  
  }
  /** return the length */
  public int getLength() {
    return length;
  }
  /** return the width */
  public int getWidth() {
    return width;
  }
  /** create a new Rectangle object with the same length and width as 
   that of the invoking object, but the upper-left corner being 
   shifted by dispX and dispY in the x and y directions, respectively 
   (we assume dispX and dispY are non-negative), the method returns a 
   reference to the created Rectangle */
  public Rectangle translate(int dispX, int dispY) {
    // create a new TwoDPoint for the shifted upperLeft corner
    TwoDPoint p = new TwoDPoint(upperLeft.getX() + dispX, 
                  upperLeft.getY() + dispY);  
    return new Rectangle(p, length, width);
  }
  /** determine if any of Rectangle r's corners lies within the invoking 
   Rectangle object, or if any of invoking rectangle's corner lies 
   within Rectangle r; return true or false accordingly. 
   Note: This algorithm doesn't handle all cases when the two rectangles
         overlap!
  */ 
  public boolean intersect(Rectangle r) { 
    /* find r's upper-left corner's coordinates */ 
    int x = r.getUpperLeft().getX();  
    int y = r.getUpperLeft().getY(); 
    /* find r's length and width */
    int len = r.getLength(); 
    int wid = r.getWidth();  

    /* now find r's other corners */
    TwoDPoint upperRight = new TwoDPoint(x + len, y);
    TwoDPoint lowerLeft = new TwoDPoint(x, y + wid);
    TwoDPoint lowerRight = new TwoDPoint(x + len, y + wid);

    /* determine if any of Rectangle r's 4 corners lies on or
     within the boundary of the invoking rectangle */
    if (inside(r.getUpperLeft()) || inside(upperRight) 
        || inside(lowerLeft) || inside(lowerRight))
      return true;  

    /* if not returned, next find the corners of the
     invoking rectangle */
    x = upperLeft.getX(); // invoking rectangle's x-coordinate
    y = upperLeft.getY(); // invoking rectangle's y-coordinate
    upperRight = new TwoDPoint(x + length, y);
    lowerLeft = new TwoDPoint(x, y + width);
    lowerRight = new TwoDPoint(x + length, y + width);

    /* determine if any of the invoking rectangle's 4 corners 
     lies on or within the boundary of Rectangle r */
    if (r.inside(getUpperLeft()) || r.inside(upperRight) 
        || r.inside(lowerLeft) || r.inside(lowerRight))
      return true;  

    /* if not returned, the two rectangles do not intersect */
    return false;
  }
  /** return the area of the invoking Rectangle object */
  public int area() {
    return length * width;
  }
  /** return a String representation of the invoking Rectangle object */
  public String toString() {
    String s = upperLeft.toString();  // string for the upperLeft corner
    return new String("The upper-left corner has " + s + "; length = " + 
                      length + ", width = " + width);
  }

  /** a private method that determines if point p lies on or within 
   the bounday of the invoking Rectanle object */
  private boolean inside(TwoDPoint p) {
    int leftX = upperLeft.getX();  /* the x-coordinate of invoking 
                                    rectangle's left edge */
    int rightX = upperLeft.getX()+length; /* the x-coordinate of 
                                 invoking rectangle's right edge */
    int topY = upperLeft.getY();  /* the y-coordinate of invoking 
                                    rectangle's top edge */
    int bottomY = upperLeft.getY()+width; /* the y-coordinate of 
                                 invoking rectangle's bottom edge */
    /* determine if TwoDPoint p lies within the 4 rectangle edges */
    if (p.getX() >= leftX && p.getX() <= rightX 
        && p.getY() >= topY && p.getY() <= bottomY)
      return true;
    else
      return false;
  }
}    

