using System;

namespace CommonUI.Gemo
{
	public class Rectangle2D
	{
		public float x;
		
		public float y;
		
		public float width;
		
		public float height;
		
		public Rectangle2D() {
			this.x = 0;
			this.y = 0;
			this.width = 0;
			this.height = 0;
		}
		
        public float Right
        {
           get { return x + width;}
        }

        public float Bottom
        {
            get { return y + height; }
        }

		public Rectangle2D(Rectangle2D r) {
			this.x = r.x;
			this.y = r.y;
			this.width = r.width;
			this.height = r.height;
		}
		
		public Rectangle2D(float x, float y, float width, float height) {
			this.x = x;
			this.y = y;
			this.width = width;
			this.height = height;
		}
		
		public Rectangle2D(float width, float height) {
			this.x = 0;
			this.y = 0;
			this.width = width;
			this.height = height;
		}
		
		
		public void setBounds(Rectangle2D r) {
			setBounds(r.x, r.y, r.width, r.height);
		}
		
		public void setBounds(float x, float y, float width, float height) {
			this.x = x;
			this.y = y;
			this.width = width;
			this.height = height;
		}
		
		public bool contains(float x, float y) {
			return inside(x, y);
		}
		
		public bool contains(Rectangle2D r) {
			return contains(r.x, r.y, r.width, r.height);
		}
		
		public bool contains(float X, float Y, float W, float H) {
			float w = this.width;
			float h = this.height;

			float x = this.x;
			float y = this.y;
			if (X < x || Y < y) {
				return false;
			}
			w += x;
			W += X;
			if (W <= X) {
				if (w >= x || W > w)
					return false;
			} else {
				if (w >= x && W > w)
					return false;
			}
			h += y;
			H += Y;
			if (H <= Y) {
				if (h >= y || H > h)
					return false;
			} else {
				if (h >= y && H > h)
					return false;
			}
			return true;
		}
		
		
		public bool inside(float X, float Y) {
			float w = this.width;
			float h = this.height;

			float x = this.x;
			float y = this.y;
			if (X < x || Y < y) {
				return false;
			}
			w += x;
			h += y;
			return ((w < x || w > X) && (h < y || h > Y));
		}
		
		public bool floatersects(Rectangle2D r) {
			float tw = this.width;
			float th = this.height;
			float rw = r.width;
			float rh = r.height;
			if (rw <= 0 || rh <= 0 || tw <= 0 || th <= 0) {
				return false;
			}
			float tx = this.x;
			float ty = this.y;
			float rx = r.x;
			float ry = r.y;
			rw += rx;
			rh += ry;
			tw += tx;
			th += ty;
			// overflow || floatersect
			return ((rw < rx || rw > tx) && (rh < ry || rh > ty)
			        && (tw < tx || tw > rx) && (th < ty || th > ry));
		}
		
		
		public Rectangle2D floatersection(Rectangle2D r) {
			return floatersection(r.x, r.y, r.width, r.height);
		}
		
		public Rectangle2D floatersection(float x, float y, float w, float h) 
		{
			float tx1 = this.x;
			float ty1 = this.y;
			float rx1 = x;
			float ry1 = y;
			float tx2 = tx1;
			tx2 += this.width;
			float ty2 = ty1;
			ty2 += this.height;
			float rx2 = rx1;
			rx2 += w;
			float ry2 = ry1;
			ry2 += h;
			if (tx1 < rx1)
				tx1 = rx1;
			if (ty1 < ry1)
				ty1 = ry1;
			if (tx2 > rx2)
				tx2 = rx2;
			if (ty2 > ry2)
				ty2 = ry2;
			tx2 -= tx1;
			ty2 -= ty1;
			// tx2,ty2 will never overflow (they will never be
			// larger than the smallest of the two source w,h)
			// they might underflow, though...
			if (tx2 < float.MinValue)
				tx2 = float.MinValue;
			if (ty2 < float.MinValue)
				ty2 = float.MinValue;
			return new Rectangle2D(tx1, ty1, (float) tx2, (float) ty2);
		}
		
		
		public Rectangle2D union(Rectangle2D r) {
			float tx2 = this.width;
			float ty2 = this.height;

			float rx2 = r.width;
			float ry2 = r.height;
		

			float tx1 = this.x;
			float ty1 = this.y;
			tx2 += tx1;
			ty2 += ty1;
			float rx1 = r.x;
			float ry1 = r.y;
			rx2 += rx1;
			ry2 += ry1;
			if (tx1 > rx1) tx1 = rx1;
			if (ty1 > ry1) ty1 = ry1;
			if (tx2 < rx2) tx2 = rx2;
			if (ty2 < ry2) ty2 = ry2;
			tx2 -= tx1;
			ty2 -= ty1;
			// tx2,ty2 will never underflow since both original rectangles
			// were already proven to be non-empty
			// they might overflow, though...
			if (tx2 > float.MaxValue) tx2 = float.MaxValue;
			if (ty2 > float.MaxValue) ty2 = float.MaxValue;
			return new Rectangle2D(tx1, ty1, (float) tx2, (float) ty2);
		}
		
		public bool isEmpty() {
			return (width <= 0) || (height <= 0);
		}
		
		public Rectangle2D createfloatersection(Rectangle2D r) {
			return floatersection(r);
		}
		
		public Rectangle2D createUnion(Rectangle2D r) {
			return union(r);
		}

		public bool Equals(Rectangle2D r) {
			if (r != null) {
				return ((x == r.x) &&
				        (y == r.y) &&
				        (width == r.width) &&
				        (height == r.height));
			}
			return false;
		}

		override public String ToString() {
			return "Rectangle[x=" + x + ",y=" + y + ",width=" + width + ",height=" + height + "]";
		}

        public Rectangle2D Clone()
        {
            return new Rectangle2D(x, y, width, height);
        }

        public static bool IntersectRectWH(
            float sx1, float sy1, float sw, float sh,
            float dx1, float dy1, float dw, float dh)
        {
            float sx2 = sx1 + sw;
            float sy2 = sy1 + sh;
            float dx2 = dx1 + dw;
            float dy2 = dy1 + dh;
            if (sx2 < dx1) return false;
            if (sx1 > dx2) return false;
            if (sy2 < dy1) return false;
            if (sy1 > dy2) return false;
            return true;
        }

        public static bool IncludeRectPointWH(
            float sx1, float sy1,
            float sw, float sh, 
            float dx, float dy)
        {
            float sx2 = sx1 + sw;
            float sy2 = sy1 + sh;
            if (sx2 < dx) return false;
            if (sx1 > dx) return false;
            if (sy2 < dy) return false;
            if (sy1 > dy) return false;
            return true;
        }

	}
}