namespace RyzStudio.Windows.ThemedForms
{
    using System;
    using System.ComponentModel;
    using System.Drawing;
    using System.Drawing.Design;
    using System.Windows.Forms;

    public partial class BorderlessForm : System.Windows.Forms.Form
    {
        protected bool isBusy = false;

        protected Color topFillColour = Color.FromArgb(15, 15, 15);
        protected int topFillHeight = 48;
        protected Color bottomFillColour = Color.FromArgb(15, 15, 15);
        protected int bottomFillMargin = 19;
        protected int bottomLeftMargin = 20;
        protected int borderWidth = 1;
        protected int menuFillWidth = 160;
        protected Color menuFillColour = Color.FromArgb(179, 179, 179);

        private bool windowDragging = false;
        private Point windowOffset = new Point();
        private Point windowSize = new Point();

        public BorderlessForm() : base()
        {
            this.InitializeComponent();

            this.BackColor = Color.FromArgb(247, 247, 247);
            this.FormBorderStyle = FormBorderStyle.None;
            this.Padding = new Padding(1);

			this.topFillColour = Color.FromArgb(51, 51, 51);
			this.topFillHeight = 48;
			this.bottomFillColour = Color.FromArgb(0, 152, 167);
			this.bottomFillMargin = 6;

            pictureBox1.Click += pictureBox1_Click;
            pictureBox2.Click += pictureBox2_Click;
            pictureBox3.Click += pictureBox3_Click;
            pictureBox4.Click += pictureBox4_Click;

            updatePictureBox2Image();
        }

        protected override void OnClosing(CancelEventArgs e)
        {
            base.OnClosing(e);

            if (this.IsBusy)
            {
                e.Cancel = true;
            }
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            Graphics g = e.Graphics;

            Rectangle areaTop = new Rectangle(this.DisplayRectangle.Left, this.Padding.Top, this.DisplayRectangle.Width, topFillHeight);
            Rectangle areaBottom = new Rectangle(this.DisplayRectangle.Left, (this.DisplayRectangle.Height - bottomFillMargin + this.Padding.Top), this.DisplayRectangle.Width, bottomFillMargin);
            Rectangle areaBorder = new Rectangle(this.ClientRectangle.X, this.ClientRectangle.Y, this.ClientRectangle.Width - borderWidth, this.ClientRectangle.Height - borderWidth);

            Rectangle areaMenu = new Rectangle(this.DisplayRectangle.Left, this.DisplayRectangle.Top + topFillHeight, menuFillWidth, (this.DisplayRectangle.Height - bottomFillMargin - topFillHeight));

            // draw header
            if (topFillHeight > 0)
            {
                g.FillRectangle(new SolidBrush(topFillColour), areaTop);
            }

            // fill menu
            g.FillRectangle(new SolidBrush(menuFillColour), areaMenu);

            // draw footer
            if (bottomFillMargin > 0)
            {
                g.FillRectangle(new SolidBrush(bottomFillColour), areaBottom);
            }

            // draw logo
            if (this.TitleLogo != null)
            {
                g.DrawImageUnscaled(this.TitleLogo, this.Padding.Left, this.Padding.Top);
            }

            if (this.Banner != null)
            {
                g.DrawImageUnscaled(this.Banner, this.Padding.Left + bottomLeftMargin, (this.DisplayRectangle.Height - this.Banner.Height - bottomFillMargin + this.Padding.Top), (this.DisplayRectangle.Width - (this.Padding.Left + this.Padding.Right)), this.Banner.Height);
            }

            g.DrawRectangle(new Pen(Color.Black, borderWidth), areaBorder);
        }

        protected override void OnResize(EventArgs e)
        {
            base.OnResize(e);

            updatePictureBox2Image();

            this.Invalidate();
        }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new Color BackColor { get => base.BackColor; set => base.BackColor = value; }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new FormBorderStyle FormBorderStyle { get => base.FormBorderStyle; set => base.FormBorderStyle = value; }

        [Browsable(false), EditorBrowsable(EditorBrowsableState.Never)]
        public new Padding Padding { get => base.Padding; set => base.Padding = value; }

        [Category("Appearance"), Browsable(true)]
        public string Description
        {
            get
            {
                return label1.Text?.Replace("\n", "\\n");
            }
            set
            {
                label1.Text = value?.Replace("\\n", "\n");
            }
        }

        [Category("Appearance"), Browsable(true)]
        public Image TitleLogo { get; set; }

        [Category("Appearance"), Browsable(true)]
        public Image Banner { get; set; }

        [Category("Appearance"), Browsable(true)]
        public bool ShowMenuButton { get => pictureBox4.Visible; set => pictureBox4.Visible = value; }

        protected virtual bool IsBusy { get => isBusy; set => isBusy = value; }

        private void pictureBox4_Click(object sender, System.EventArgs e)
        {
            //this.WindowState = FormWindowState.Minimized;
        }

        private void pictureBox1_Click(object sender, System.EventArgs e)
        {
            MouseEventArgs mouseEvent = (MouseEventArgs)e;
            if (mouseEvent != null)
            {
                if (mouseEvent.Button != MouseButtons.Left)
                {
                    return;
                }
            }

            this.WindowState = FormWindowState.Minimized;
        }

