using System;
using System.Windows.Forms;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Collections;
using System.Collections.Generic;
using System.Security.Permissions;
using System.Diagnostics.CodeAnalysis;
#pragma warning disable CS1591 // 缺少对公共可见类型或成员的 XML 注释
namespace WeifenLuo.WinFormsUI.Docking
{
    /// <summary>
    /// 
    /// </summary>
    public abstract class DockPaneStripBase : Control
    {
        /// <summary>
        /// 
        /// </summary>
        [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]        
        protected internal class Tab : IDisposable
        {
            private IDockContent m_content;
            /// <summary>
            /// 
            /// </summary>
            /// <param name="content"></param>
            public Tab(IDockContent content)
            {
                m_content = content;
            }
            /// <summary>
            /// 
            /// </summary>
            ~Tab()
            {
                Dispose(false);
            }
            /// <summary>
            /// 
            /// </summary>
            public IDockContent Content
            {
                get { return m_content; }
            }
            /// <summary>
            /// 
            /// </summary>
            public Form ContentForm
            {
                get { return m_content as Form; }
            }
            /// <summary>
            /// 
            /// </summary>
            public void Dispose()
            {
                Dispose(true);
                GC.SuppressFinalize(this);
            }
            /// <summary>
            /// 
            /// </summary>
            /// <param name="disposing"></param>
            protected virtual void Dispose(bool disposing)
            {
            }

            private Rectangle? _rect;
            private static Rectangle empty = new Rectangle();
            /// <summary>
            /// 
            /// </summary>
            public Rectangle? Rectangle
            {
                get
                {
                    if (_rect != null)
                    {
                        return _rect;
                    }

                    return _rect = empty;
                }

                set
                {
                    _rect = value;
                }
            }
        }
        /// <summary>
        /// 
        /// </summary>
        [SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]        
        protected sealed class TabCollection : IEnumerable<Tab>
        {
            #region IEnumerable Members
            IEnumerator<Tab> IEnumerable<Tab>.GetEnumerator()
            {
                for (int i = 0; i < Count; i++)
                    yield return this[i];
            }

            IEnumerator IEnumerable.GetEnumerator()
            {
                for (int i = 0; i < Count; i++)
                    yield return this[i];
            }
            #endregion

            internal TabCollection(DockPane pane)
            {
                m_dockPane = pane;
            }

