using System;
using System.Collections.Generic;
using System.Text;
using WeifenLuo.WinFormsUI.Docking;
using nft.framework;
using nft.ui.mainframe_old;
using System.Windows.Forms;
using nft.ui.mainframe;
using nft.ui.ui.docking;

namespace nft.ui.docking {

    public enum LayoutState : int {
        Unknown = 0, Float = 1, Left = 2, Right = 4, Top = 8, Bottom = 16,
        LeftShrink = 32 + 2, RightShrink = 32 + 6, TopShrink = 32 + 8, BottomShirink = 16 + 32
    }
    [Flags]
    public enum LayoutStyle : int {
        Unknown = 0, Float = 1, Left = 2, Right = 4, Top = 8, Bottom = 16, AllSide = 31
    }
    [Flags]
    public enum StyleOption : int { Default = 0, NoShrink = 1, NoClose = 2, Tempolaly = 4, NoSaveLayout = 8 }

    /// <summary>
    /// ドッキングフォームをラップする抽象クラス
    /// </summary>
    public abstract class SubformHolder {
        protected static List<SubformHolder> all_holders = new List<SubformHolder>();

        public static IList<SubformHolder> LiveHolders {
            get {
                return all_holders;
            }
        }

        /// <summary> Fired when the content is closed by the user. </summary>
        public event EventHandler OnHidden;
        /// <summary> Fired when the content is shown by the user.</summary>
        public event EventHandler OnShown;

        public event EventHandler OnDisposed;

        public SubformHolder(LayoutState initial)
            : this(initial, (LayoutStyle)initial | LayoutStyle.AllSide, StyleOption.Default) {
        }

        public SubformHolder(LayoutState initial, LayoutStyle allowed)
            : this(initial, allowed, StyleOption.Default) {
        }

        public SubformHolder(LayoutState initial, LayoutStyle allowed, StyleOption opt) {
            this.state = initial;
            this.styleAllowed = allowed;
            this.option = opt;
        }

        protected DefaultDockForm cmpDocking;
        protected Control content;
        protected readonly LayoutState state;
        protected readonly LayoutStyle styleAllowed;
        protected readonly StyleOption option;

        public LayoutStyle AllowedStyle {
            get { return styleAllowed; }
        }

        public LayoutState LayoutState {
            get {
                if (cmpDocking != null) {
                    return FromState(cmpDocking.DockState);
                } else {
                    return state;
                }
            }
        }

        public StyleOption OtpionFlags {
            get { return option; }
        }

        public Boolean HasOption(StyleOption o) {
            return (option & o) != 0;
        }

        public bool Visible {
            get { return (cmpDocking != null && !cmpDocking.IsHidden); }
            set {
                if (value) {
                    Show();
                } else {
                    Hide();
                }
            }
        }

        public Control Content {
            get { return content; }
            set {
                content = value;
                if (cmpDocking == null) {
                    cmpDocking = createDockComponent();
                    setupDockComponent();
                }
                SetContent();
            }
        }

        protected void SetContent() {
            cmpDocking.Controls.Clear();
            cmpDocking.Controls.Add(content);
            content.Dock = DockStyle.Fill;
            cmpDocking.PerformLayout();
        }

        protected virtual DefaultDockForm createDockComponent() {
            return new DefaultDockForm(this);
        }

        protected virtual void setupDockComponent() {
            cmpDocking.Tag = this;
            cmpDocking.ShowHint = ToState(state);
            cmpDocking.DockAreas = ToAreas(AllowedStyle);
            cmpDocking.CloseButtonVisible = !HasOption(StyleOption.NoClose);
            cmpDocking.HideOnClose = !HasOption(StyleOption.Tempolaly);
            cmpDocking.Disposed += new EventHandler(cmpDocking_Disposed);
            cmpDocking.DockStateChanged += new EventHandler(cmpDocking_DockStateChanged);
        }

        void cmpDocking_Disposed(object sender, EventArgs e) {
            all_holders.Remove(this);
            if (OnDisposed != null) OnDisposed(this, e);
            content = null;
            cmpDocking = null;
        }

        void cmpDocking_DockStateChanged(object sender, EventArgs e) {
            if (cmpDocking.DockState == DockState.Hidden) {
                if (OnHidden != null) OnHidden(this, e);
            } else if (cmpDocking.DockState != DockState.Unknown) {
                if (OnShown != null) OnShown(this, e);
            }
        }

        public void Show() {
            if (cmpDocking == null) {
                cmpDocking = createDockComponent();
                setupDockComponent();
                SetContent();
            }
            if (!all_holders.Contains(this)) {
                all_holders.Add(this);
            }
            cmpDocking.Show(getDockPanel());
            /* 何で必要だったか忘れた…
            if (cmpDocking.DockState == DockState.Hidden || cmpDocking.DockState == DockState.Unknown) {
                cmpDocking.Show();
            }
             */
        }

        public void Hide() {
            if (cmpDocking.DockState != DockState.Hidden && cmpDocking.DockState != DockState.Unknown) {
                cmpDocking.Hide();
            }
        }

        public void ToggleVisible() {
            Visible = !Visible;
        }

        private DockPanel getDockPanel() {
            return ((MainFrame)Main.mainFrame).dockManager.DockPanel;
        }

        #region LayoutStyle convert utiliti methods
        protected static DockAreas ToAreas(LayoutStyle s) {
            DockAreas ret = DockAreas.Document;
            if ((s & LayoutStyle.Float) != 0) ret |= DockAreas.Float;
            if ((s & LayoutStyle.Left) != 0) ret |= DockAreas.DockLeft;
            if ((s & LayoutStyle.Right) != 0) ret |= DockAreas.DockRight;
            if ((s & LayoutStyle.Top) != 0) ret |= DockAreas.DockTop;
            if ((s & LayoutStyle.Bottom) != 0) ret |= DockAreas.DockBottom;
            return ret ^ DockAreas.Document;
        }

        protected static DockState ToState(LayoutState s) {
            if (s == LayoutState.Float) {
                return DockState.Float;
            } else {
                bool shrink = ((int)s & 0x20) != 0;
                s = (LayoutState)((int)s & 0x1f);
                switch (s) {
                    case LayoutState.Left:
                        return shrink ? DockState.DockLeftAutoHide : DockState.DockLeft;
                    case LayoutState.Right:
                        return shrink ? DockState.DockRightAutoHide : DockState.DockRight;
                    case LayoutState.Top:
                        return shrink ? DockState.DockTopAutoHide : DockState.DockTop;
                    case LayoutState.Bottom:
                        return shrink ? DockState.DockBottomAutoHide : DockState.DockBottom;
                }
                return DockState.Unknown;
            }
        }

        protected static LayoutState FromState(DockState s) {
            if (s == DockState.Float) {
                return LayoutState.Float;
            } else if (s == DockState.DockLeft) {
                return LayoutState.Left;
            } else if (s == DockState.DockRight) {
                return LayoutState.Right;
            } else if (s == DockState.DockTop) {
                return LayoutState.Top;
            } else if (s == DockState.DockBottom) {
                return LayoutState.Bottom;
            } else if (s == DockState.DockLeftAutoHide) {
                return LayoutState.LeftShrink;
            } else if (s == DockState.DockRightAutoHide) {
                return LayoutState.RightShrink;
            } else if (s == DockState.DockTopAutoHide) {
                return LayoutState.TopShrink;
            } else if (s == DockState.DockBottomAutoHide) {
                return LayoutState.BottomShirink;
            } else {
                return LayoutState.Unknown;
            }

        }
        #endregion

        internal protected abstract VDockContentId ContentID { get; }
    }
}
