using System;
using System.Collections.Generic;
using System.Drawing;
using System.Xml;

namespace ZionVault.Basic
{
    public class Location : IDisposable
    {
        private double top;
        private double right;
        private double bottom;
        private double left;

        public double Top { get => top; set => top = value; }
        public double Right { get => right; set => right = value; }
        public double Bottom { get => bottom; set => bottom = value; }
        public double Left { get => left; set => left = value; }

        public double Height { get => Bottom - Top; }

        public double Width { get => Right - Left; }

        public System.Drawing.Rectangle Rectangle
        {
            get
            {
                double left = (this.Left < 0) ? 0 : this.Left;
                double top = (this.Top < 0) ? 0 : this.Top;
                double right = (this.Right < 0) ? 0 : this.Right;
                double bottom = (this.Bottom < 0) ? 0 : this.Bottom;

                return new System.Drawing.Rectangle(
                    (int)left,
                    (int)top,
                    (int)((right - left < 0) ? -1 : (right - left)),
                    (int)((bottom - top < 0) ? -1 : (bottom - top)));
            }
        }

        public void Dispose() => GC.SuppressFinalize(this);

        public Rectangle Rect
        {
            get
            {
                int left = (this.left < 0) ? 0 : int.Parse(this.left.ToString());
                int top = (this.top < 0) ? 0 : int.Parse(this.top.ToString());
                int right = (this.right < 0) ? 0 : int.Parse(this.right.ToString());
                int bottom = (this.bottom < 0) ? 0 : int.Parse(this.bottom.ToString());

                return new System.Drawing.Rectangle(
                    left,
                    top,
                    (right - left < 0) ? -1 : (right - left),
                    (bottom - top < 0) ? -1 : (bottom - top));
            }
        }

        public Location(int top, int right, int bottom, int left)
        {
            this.top = top;
            this.right = right;
            this.bottom = bottom;
            this.left = left;
        }

        public Location(double top, double right, double bottom, double left)
        {
            this.top = top;
            this.right = right;
            this.bottom = bottom;
            this.left = left;
        }

        public Location(XmlNode element)
        {
            this.top = double.Parse(element.Attributes[@"Top"].Value);
            this.right = double.Parse(element.Attributes[@"Right"].Value);
            this.bottom = double.Parse(element.Attributes[@"Bottom"].Value);
            this.left = double.Parse(element.Attributes[@"Left"].Value);
        }

        public Location(string value)
        {
            try
            {
                string[] values = value.Split(';');
                top = double.Parse(values[0]);
                right = double.Parse(values[1]);
                bottom = double.Parse(values[2]);
                left = double.Parse(values[3]);
            }
            catch
            {
                top = 0;
                right = 0;
                bottom = 0;
                left = 0;
            }
        }

        public Rectangle Proportion(int width, int height)
        {
            int left = (int)((this.Left < 0) ? 0 : this.Left);
            int top = (int)((this.Top < 0) ? 0 : this.Top);
            int right = (int)((this.Right < 0) ? 0 : this.Right);
            int bottom = (int)((this.Bottom < 0) ? 0 : this.Bottom);

            return new Rectangle(
                (int)((left / 100.0) * width),
                (int)((top / 100.0) * height),
                (int)((right - left < 0) ? -1 : ((right - left) / 100) * width),
                (int)((bottom - top < 0) ? -1 : ((bottom - top) / 100) * height));
        }

        public override string ToString()
        {
            return string.Format("{0};{1};{2};{3}", top, right, bottom, left);
        }

        public override bool Equals(object obj)
        {
            return obj is Location location &&
                   Bottom == location.Bottom &&
                   Left == location.Left &&
                   Right == location.Right &&
                   Top == location.Top &&
                   EqualityComparer<Rectangle>.Default.Equals(Rectangle, location.Rectangle);
        }

        public override int GetHashCode()
        {
            var hashCode = 11155026;
            hashCode = hashCode * -1521134295 + Bottom.GetHashCode();
            hashCode = hashCode * -1521134295 + Left.GetHashCode();
            hashCode = hashCode * -1521134295 + Right.GetHashCode();
            hashCode = hashCode * -1521134295 + Top.GetHashCode();
            hashCode = hashCode * -1521134295 + EqualityComparer<Rectangle>.Default.GetHashCode(Rectangle);
            return hashCode;
        }

        public XmlElement Export(XmlDocument document)
        {
            XmlElement location = document.CreateElement(@"area");
            location.SetAttribute(@"Top", Top.ToString());
            location.SetAttribute(@"Right", Right.ToString());
            location.SetAttribute(@"Bottom", Bottom.ToString());
            location.SetAttribute(@"Left", Left.ToString());

            return location;
        }

        public void AppendTo(XmlDocument doc, XmlNode parent)
        {
            XmlElement location = doc.CreateElement("Area");

            location.SetAttribute(@"Top", Top.ToString());
            location.SetAttribute(@"Right", Right.ToString());
            location.SetAttribute(@"Bottom", Bottom.ToString());
            location.SetAttribute(@"Left", Left.ToString());

            parent.AppendChild(location);
        }
    }
}