            private DockPane m_dockPane;
            /// <summary>
            /// 
            /// </summary>
            public DockPane DockPane
            {
                get { return m_dockPane; }
            }
            /// <summary>
            /// 
            /// </summary>
            public int Count
            {
                get { return DockPane.DisplayingContents.Count; }
            }
            /// <summary>
            /// 
            /// </summary>
            /// <param name="index"></param>
            /// <returns></returns>
            public Tab this[int index]
            {
                get
                {
                    IDockContent content = DockPane.DisplayingContents[index];
                    if (content == null)
                        throw (new ArgumentOutOfRangeException("index"));
                    return content.DockHandler.GetTab(DockPane.TabStripControl);
                }
            }
            /// <summary>
            /// 
            /// </summary>
            /// <param name="tab"></param>
            /// <returns></returns>
            public bool Contains(Tab tab)
            {
                return (IndexOf(tab) != -1);
            }
            /// <summary>
            /// 
            /// </summary>
            /// <param name="content"></param>
            /// <returns></returns>
            public bool Contains(IDockContent content)
            {
                return (IndexOf(content) != -1);
            }
            /// <summary>
            /// 
            /// </summary>
            /// <param name="tab"></param>
            /// <returns></returns>
            public int IndexOf(Tab tab)
            {
                if (tab == null)
                    return -1;

                return DockPane.DisplayingContents.IndexOf(tab.Content);
            }
            /// <summary>
            /// 
            /// </summary>
            /// <param name="content"></param>
            /// <returns></returns>
            public int IndexOf(IDockContent content)
            {
                return DockPane.DisplayingContents.IndexOf(content);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="pane"></param>
        protected DockPaneStripBase(DockPane pane)
        {
            m_dockPane = pane;

            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            SetStyle(ControlStyles.Selectable, false);
            AllowDrop = true;
        }

        private DockPane m_dockPane;
        /// <summary>
        /// 
        /// </summary>
        protected DockPane DockPane
        {
            get { return m_dockPane; }
        }
        /// <summary>
        /// 
        /// </summary>
        protected DockPane.AppearanceStyle Appearance
        {
            get { return DockPane.Appearance; }
        }

        private TabCollection m_tabs;
        /// <summary>
        /// 
        /// </summary>
        protected TabCollection Tabs
        {
            get
            {
                return m_tabs ?? (m_tabs = new TabCollection(DockPane));
            }
        }

        internal void RefreshChanges()
        {
            if (IsDisposed)
                return;

            OnRefreshChanges();
        }

        protected virtual void OnRefreshChanges()
        {
        }

        protected internal abstract int MeasureHeight();

        protected internal abstract void EnsureTabVisible(IDockContent content);

        protected int HitTest()
        {
            return HitTest(PointToClient(Control.MousePosition));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        protected internal abstract int HitTest(Point point);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        /// <returns></returns>
        protected virtual bool MouseDownActivateTest(MouseEventArgs e)
        {
            return true;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public abstract GraphicsPath GetOutline(int index);
        /// <summary>
        /// 
        /// </summary>
        /// <param name="content"></param>
        /// <returns></returns>
        protected internal virtual Tab CreateTab(IDockContent content)
        {
            return new Tab(content);
        }

        private Rectangle _dragBox = Rectangle.Empty;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseDown(MouseEventArgs e)
        {
            base.OnMouseDown(e);
            int index = HitTest();
            if (index != -1)
            {
                if (e.Button == MouseButtons.Middle)
                {
                    // Close the specified content.
                    TryCloseTab(index);
                }
                else
                {
                    IDockContent content = Tabs[index].Content;
                    if (DockPane.ActiveContent != content)
                    {
                        // Test if the content should be active
                        if (MouseDownActivateTest(e))
                            DockPane.ActiveContent = content;
                    }

                }
            }

            if (e.Button == MouseButtons.Left)
            {
                var dragSize = SystemInformation.DragSize;
                _dragBox = new Rectangle(new Point(e.X - (dragSize.Width / 2),
                                                e.Y - (dragSize.Height / 2)), dragSize);
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);

            if (e.Button != MouseButtons.Left || _dragBox.Contains(e.Location)) 
                return;

            if (DockPane.ActiveContent == null)
                return;

            if (DockPane.DockPanel.AllowEndUserDocking && DockPane.AllowDockDragAndDrop && DockPane.ActiveContent.DockHandler.AllowEndUserDocking)
                DockPane.DockPanel.BeginDrag(DockPane.ActiveContent.DockHandler);
        }
        /// <summary>
        /// 
        /// </summary>
        protected bool HasTabPageContextMenu
        {
            get { return DockPane.HasTabPageContextMenu; }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="position"></param>
        protected void ShowTabPageContextMenu(Point position)
        {
            DockPane.ShowTabPageContextMenu(this, position);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        protected bool TryCloseTab(int index)
        {
            if (index >= 0 || index < Tabs.Count)
            {
                // Close the specified content.
                IDockContent content = Tabs[index].Content;
                DockPane.CloseContent(content);
                return true;
            }
            return false;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="e"></param>
        protected override void OnMouseUp(MouseEventArgs e)
        {
            base.OnMouseUp(e);

            if (e.Button == MouseButtons.Right)
                ShowTabPageContextMenu(new Point(e.X, e.Y));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="m"></param>
        [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
        protected override void WndProc(ref Message m)
        {
            if (m.Msg == (int)Win32.Msgs.WM_LBUTTONDBLCLK)
            {
                base.WndProc(ref m);

                int index = HitTest();
                if (DockPane.DockPanel.AllowEndUserDocking && index != -1)
                {
                    IDockContent content = Tabs[index].Content;
                    if (content.DockHandler.CheckDockState(!content.DockHandler.IsFloat) != DockState.Unknown)
                        content.DockHandler.IsFloat = !content.DockHandler.IsFloat;	
                }

                return;
            }

            base.WndProc(ref m);
            return;
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="drgevent"></param>
        protected override void OnDragOver(DragEventArgs drgevent)
        {
            base.OnDragOver(drgevent);

            int index = HitTest();
            if (index != -1)
            {
                IDockContent content = Tabs[index].Content;
                if (DockPane.ActiveContent != content)
                    DockPane.ActiveContent = content;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        protected void ContentClosed()
        {
            if (m_tabs.Count == 0)
            {
                DockPane.ClearLastActiveContent();
            }
        }
/// <summary>
/// 
/// </summary>
/// <param name="tab"></param>
/// <returns></returns>
        protected abstract Rectangle GetTabBounds(Tab tab);

        internal static Rectangle ToScreen(Rectangle rectangle, Control parent)
        {
            if (parent == null)
                return rectangle;

            return new Rectangle(parent.PointToScreen(new Point(rectangle.Left, rectangle.Top)), new Size(rectangle.Width, rectangle.Height));
        }
        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        protected override AccessibleObject CreateAccessibilityInstance()
        {
            return new DockPaneStripAccessibleObject(this);
        }
        /// <summary>
        /// 
        /// </summary>
        public class DockPaneStripAccessibleObject : Control.ControlAccessibleObject
        {
            private DockPaneStripBase _strip;
            /// <summary>
            /// 
            /// </summary>
            /// <param name="strip"></param>
            public DockPaneStripAccessibleObject(DockPaneStripBase strip)
                : base(strip)
            {
                _strip = strip;
            }
            /// <summary>
            /// 
            /// </summary>
            public override AccessibleRole Role
            {
                get
                {
                    return AccessibleRole.PageTabList;
                }
            }
            /// <summary>
            /// 
            /// </summary>
            /// <returns></returns>
            public override int GetChildCount()
            {
                return _strip.Tabs.Count;
            }
            /// <summary>
            /// 
            /// </summary>
            /// <param name="index"></param>
            /// <returns></returns>
            public override AccessibleObject GetChild(int index)
            {
                return new DockPaneStripTabAccessibleObject(_strip, _strip.Tabs[index], this);
            }
            /// <summary>
            /// 
            /// </summary>
            /// <param name="x"></param>
            /// <param name="y"></param>
            /// <returns></returns>
            public override AccessibleObject HitTest(int x, int y)
            {
                Point point = new Point(x, y);
                foreach (Tab tab in _strip.Tabs)
                {
                    Rectangle rectangle = _strip.GetTabBounds(tab);
                    if (ToScreen(rectangle, _strip).Contains(point))
                        return new DockPaneStripTabAccessibleObject(_strip, tab, this);
                }

                return null;
            }
        }
        /// <summary>
        /// 
        /// </summary>
        protected class DockPaneStripTabAccessibleObject : AccessibleObject
        {
            private DockPaneStripBase _strip;
            private Tab _tab;

            private AccessibleObject _parent;

            internal DockPaneStripTabAccessibleObject(DockPaneStripBase strip, Tab tab, AccessibleObject parent)
            {
                _strip = strip;
                _tab = tab;

                _parent = parent;
            }

            public override AccessibleObject Parent
            {
                get
                {
                    return _parent;
                }
            }

            public override AccessibleRole Role
            {
                get
                {
                    return AccessibleRole.PageTab;
                }
            }

            public override Rectangle Bounds
            {
                get
                {
                    Rectangle rectangle = _strip.GetTabBounds(_tab);
                    return ToScreen(rectangle, _strip);
                }
            }

            public override string Name
            {
                get
                {
                    return _tab.Content.DockHandler.TabText;
                }
                set
                {
                    //base.Name = value;
                }
            }
        }
 
    }
}
