/** Represents a immutable two-dimensional rectangle, normally
 * used for representing the bounds of a planar object. */
public class Bounds {
	/** An object representing an empty bounding rectangle. */
	public static final Bounds EMPTY_BOUNDS = new Bounds(0, 0, 0, 0);

	private double x0;
	private double y0;
	private double x1;
	private double y1;

	private Bounds(double x0, double y0, double x1, double y1) {
		this.x0 = x0;
		this.y0 = y0;
		this.x1 = x1;
		this.y1 = y1;
	}

	/** Returns <code>true</code> if the given rectangle lies
	 * entirely within this rectangle, even if it shares a
	 * boundary with this rectangle. */
	public boolean contains(Bounds o) {
		if(o == EMPTY_BOUNDS) return true;
		if(this == EMPTY_BOUNDS) return false;
		return o.x0 >= this.x0 && o.y0 >= this.y0 &&
			o.x1 <= this.x1 && o.y1 <= this.y1;
	}

	/** Returns a bounding rectangle containing both this
	 * rectangle and the given rectangle. */
	public Bounds add(Bounds o) {
		if(this == EMPTY_BOUNDS) return o;
		if(o == EMPTY_BOUNDS) return this;
		if(o.contains(this)) return o;
		if(this.contains(o)) return this;
		return new Bounds(Math.min(this.x0, o.x0),
			Math.min(this.y0, o.y0),
			Math.max(this.x1, o.x1),
			Math.max(this.y1, o.y1));
	}

	/** Returns the least <code>x</code>-coordinate contained
	 * within this rectangle. */
	public double getX()      { return x0; }

	/** Returns the least <code>y</code>-coordinate contained
	 * within this rectangle. */
	public double getY()      { return y0; }

	/** Returns the width of this rectangle. */
	public double getWidth()  { return x1 - x0; }

	/** Returns the height of this rectangle. */
	public double getHeight() { return y1 - y0; }

	public String toString() {
		return "Bounds[" + x0 + "," + y1 + ":" + (x1 - x0) + "/" + (y1 - y0) + "]";
	}

	/** Returns a rectangle starting at the given x- and
	 * y-coordinates and extending for the given width and
	 * height. */
	public static Bounds create(double x, double y,
			double width, double height) {
		return new Bounds(x, y, x + width, y + height);
	}
}
