package com.baselet.control.basics.geom;

public class Rectangle {

	public int x;
	public int y;
	public int width;
	public int height;

	public Rectangle() {
		super();
	}

	/**
	 * TODO as with DimensionDouble and PointDouble, Rectangle should also contain only double values in future!
	 */
	public Rectangle(Double x, Double y, Double width, Double height) {
		this((int) Math.round(x), (int) Math.round(y), (int) Math.round(width), (int) Math.round(height));
	}

	public Rectangle(int x, int y, int width, int height) {
		this();
		setBounds(x, y, width, height);
	}

	public void setBounds(int x, int y, int width, int height) {
		this.x = x;
		this.y = y;
		this.width = width;
		this.height = height;
	}

	public int getX() {
		return x;
	}

	public int getX2() {
		return x + width;
	}

	public void setX(int x) {
		this.x = x;
	}

	public int getY() {
		return y;
	}

	public int getY2() {
		return y + height;
	}

	public PointDouble getUpperLeftCorner() {
		return new PointDouble(x, y);
	}

	public PointDouble getCenter() {
		return new PointDouble(x + width / 2, y + height / 2);
	}

	public void setY(int y) {
		this.y = y;
	}

	public int getWidth() {
		return width;
	}

	public void setWidth(int width) {
		this.width = width;
	}

	public int getHeight() {
		return height;
	}

	public Dimension getSize() {
		return new Dimension(width, height);
	}

	public void setHeight(int height) {
		this.height = height;
	}

	public void move(int diffX, int diffY) {
		x += diffX;
		y += diffY;
	}

	public void addBorder(int border) {
		x -= border;
		y -= border;
		width += border * 2;
		height += border * 2;
	}

	public boolean contains(Point p) {
		return contains(new Rectangle(p.getX(), p.getY(), 0, 0));
	}

	public boolean contains(Rectangle other) {
		return getX() <= other.getX() && getX2() >= other.getX2() && getY() <= other.getY() && getY2() >= other.getY2();
	}

	public void setLocation(int x, int y) {
		this.x = x;
		this.y = y;
	}

	public void setSize(int width, int height) {
		this.width = width;
		this.height = height;
	}

	public boolean intersects(Rectangle other) {
		if (getY2() < other.getY()) {
			return false;
		}
		if (getY() > other.getY2()) {
			return false;
		}
		if (getX2() < other.getX()) {
			return false;
		}
		if (getX() > other.getX2()) {
			return false;
		}
		return true;
	}

	/**
	 * move the bounds of this rectangle to the lowest upper/left and highest lower/right bounds
	 * eg: Rect(x=-1,y=2,x2=3,y2=5).merge(Rect(x=2,y=1,x2=5,y2=3))=Rect(x=-1,y=1,x2=5,y2=5)
	 */
	public void merge(Rectangle other) {
		// must store X2 and Y2 before changing this X and Y, otherwise information can be lost
		// eg: this(y=100,h=10) and other(y=50,h=10) -> this.y2 is 110 but would be changed to 60)
		int oldX2 = getX2();
		int oldY2 = getY2();
		setX(Math.min(getX(), other.getX()));
		setY(Math.min(getY(), other.getY()));
		setWidth(Math.max(oldX2, other.getX2()) - getX());
		setHeight(Math.max(oldY2, other.getY2()) - getY());
	}

	public static Rectangle mergeToLeft(Rectangle left, Rectangle right) {
		if (left == null) {
			left = right;
		}
		else {
			left.merge(right);
		}
		return left;
	}

	public Rectangle copy() {
		return new Rectangle(x, y, width, height);
	}

	public Rectangle copyInverted() {
		return new Rectangle(-x, -y, -width, -height);
	}

	public Rectangle subtract(Rectangle other) {
		return new Rectangle(x - other.x, y - other.y, width - other.width, height - other.height);
	}

	public Rectangle add(Rectangle other) {
		return new Rectangle(x + other.x, y + other.y, width + other.width, height + other.height);
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + height;
		result = prime * result + width;
		result = prime * result + x;
		result = prime * result + y;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj) {
			return true;
		}
		if (obj == null) {
			return false;
		}
		if (getClass() != obj.getClass()) {
			return false;
		}
		Rectangle other = (Rectangle) obj;
		if (height != other.height) {
			return false;
		}
		if (width != other.width) {
			return false;
		}
		if (x != other.x) {
			return false;
		}
		if (y != other.y) {
			return false;
		}
		return true;
	}

	@Override
	public String toString() {
		return "Rectangle [x=" + x + ", y=" + y + ", width=" + width + ", height=" + height + "]";
	}

}
