#region << Using Directives >>
using System;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
#endregion
namespace Volpe.Cafe.UI
{
    public class NavButton : Control
    {
        #region 
        public event EventHandler MouseLeftClick;
        #endregion
        #region 
        public NavButton()
        {
            this.InitializeComponent();
            this.DoubleBuffered = true;
        }
        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
        }
        #endregion
        #region 
        #region 
        protected virtual void OnMouseLeftClick(MouseEventArgs e)
        {
            if (this.MouseLeftClick != null)
            {
                this.MouseLeftClick(this, e);
            }
        }
        #endregion
        #region 
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            this.PaintImage (e.Graphics);
            this.PaintText  (e.Graphics);
            this.PaintBorder(e.Graphics);
        }
        protected override void OnPaintBackground(PaintEventArgs e)
        {
            base.OnPaintBackground(e);
            Graphics  g    = e.Graphics;
            Rectangle rect = new Rectangle(0, 0, this.Width, this.Height);
            if (this._mouseHover) { g.FillRectangle(new SolidBrush(this._hoverBackColor), rect); }
            else                  { g.FillRectangle(new SolidBrush(this.BackColor      ), rect); }
        }
        void PaintImage(Graphics g)
        {
            if (this._showImage && this._image != null)
            {
                int w = this.Width;
                int h = this.Height;
                Rectangle rect = new Rectangle((this._imageLeftAlign) ? 0 : w - h, 0, h, h);
                g.DrawImage(this._image, rect);
            }
        }
        void PaintText(Graphics g)
        {
            if (this._showText)
            {
                int w = this.Width;
                int h = this.Height;
                int tX = (this._showImage && this._imageLeftAlign) ? h + 4 : 0;
                int tW = (this._showImage) ? w - h - 4 : w;
                RectangleF textRect = new RectangleF(tX, 2, tW, h - 4);
                StringFormat sf = new StringFormat();
                if (!this._textLeftAlign) { sf.FormatFlags |= StringFormatFlags.DirectionRightToLeft; }
                g.DrawString(this.Text, this.Font, new SolidBrush(this.ForeColor), textRect, sf);
            }
        }
        void PaintBorder(Graphics g)
        {
            Rectangle rect = new Rectangle(0, 0, this.Width, this.Height);
            if      (this._mouseDown ) { ControlPaint.DrawBorder(g, rect, Control.DefaultBackColor, ButtonBorderStyle.Inset); }
            else if (this._mouseHover) { ControlPaint.DrawBorder(g, rect, this._hoverBorderColor  , this._hoverBorderStyle ); }
            else                       { ControlPaint.DrawBorder(g, rect, this._borderColor       , this._borderStyle      ); }
        }
        #endregion
        #region 
        void ProcessMouseMove(int x, int y)
        {
            if (this.IsOutOfBounds(x, y))
            {   
                this.ProcessMouseLeave();
            }
            else if (!this._mouseHover)
            {
                this.BeginUpdate();
                this._mouseHover = true;
                this.BringToFront();
                this.EndUpdate();
            }
        }
        void ProcessMouseLeave()
        {
            if (this._mouseHover)
            {
                this.BeginUpdate();
                this._mouseHover = false;
                this._mouseDown = false;
                this.EndUpdate();
            }
        }
        void ProcessLMouseDown(int x, int y)
        {
            if (!this._mouseDown)
            {
                this.BeginUpdate();
                this._mouseDown = true;
                this.EndUpdate();
            }
        }
        void ProcessLMouseUp(int x, int y)
        {
            if (this._mouseDown)
            {
                this.BeginUpdate();
                this._mouseDown = false;
                this.ProcessMouseLeave();
                this.EndUpdate();
                this.OnMouseLeftClick(new MouseEventArgs(MouseButtons.Left, 1, x, y, 0));
            }
        }
        #endregion
        protected override void OnSizeChanged(EventArgs e)
        {
            this.Invalidate();
            base.OnSizeChanged(e);
        }
        protected override void WndProc(ref Message m)
        {
            IntPtr lParam = m.LParam;
            int x = Win32.LoWord(lParam.ToInt32());
            int y = Win32.HiWord(lParam.ToInt32());
            switch ((Win32.Messages)m.Msg)
            {
                case Win32.Messages.WM_MOUSEMOVE:
                    this.ProcessMouseMove(x, y);
                    break;
                case Win32.Messages.WM_MOUSELEAVE:
                    this.ProcessMouseLeave();
                    break;
                case Win32.Messages.WM_LBUTTONDOWN:
                    this.ProcessLMouseDown(x, y);
                    break;
                case Win32.Messages.WM_LBUTTONUP:
                    this.ProcessLMouseUp(x, y);
                    break;
            }
            try
            {   
                base.WndProc(ref m);
            }
            catch (Exception ex) { Console.WriteLine(ex.ToString()); }
        }
        public override void Refresh()
        {
            this.ProcessMouseLeave();
            base.Refresh();
        }
        void InitializeComponent()
        {
            this.Text = this.Name;
            this._showText = true;
            this._textLeftAlign = true;
            this._image = null;
            this._showImage = true;
            this._imageLeftAlign = true;
            this._borderStyle = ButtonBorderStyle.Solid;
            this._borderColor = SystemColors.ControlDark;
            this._hoverBorderStyle = ButtonBorderStyle.Outset;
            this._hoverBorderColor = SystemColors.Control;
            this._hoverBackColor   = SystemColors.Control;
        }
        void BeginUpdate()
        {
            Win32.BeginUpdate(this, ref this._updateCount, ref this._eventMask);
        }
        void EndUpdate()
        {
            Win32.EndUpdate(this, ref this._updateCount, ref this._eventMask);
            base.Refresh();
        }
        bool IsOutOfBounds(Point pt)
        {
            return this.IsOutOfBounds(pt.X, pt.Y);
        }
        bool IsOutOfBounds(int x, int y)
        {
            int xl = 0, yl = 0, xr = this.Width, yr = this.Height;
            return (x < xl || y < yl || x > xr || y > yr);
        }
        #endregion
        #region 
        [Category("Appearance")]
        [Description("Indicates whether the text should be displayed on the control.")]
        [DefaultValue(true)]
        public bool ShowText { get { return this._showText; } set { this._showText = value; base.Refresh(); } }
        [Category("Appearance")]
        [Description("Indicates whether the text should be left-aligned (true), or right-aligned (false).")]
        [DefaultValue(true)]
        public bool TextLeftAlign { get { return this._textLeftAlign; } set { this._textLeftAlign = value; base.Refresh(); } }
        [Category("Appearance")]
        [Description("The image associated with the control.")]
        [DefaultValue(null)]
        public Image Image { get { return this._image; } set { this._image = value; base.Refresh(); } }
        [Category("Appearance")]
        [Description("Indicates whether an image should be displayed on the control.")]
        [DefaultValue(true)]
        public bool ShowImage { get { return this._showImage; } set { this._showImage = value; base.Refresh(); } }
        [Category("Appearance")]
        [Description("Indicates whether an image should be left-aligned (true), or right-aligned (false).")]
        [DefaultValue(true)]
        public bool ImageLeftAlign { get { return this._imageLeftAlign; } set { this._imageLeftAlign = value; base.Refresh(); } }
        [Category("Appearance")]
        [Description("Determines whether the control has a border.")]
        [DefaultValue(typeof(ButtonBorderStyle), "Solid")]
        public ButtonBorderStyle BorderStyle { get { return this._borderStyle; } set { this._borderStyle = value; base.Refresh(); } }
        [Category("Appearance")]
        [Description("If the control has a visible border, indicates the border color for the control.")]
        [DefaultValue(typeof(Color), "ControlDark")]
        public Color BorderColor { get { return this._borderColor; } set { this._borderColor = value; base.Refresh(); } }
        [Category("Appearance")]
        [Description("The border style for the control, when the mouse is hovering over it.")]
        [DefaultValue(typeof(ButtonBorderStyle), "Outset")]
        public ButtonBorderStyle HoverBorderStyle { get { return this._hoverBorderStyle; } set { this._hoverBorderStyle = value; } }
        [Category("Appearance")]
        [Description("The border color of the control, when the mouse is hovering over it.")]
        [DefaultValue(typeof(Color), "Control")]
        public Color HoverBorderColor { get { return this._hoverBorderColor; } set { this._hoverBorderColor = value; } }
        [Category("Appearance")]
        [Description("The background color of the control, when the mouse is hovering over it.")]
        [DefaultValue(typeof(Color), "Control")]
        public Color HoverBackColor { get { return this._hoverBackColor; } set { this._hoverBackColor = value; } }
        #endregion
        #region 
        bool _showText;
        bool _textLeftAlign;
        Image _image;
        bool  _showImage;
        bool  _imageLeftAlign;
        ButtonBorderStyle _borderStyle;
        Color             _borderColor;
        ButtonBorderStyle _hoverBorderStyle;
        Color             _hoverBorderColor;
        Color             _hoverBackColor;
        bool _mouseDown = false;
        bool _mouseHover = false;
        int _updateCount = 0;
        int _eventMask = 0;
        #endregion
    }
}

