using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Drawing;
using System.Security.Permissions;
using System.Runtime.InteropServices;
using DevComponents.DotNetBar.Rendering;
namespace DevComponents.DotNetBar.Controls
{
    internal class PopupControlHost : ToolStripDropDown
    {
        #region Constructor
        private ePopupResizeEdge _ResizeEdge = ePopupResizeEdge.None;
        private Rectangle _ResizeGripBounds = Rectangle.Empty;
        private bool _CanResizeHostControl = false;
        private bool _CanResizePopup = false;
        private bool _RefreshSize = false;
        private static readonly Size ResizeGripSize = new Size(16, 16);
        public PopupControlHost()
        {
            this.AutoSize = false;
            this.Padding = System.Windows.Forms.Padding.Empty;
            this.Margin = System.Windows.Forms.Padding.Empty;
        }
        #endregion
        #region Implementation
        protected override void OnClosing(ToolStripDropDownClosingEventArgs e)
        {
            Control hostControl = GetHostedControl();
            if (hostControl != null)
                hostControl.SizeChanged -= HostControlSizeChanged;
            base.OnClosing(e);
        }
        protected override void OnPaint(PaintEventArgs e)
        {
            ResizeGripBounds = Rectangle.Empty;
            Size resizeGripSize = Dpi.Size(ResizeGripSize);
            if (IsResizeEnabled(ePopupResizeEdge.BottomLeft))
            {
                ResizeGripColors colors = GetColors();
                using (SolidBrush brush = new SolidBrush(colors.BackColor))
                    e.Graphics.FillRectangle(brush, 1, Height - resizeGripSize.Height, Width - 2, resizeGripSize.Height - 1);
                ResizeGripBounds = new Rectangle(1, Height - resizeGripSize.Height, resizeGripSize.Width, resizeGripSize.Height);
                ResizeHandlePainter.DrawResizeHandle(e.Graphics, ResizeGripBounds, colors.GripLightColor, colors.GripColor, true);
            }
            else if (IsResizeEnabled(ePopupResizeEdge.BottomRight))
            {
                ResizeGripColors colors = GetColors();
                using (SolidBrush brush = new SolidBrush(colors.BackColor))
                    e.Graphics.FillRectangle(brush, 1, Height - resizeGripSize.Height, Width - 2, resizeGripSize.Height - 1);
                ResizeGripBounds = new Rectangle(Width - resizeGripSize.Width - 1, Height - resizeGripSize.Height, resizeGripSize.Width, resizeGripSize.Height);
                ResizeHandlePainter.DrawResizeHandle(e.Graphics, ResizeGripBounds, colors.GripLightColor, colors.GripColor, false);
            }
            base.OnPaint(e);
        }
        private ResizeGripColors _ResizeGripColors;
        private ResizeGripColors GetColors()
        {
            return _ResizeGripColors;
        }
        #region ResizeGripColors
        private struct ResizeGripColors
        {
            public Color BackColor;
            public Color GripLightColor;
            public Color GripColor;
            /// 
            /// Initializes a new instance of the ResizeGripColors structure.
            /// 
            /// 
            /// 
            /// 
            public ResizeGripColors(Color backColor, Color gripLightColor, Color gripColor)
            {
                BackColor = backColor;
                GripLightColor = gripLightColor;
                GripColor = gripColor;
            }
        }
        #endregion
        private bool _PopupUserSize = false;
        /// 
        /// Gets whether popup has been resized by end-user.
        /// 
        public bool PopupUserSize
        {
            get { return _PopupUserSize; }
            set { _PopupUserSize = value; }
        }
        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);
            if (!_CanResizePopup)
            {
                UpdateHostControlSize();
                _PopupUserSize = true;
            }
        }
        protected void HostControlSizeChanged(object sender, EventArgs e)
        {
            if (!_CanResizeHostControl)
                UpdateContentBasedSize(-1);
        }
        public new void Show(int x, int y)
        {
            Show(x, y, -1, -1);
        }
        public void Show(int x, int y, int width, int height)
        {
            if (GlobalManager.Renderer is Office2007Renderer)
            {
                Office2007ColorTable table = ((Office2007Renderer)GlobalManager.Renderer).ColorTable;
                _ResizeGripColors = new ResizeGripColors(table.Form.BackColor, table.LegacyColors.SplitterBackground2, table.LegacyColors.BarStripeColor);
            }
            else
                _ResizeGripColors = new ResizeGripColors(SystemColors.ButtonFace, Color.White, SystemColors.ControlDark);
            Control hostControl = GetHostedControl();
            if (hostControl == null)
                return;
            _CanResizeHostControl = true;
            _CanResizePopup = true;
            this.Size = new Size(1, 1);
            base.Show(x, y);
            _CanResizeHostControl = false;
            _CanResizePopup = false;
            UpdateContentBasedSize(width);
            if (_CloseButtonVisible && IsResizeGripShown)
            {
                if (_CloseButtonController == null)
                {
                    ButtonItem button = new ButtonItem();
                    button.Symbol = "\uf00d";
                    button.SymbolSize = 8;
                    button.Style = eDotNetBarStyle.StyleManagerControlled;
                    button.ButtonStyle = eButtonStyle.ImageAndText;
                    button.LeftInternal = 1;
                    button.Click += new EventHandler(ClosePopupButtonClick);
                    _CloseButtonController = new BaseItemController(button, this);
                    button.RecalcSize();
                    button.TopInternal = this.Height - button.HeightInternal - 1;
                }
            }
            else if (_CloseButtonController != null)
            {
                _CloseButtonController.Dispose();
                _CloseButtonController = null;
            }
            if (_RefreshSize)
                UpdateHostControlSize();
            if (y > Top && y <= Bottom)
            {
                if (_ParentControlBounds.IsEmpty)
                    Top = y - Height - (height != -1 ? height : 0);
                else
                    Top = _ParentControlBounds.Y - Height;
                //ePopupResizeEdge previous = ResizeEdge;
                //if (ResizeEdge == ePopupResizeEdge.BottomLeft)
                //    ResizeEdge = ePopupResizeEdge.None; // ePopupResizeEdge.TopLeft;
                //else if (ResizeEdge == ePopupResizeEdge.BottomRight)
                //    ResizeEdge = ePopupResizeEdge.None; // ePopupResizeEdge.TopRight;
                //if (ResizeEdge != previous)
                //    UpdateHostControlSize();
            }
            hostControl.SizeChanged += HostControlSizeChanged;
        }
        private Rectangle _ParentControlBounds = Rectangle.Empty;
        public Rectangle ParentControlBounds
        {
            get { return _ParentControlBounds; }
            set { _ParentControlBounds = value; }
        }
        private void ClosePopupButtonClick(object sender, EventArgs e)
        {
            this.Close(ToolStripDropDownCloseReason.CloseCalled);
        }
        BaseItemController _CloseButtonController = null;
        protected void UpdateContentBasedSize(int proposedWidth)
        {
            if (_CanResizePopup)
                return;
            _CanResizeHostControl = true;
            try
            {
                Rectangle bounds = Bounds;
                bounds.Size = SizeFromContent(proposedWidth);
                if (!IsResizeEnabled(ePopupResizeEdge.None))
                {
                    if (proposedWidth > 0 && bounds.Width - 2 > proposedWidth)
                        if (!IsResizeEnabled(ePopupResizeEdge.Right))
                            bounds.X -= bounds.Width - 2 - proposedWidth;
                }
                Bounds = bounds;
            }
            finally
            {
                _CanResizeHostControl = false;
            }
        }
        protected void UpdateHostControlSize()
        {
            if (_CanResizeHostControl)
                return;
            _CanResizePopup = true;
            try
            {
                Control hostedControl = GetHostedControl();
                if (hostedControl != null)
                {
                    Rectangle bounds = hostedControl.Bounds;
                    if (IsResizeEnabled(ePopupResizeEdge.TopLeft) || IsResizeEnabled(ePopupResizeEdge.TopRight))
                        bounds.Location = new Point(1, Dpi.Height(ResizeGripSize.Height));
                    else
                        bounds.Location = new Point(1, 1);
                    bounds.Width = ClientRectangle.Width - 2;
                    bounds.Height = ClientRectangle.Height - 2;
                    if (IsResizeGripShown)
                        bounds.Height -= Dpi.Height(ResizeGripSize.Height);
                    if (bounds.Size != hostedControl.Size)
                        hostedControl.Size = bounds.Size;
                    if (bounds.Location != hostedControl.Location)
                        hostedControl.Location = bounds.Location;
                    if (_CloseButtonController != null)
                    {
                        _CloseButtonController.Item.TopInternal = this.Height - _CloseButtonController.Item.HeightInternal - 1;
                    }
                }
            }
            finally
            {
                _CanResizePopup = false;
            }
        }
        public Control GetHostedControl()
        {
            if (Items.Count > 0)
            {
                ToolStripControlHost host = Items[0] as ToolStripControlHost;
                if (host != null)
                    return host.Control;
            }
            return null;
        }
        public bool IsResizeEnabled(ePopupResizeEdge edge)
        {
            return (ResizeEdge & edge) == edge;
        }
        protected Size SizeFromContent(int proposedWidth)
        {
            Size contentSize = Size.Empty;
            _RefreshSize = false;
            // Fetch hosted control.
            Control hostedControl = GetHostedControl();
            if (hostedControl != null)
            {
                if (IsResizeEnabled(ePopupResizeEdge.TopLeft) || IsResizeEnabled(ePopupResizeEdge.TopRight))
                    hostedControl.Location = new Point(1, Dpi.Height16);
                else
                    hostedControl.Location = new Point(1, 1);
                contentSize = SizeFromClientSize(hostedControl.Size);
                // Use minimum width (if specified).
                if (proposedWidth > 0 && contentSize.Width < proposedWidth)
                {
                    contentSize.Width = proposedWidth;
                    _RefreshSize = true;
                }
            }
            // If a grip box is shown then add it into the drop down height.
            if (IsResizeGripShown)
                contentSize.Height += Dpi.Height16;
            // Add some additional space to allow for borders.
            contentSize.Width += 2;
            contentSize.Height += 2;
            return contentSize;
        }
        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        protected override void WndProc(ref Message m)
        {
            if (!ProcessResizeGripMessages(ref m, false))
                base.WndProc(ref m);
        }
        /// 
        /// Processes the resizing messages.
        /// 
        /// The message.
        /// true, if the WndProc method from the base class shouldn't be invoked.
        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        public bool ProcessResizeGripMessages(ref Message m)
        {
            return ProcessResizeGripMessages(ref m, true);
        }
        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        private bool ProcessResizeGripMessages(ref Message m, bool contentControl)
        {
            if (ResizeEdge != ePopupResizeEdge.None)
            {
                if (m.Msg == (int)WinApi.WindowsMessages.WM_NCHITTEST)
                    return ProcessNcHitTest(ref m, contentControl);
                else if (m.Msg == (int)WinApi.WindowsMessages.WM_GETMINMAXINFO)
                    return ProcessGetMinMaxInfo(ref m);
            }
            return false;
        }
        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        private bool ProcessGetMinMaxInfo(ref Message m)
        {
            Control hostedControl = GetHostedControl();
            if (hostedControl != null)
            {
                WinApi.MINMAXINFO minmax = (WinApi.MINMAXINFO)Marshal.PtrToStructure(m.LParam, typeof(WinApi.MINMAXINFO));
                // Maximum size.
                if (hostedControl.MaximumSize.Width != 0)
                    minmax.maxTrackSize.Width = hostedControl.MaximumSize.Width;
                if (hostedControl.MaximumSize.Height != 0)
                    minmax.maxTrackSize.Height = hostedControl.MaximumSize.Height;
                // Minimum size.
                minmax.minTrackSize = new Size(32, 32);
                if (hostedControl.MinimumSize.Width > minmax.minTrackSize.Width)
                    minmax.minTrackSize.Width = hostedControl.MinimumSize.Width;
                if (hostedControl.MinimumSize.Height > minmax.minTrackSize.Height)
                    minmax.minTrackSize.Height = hostedControl.MinimumSize.Height;
                Marshal.StructureToPtr(minmax, m.LParam, false);
            }
            return true;
        }
        private bool ProcessNcHitTest(ref Message m, bool contentControl)
        {
            Point location = PointToClient(new Point(WinApi.LOWORD(m.LParam), WinApi.HIWORD(m.LParam)));
            IntPtr transparent = new IntPtr((int)WinApi.WindowHitTestRegions.TransparentOrCovered);
            if (ResizeGripBounds.Contains(location))
            {
                if (IsResizeEnabled(ePopupResizeEdge.BottomLeft))
                {
                    m.Result = contentControl ? transparent : (IntPtr)WinApi.WindowHitTestRegions.BottomLeftSizeableCorner;
                    return true;
                }
                else if (IsResizeEnabled(ePopupResizeEdge.BottomRight))
                {
                    m.Result = contentControl ? transparent : (IntPtr)WinApi.WindowHitTestRegions.BottomRightSizeableCorner;
                    return true;
                }
                else if (IsResizeEnabled(ePopupResizeEdge.TopLeft))
                {
                    m.Result = contentControl ? transparent : (IntPtr)WinApi.WindowHitTestRegions.TopLeftSizeableCorner;
                    return true;
                }
                else if (IsResizeEnabled(ePopupResizeEdge.TopRight))
                {
                    m.Result = contentControl ? transparent : (IntPtr)WinApi.WindowHitTestRegions.TopRightSizeableCorner;
                    return true;
                }
            }
            else
            {
                Rectangle rectClient = ClientRectangle;
                if (location.X > rectClient.Right - 3 && location.X <= rectClient.Right && IsResizeEnabled(ePopupResizeEdge.Right))
                {
                    m.Result = contentControl ? transparent : (IntPtr)WinApi.WindowHitTestRegions.RightSizeableBorder;
                    return true;
                }
                else if (location.Y > rectClient.Bottom - 3 && location.Y <= rectClient.Bottom && IsResizeEnabled(ePopupResizeEdge.Bottom))
                {
                    m.Result = contentControl ? transparent : (IntPtr)WinApi.WindowHitTestRegions.BottomSizeableBorder;
                    return true;
                }
                else if (location.X > -1 && location.X < 3 && IsResizeEnabled(ePopupResizeEdge.Left))
                {
                    m.Result = contentControl ? transparent : (IntPtr)WinApi.WindowHitTestRegions.LeftSizeableBorder;
                    return true;
                }
                else if (location.Y > -1 && location.Y < 3 && IsResizeEnabled(ePopupResizeEdge.Top))
                {
                    m.Result = contentControl ? transparent : (IntPtr)WinApi.WindowHitTestRegions.TopSizeableBorder;
                    return true;
                }
            }
            return false;
        }
        /// 
        /// Type of resize mode, grips are automatically drawn at bottom-left and bottom-right corners.
        /// 
        public ePopupResizeEdge ResizeEdge
        {
            get { return _ResizeEdge; }
            set
            {
                if (value != _ResizeEdge)
                {
                    _ResizeEdge = value;
                    Invalidate();
                }
            }
        }
        private bool _CloseButtonVisible = true;
        /// 
        /// Gets or sets whether Close button is visible in fotter. Resize handle must also be visible in order for close button to render.
        /// 
        public bool CloseButtonVisible
        {
            get { return _CloseButtonVisible; }
            set
            {
                _CloseButtonVisible = value;
            }
        }
        /// 
        /// Gets resize grip bounds.
        /// 
        public Rectangle ResizeGripBounds
        {
            get { return _ResizeGripBounds; }
            private set { _ResizeGripBounds = value; }
        }
        private bool IsResizeGripShown
        {
            get
            {
                return (ResizeEdge == ePopupResizeEdge.BottomLeft || ResizeEdge == ePopupResizeEdge.BottomRight);
            }
        }
        #endregion
    }
    #region ePopupResizeEdge
    /// 
    /// Specifies the popup resize modes
    /// 
    public enum ePopupResizeEdge
    {
        None = 0,
        Left = 1,
        Top = 2,
        Right = 4,
        Bottom = 8,
        All = (Top | Left | Bottom | Right),
        TopLeft = (Top | Left),
        TopRight = (Top | Right),
        BottomLeft = (Bottom | Left),
        BottomRight = (Bottom | Right),
    }
    #endregion
    #region PopupHostController
    internal class PopupHostController : IDisposable
    {
        #region Constructor
        private ToolStripControlHost _ControlHost;
        private PopupControlHost _PopupControlHost;
        private System.Windows.Forms.Padding _Padding = System.Windows.Forms. Padding. Empty;
        private System.Windows.Forms.Padding _Margin = new System.Windows.Forms.Padding(1, 1, 1, 1);
        public PopupHostController()
        {
            InitializePopupControlHost();
        }
        #endregion
        #region Implementation
        /// 
        /// Occurs after popup is closed.
        /// 
        public event ToolStripDropDownClosedEventHandler Closed;
        /// 
        /// Raises Closed event.
        /// 
        /// Provides event arguments.
        protected virtual void OnClosed(ToolStripDropDownClosedEventArgs e)
        {
            ToolStripDropDownClosedEventHandler handler = Closed;
            if (handler != null)
                handler(this, e);
        }
        /// 
        /// Occurs before popup is closed and allows canceling.
        /// 
        public event ToolStripDropDownClosingEventHandler Closing;
        /// 
        /// Raises Closing event.
        /// 
        /// Provides event arguments.
        protected virtual void OnClosing(ToolStripDropDownClosingEventArgs e)
        {
            ToolStripDropDownClosingEventHandler handler = Closing;
            if (handler != null)
                handler(this, e);
        }
        private void InitializeHost(Control control)
        {
            InitializePopupControlHost();
            if (control != this.Control)
                DisposeToolstripControlHost();
            if (_ControlHost == null)
            {
                _ControlHost = new ToolStripControlHost(control);
                _ControlHost.AutoSize = false;
                _ControlHost.Padding = this.Padding;
                _ControlHost.Margin = this.Margin;
            }
            _ControlHost.Size = control.Size;
            _PopupControlHost.Items.Clear();
            _PopupControlHost.Padding = _PopupControlHost.Margin = System.Windows.Forms.Padding.Empty;
            _PopupControlHost.Items.Add(_ControlHost);
        }
        private void InitializePopupControlHost()
        {
            if (_PopupControlHost == null)
            {
                _PopupControlHost = new PopupControlHost();
                _PopupControlHost.Closed += new ToolStripDropDownClosedEventHandler(DropDownClosed);
                _PopupControlHost.Closing += new ToolStripDropDownClosingEventHandler(DropDownClosing);
            }
        }
        private void DropDownClosed(object sender, ToolStripDropDownClosedEventArgs e)
        {
            OnClosed(e);
        }
        void DropDownClosing(object sender, ToolStripDropDownClosingEventArgs e)
        {
            OnClosing(e);
        }
        /// 
        /// Show control on popup at specified location.
        /// 
        public void Show(Control control, int x, int y)
        {
            Show(control, x, y, ePopupResizeEdge.None);
        }
        /// 
        /// Shows control on popup at specified location with specified popup resize edges.
        /// 
        public void Show(Control control, int x, int y, ePopupResizeEdge resizeEdge)
        {
            Show(control, x, y, -1, -1, resizeEdge);
        }
        /// 
        /// Shows control on popup at specified location and size with specified popup resize edges.
        /// 
        public void Show(Control control, int x, int y, int width, int height, ePopupResizeEdge resizeEdge)
        {
            Size controlSize = control.Size;
            InitializeHost(control);
            _PopupControlHost.ResizeEdge = resizeEdge;
            _PopupControlHost.Show(x, y, width, height);
            control.Focus();
        }
        public Rectangle Bounds
        {
            get
            {
                return _PopupControlHost.Bounds;
            }
        }
        /// 
        /// Hides popup if visible.
        /// 
        public void Hide()
        {
            if (_PopupControlHost != null && _PopupControlHost.Visible)
            {
                _PopupControlHost.Hide();
            }
        }
        private void DisposeToolstripControlHost()
        {
            if (_ControlHost != null)
            {
                if (_PopupControlHost != null)
                    _PopupControlHost.Items.Clear();
                _ControlHost.Dispose();
                _ControlHost = null;
            }
        }
        public bool AutoClose
        {
            get
            {
                return _PopupControlHost.AutoClose;
            }
            set
            {
                _PopupControlHost.AutoClose = value;
            }
        }
        public Rectangle ParentControlBounds
        {
            get { return _PopupControlHost.ParentControlBounds; }
            set { _PopupControlHost.ParentControlBounds = value; }
        }
        /// 
        /// Gets whether popup is visible.
        /// 
        public bool Visible
        {
            get { return (_PopupControlHost != null && _PopupControlHost.Visible) ? true : false; }
        }
        /// 
        /// Gets the control displayed on popup.
        /// 
        public Control Control
        {
            get { return (_ControlHost != null) ? _ControlHost.Control : null; }
        }
        /// 
        /// Gets or sets the popup padding.
        /// 
        public System.Windows.Forms.Padding Padding
        {
            get { return _Padding; }
            set { _Padding = value; }
        }
        /// 
        /// Gets or sets popup margin.
        /// 
        public System.Windows.Forms.Padding Margin
        {
            get { return _Margin; }
            set { _Margin = value; }
        }
        public bool PopupUserSize
        {
            get
            {
                if (_PopupControlHost == null) return false;
                return _PopupControlHost.PopupUserSize;
            }
            set
            {
                if (_PopupControlHost != null)
                    _PopupControlHost.PopupUserSize = value;
            }
        }
        public bool CloseButtonVisible
        {
            get
            {
                if (_PopupControlHost == null) return false;
                return _PopupControlHost.CloseButtonVisible;
            }
            set
            {
                if (_PopupControlHost != null)
                    _PopupControlHost.CloseButtonVisible = value;
            }
        }
        #endregion
        #region IDisposable Members
        public void Dispose()
        {
            DisposeToolstripControlHost();
            if (_PopupControlHost != null)
            {
                _PopupControlHost.Closed -= new ToolStripDropDownClosedEventHandler(DropDownClosed);
                _PopupControlHost.Closing -= new ToolStripDropDownClosingEventHandler(DropDownClosing);
                _PopupControlHost.Dispose();
                _PopupControlHost = null;
            }
        }
        #endregion
    }
    #endregion
}