#region Copyright & License Information
/*
 * Copyright 2007-2020 The OpenRA Developers (see AUTHORS)
 * This file is part of OpenRA, which is free software. It is made
 * available to you under the terms of the GNU General Public License
 * as published by the Free Software Foundation, either version 3 of
 * the License, or (at your option) any later version. For more
 * information, see COPYING.
 */
#endregion

using System;

namespace OpenRA.Primitives
{
	public struct Rectangle : IEquatable<Rectangle>
	{
		// TODO: Make these readonly: this will require a lot of changes to the UI logic
		public int X;
		public int Y;
		public int Width;
		public int Height;
		public static readonly Rectangle Empty;

		public static Rectangle FromLTRB(int left, int top, int right, int bottom)
		{
			return new Rectangle(left, top, right - left, bottom - top);
		}

		public static Rectangle Union(Rectangle a, Rectangle b)
		{
			return FromLTRB(Math.Min(a.Left, b.Left), Math.Min(a.Top, b.Top), Math.Max(a.Right, b.Right), Math.Max(a.Bottom, b.Bottom));
		}

		public static bool operator ==(Rectangle left, Rectangle right)
		{
			return left.Location == right.Location && left.Size == right.Size;
		}

		public static bool operator !=(Rectangle left, Rectangle right)
		{
			return !(left == right);
		}

		public Rectangle(int x, int y, int width, int height)
		{
			X = x;
			Y = y;
			Width = width;
			Height = height;
		}

		public Rectangle(int2 location, Size size)
		{
			X = location.X;
			Y = location.Y;
			Width = size.Width;
			Height = size.Height;
		}

		public int Left { get { return X; } }
		public int Right { get { return X + Width; } }
		public int Top { get { return Y; } }
		public int Bottom { get { return Y + Height; } }
		public bool IsEmpty { get { return X == 0 && Y == 0 && Width == 0 && Height == 0; } }
		public int2 Location { get { return new int2(X, Y); } }
		public Size Size { get { return new Size(Width, Height); } }

		public int2 TopLeft { get { return Location; } }
		public int2 TopRight { get { return new int2(X + Width, Y); } }
		public int2 BottomLeft { get { return new int2(X, Y + Height); } }
		public int2 BottomRight { get { return new int2(X + Width, Y + Height); } }

		public bool Contains(int x, int y)
		{
			return x >= Left && x < Right && y >= Top && y < Bottom;
		}

		public bool Contains(int2 pt)
		{
			return Contains(pt.X, pt.Y);
		}

		public bool Equals(Rectangle other)
		{
			return this == other;
		}

		public override bool Equals(object obj)
		{
			if (!(obj is Rectangle))
				return false;

			return this == (Rectangle)obj;
		}

		public override int GetHashCode()
		{
			return Height + Width ^ X + Y;
		}

		public bool IntersectsWith(Rectangle rect)
		{
			return Left < rect.Right && Right > rect.Left && Top < rect.Bottom && Bottom > rect.Top;
		}

		bool IntersectsWithInclusive(Rectangle r)
		{
			return Left <= r.Right && Right >= r.Left && Top <= r.Bottom && Bottom >= r.Top;
		}

		public static Rectangle Intersect(Rectangle a, Rectangle b)
		{
			if (!a.IntersectsWithInclusive(b))
				return Empty;

			return FromLTRB(Math.Max(a.Left, b.Left), Math.Max(a.Top, b.Top), Math.Min(a.Right, b.Right), Math.Min(a.Bottom, b.Bottom));
		}

		public bool Contains(Rectangle rect)
		{
			return rect == Intersect(this, rect);
		}

		public static Rectangle operator *(int a, Rectangle b) { return new Rectangle(a * b.X, a * b.Y, a * b.Width, a * b.Height); }

		public override string ToString()
		{
			return string.Format("{{X={0},Y={1},Width={2},Height={3}}}", X, Y, Width, Height);
		}
	}
}