        private void pictureBox2_Click(object sender, System.EventArgs e)
        {
            MouseEventArgs mouseEvent = (MouseEventArgs)e;
            if (mouseEvent != null)
            {
                if (mouseEvent.Button != MouseButtons.Left)
                {
                    return;
                }
            }

            if (this.WindowState == FormWindowState.Maximized)
            {
                this.WindowState = FormWindowState.Normal;
                pictureBox2.NormalImage = Resources.form20_maximise;
                pictureBox2.HighlightImage = Resources.form20_maximise2;
            }
            else
            {
                this.WindowState = FormWindowState.Maximized;
                pictureBox2.NormalImage = Resources.form20_restore;
                pictureBox2.HighlightImage = Resources.form20_restore2;
            }
        }

        private void pictureBox3_Click(object sender, System.EventArgs e)
        {
            MouseEventArgs mouseEvent = (MouseEventArgs)e;
            if (mouseEvent != null)
            {
                if (mouseEvent.Button != MouseButtons.Left)
                {
                    return;
                }
            }

            this.Close();
        }

        public void SetValue(Label sender, string value)
        {
            if (sender.InvokeRequired)
            {
                sender.Invoke(new MethodInvoker(() => { sender.Text = value; }));
            }
            else
            {
                sender.Text = value;
            }
        }

        public void SetValue(GroupBox sender, string value)
        {
            if (sender.InvokeRequired)
            {
                sender.Invoke(new MethodInvoker(() => { sender.Text = value; }));
            }
            else
            {
                sender.Text = value;
            }
        }

        public void AddValue(ListBox sender, string value)
        {
            if (sender.InvokeRequired)
            {
                sender.Invoke(new MethodInvoker(() => { sender.Items.Add(value); }));
            }
            else
            {
                sender.Items.Add(value);
            }
        }

        public void AddControl(FlowLayoutPanel sender, Control value)
        {
            if (sender.InvokeRequired)
            {
                sender.Invoke(new MethodInvoker(() =>
                {
                    sender.Controls.Add(value);
                }));
            }
            else
            {
                sender.Controls.Add(value);
            }
        }

        public void ClearValues(ListBox sender)
        {
            if (sender.InvokeRequired)
            {
                sender.Invoke(new MethodInvoker(() => { sender.Items.Clear(); }));
            }
            else
            {
                sender.Items.Clear();
            }
        }

        public string GetValue(ListBox sender)
        {
            string rv = string.Empty;

            if (sender.InvokeRequired)
            {
                sender.Invoke(new MethodInvoker(() => { rv = (sender.SelectedItem == null) ? string.Empty : sender.SelectedItem.ToString(); }));
            }
            else
            {
                rv = (sender.SelectedItem == null) ? string.Empty : sender.SelectedItem.ToString();
            }

            return rv;
        }

        public string GetValue(TextBox sender)
        {
            string rv = string.Empty;

            if (sender.InvokeRequired)
            {
                sender.Invoke(new MethodInvoker(() => { rv = sender.Text.Trim(); }));
            }
            else
            {
                rv = sender.Text.Trim();
            }

            return rv;
        }

        public int GetValue(NumericUpDown sender)
        {
            int rv = 0;

            if (sender.InvokeRequired)
            {
                sender.Invoke(new MethodInvoker(() => { rv = (int)sender.Value; }));
            }
            else
            {
                rv = (int)sender.Value;
            }

            return rv;
        }

        protected void updatePictureBox2Image()
        {
            if (this.WindowState == FormWindowState.Maximized)
            {
                pictureBox2.NormalImage = Resources.form20_restore;
                pictureBox2.HighlightImage = Resources.form20_restore2;
            }
            else
            {
                pictureBox2.NormalImage = Resources.form20_maximise;
                pictureBox2.HighlightImage = Resources.form20_maximise2;
            }
        }

        private void label1_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button != MouseButtons.Left)
            {
                return;
            }

            windowDragging = true;
            windowOffset = e.Location;
        }

        private void label1_MouseUp(object sender, MouseEventArgs e)
        {
            windowDragging = false;
        }

        private void label1_MouseMove(object sender, MouseEventArgs e)
        {
            if (windowDragging)
            {
                Point currentScreenPos = PointToScreen(e.Location);
                Location = new Point(currentScreenPos.X - windowOffset.X, currentScreenPos.Y - windowOffset.Y);
            }
        }

        private void label1_DoubleClick(object sender, EventArgs e) => pictureBox2_Click(sender, e);

        private void label1_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Middle)
            {
                this.TopMost = !this.TopMost;
            }
        }

        private void panel1_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button != MouseButtons.Left)
            {
                return;
            }

            windowDragging = true;
            windowOffset = e.Location;
            windowSize = new Point(this.Width, this.Height);
        }

        private void panel1_MouseUp(object sender, MouseEventArgs e)
        {
            windowDragging = false;
        }

        private void panel1_MouseMove(object sender, MouseEventArgs e)
        {
            if (windowDragging)
            {
                this.Size = new Size(e.X - windowOffset.X + this.Width, e.Y - windowOffset.Y + this.Height);
            }
        }

        private void panel2_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button != MouseButtons.Left)
            {
                return;
            }

            windowDragging = true;
            windowOffset = e.Location;
            windowSize = new Point(this.Width, this.Height);
        }

        private void panel2_MouseUp(object sender, MouseEventArgs e)
        {
            windowDragging = false;
        }

        private void panel2_MouseMove(object sender, MouseEventArgs e)
        {
            if (windowDragging)
            {
                this.Size = new Size(windowSize.X, e.Y - windowOffset.Y + this.Height);
            }
        }

    }
}