using System;
using System.Windows.Forms;
using System.Xml;
using nft.framework;
using nft.framework.plugin;
using nft.ui.mainframe;
using nft.ui.command;
using nft.util;
using WeifenLuo.WinFormsUI.Docking;
using System.Collections.Generic;
using nft.ui.docking;

namespace nft.contributions.ui
{
	/// <summary>
	/// Contributes a sub-form (window) to the system, 
    /// such as infomation windows or control panels.
	/// 
	/// sub-form can float or docking. (can auto-shrink or no-shrink while docking).
    /// you can forbid some of style to each form by specifing several options.
	/// </summary>
	public class CtbSubform : Contribution
	{
        public static class PredefinedOptions {
            public static readonly string Multiple = "multiple";
            public static readonly string Suicidal = "suicidal";
            public static readonly string NoShrink = "noshrink";
            public static readonly string Permanent = "permanent";
            public static readonly string NoSave = "nosave";
        }

        public static readonly string SepalatorPersist = "::";

        static CtbSubform() {
            ((MainFrame)Main.mainFrame).DockingManager.RegisterResolver(ResolveDockContent);
        }

        public static DockContent ResolveDockContent(string persist) {
            int n = persist.IndexOf(SepalatorPersist);
            string id = persist.Substring(0, n);
            string nam = persist.Substring(n + SepalatorPersist.Length);
            CtbSubform ctb = PluginManager.theInstance.GetContribution(id) as CtbSubform;
            if (ctb != null) {
                return ctb.GetContent(nam, true).Parent as DockContent;
            } else {
                return null;
            }
        }

        /// <summary>
		/// 
		/// </summary>
        protected readonly IDictionary<string, SubformHolder> contentMap;

		/// <summary>
		/// Type of the control associated with this the content.
		/// </summary>
        protected readonly Type windowType;

        public CtbSubform(Plugin p, XmlElement e)
            : base(p, e) {
            options = LoadOptions(e);
			windowType = PluginUtil.loadTypeFromManifest((XmlElement)XmlUtil.SelectSingleNode(e,"class"));
            if (IsSingleton) {
                contentMap = new Dictionary<string, SubformHolder>(1);
            } else {
                contentMap = new Dictionary<string, SubformHolder>();
            }
		}

        protected virtual IList<string> LoadOptions(XmlElement e) {
            String optstr = XmlUtil.GetSingleNodeText(e, "options", "").ToLower();
            String[] sarr = optstr.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            
            return new List<string>(sarr);
        }

        protected internal override InitCompleteEventHandler Initialize() {
            if (HasOption(PredefinedOptions.Permanent)) {
                GetContent("");
            }
            return null;
        }

        /// <summary>
        /// get content control.
        /// if 'multiple' option valid, return the control which name matched to the argument.
        /// otherwise (=singleton) returns existing control.
        /// 
        /// </summary>
        /// <param name="name">key for muliple forms (ignored for singleton)</param>
        /// <param name="create">if there is no corresponding control, create new one and return it.</param>
        /// <returns></returns>
        public Control GetContent(string name, bool create) {
            SubformHolder h = GetHolder(name, create);
            if (h != null) {
                return h.Content;
            } else {
                return null;
            }
        }

        /// <summary>
        /// get content control.
        /// if 'multiple' option valid, return the control which name matched to the argument.
        /// otherwise (=singleton) returns existing control.
        /// if there is no corresponding control, create new one and return it.
        /// </summary>
        /// <param name="name">key for muliple forms (ignored for singleton)</param>
        /// <returns></returns>
        public Control GetContent(string name) {
            return GetContent(name, true);
        }

        internal protected SubformHolder GetHolder(string name, bool create) {
            string key = IsSingleton ? "" : name;
            SubformHolder holder;
            if (!contentMap.TryGetValue(key, out holder) && create) {
                Control c = CreateContent(name);
                holder = CtbFormHolder.Create(this, key);
                contentMap.Add(key, holder);
                holder.Content = c;
            }
            return holder;
        }

        protected virtual Control CreateContent(string name) {
            Control c = (Control)Activator.CreateInstance(windowType);
            c.Name = name;
            return c;
		}		

        protected IList<string> options;
        /// <summary>
        /// enumerate all option strings
        /// </summary>
        /// <returns></returns>
        public IEnumerator<String> GetOptions() {
            return options.GetEnumerator();
        }
        /// <summary>
        /// returns true if this contribution contains the same option with the argument.
        /// </summary>
        /// <param name="optstr"></param>
        /// <returns></returns>
        public bool HasOption(string optstr) {
            return options.Contains(optstr);
        }

        /// <summary>
        /// true means that this contribution hold at most one form.
        /// (if sucidal option specified too, there can be no form.)
        /// otherwise can create mulitple forms.
        /// </summary>         
        public bool IsSingleton {
            get { return !HasOption(PredefinedOptions.Multiple); }
        }

		public void ShowExpanded(string name, bool activate)
		{
            Control c = GetContent(name);
            DockContent dc = c.Parent as DockContent;
            DockState state = dc.DockState;
            if (state == DockState.Hidden || state == DockState.Unknown) {
            } else {
                if (state != DockState.DockLeftAutoHide) {
                    dc.DockState = DockState.DockLeft;
                } else if (state != DockState.DockRightAutoHide) {
                    dc.DockState = DockState.DockRight;
                } else if (state != DockState.DockTopAutoHide) {
                    dc.DockState = DockState.DockTop;
                } else if (state != DockState.DockBottomAutoHide) {
                    dc.DockState = DockState.DockBottom;
                }
            }
            if (activate && !dc.IsActivated) {
                dc.Activate();
            }
		}

        /// <summary>
        /// Show sub-form window.
        /// </summary>
        /// <param name="name">key for muliple forms (ignored for singleton)</param>
        public void Show(string name) {
            SubformHolder h = GetHolder(name, true);
            h.Show();
        }

        /// <summary>
        /// Hide sub-form window. 'Suicidal' form will be disposed.
        /// </summary>
        /// <param name="name">key for muliple forms (ignored for singleton)</param>
        public void Hide(string name) {
            SubformHolder h = GetHolder(name, false);
            if (h != null) {
                h.Hide();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public bool IsVisible(string name) {
            SubformHolder h = GetHolder(name, false);
            if (h != null) {
                return h.Visible;
            } else {
                return false;
            }
        }

        public IEnumerator<Control> EnumerateControls() {
            IEnumerator<SubformHolder> e = contentMap.Values.GetEnumerator();
            while (e.MoveNext()) {
                yield return e.Current.Content;
            }
            yield break;
        }

        protected virtual StyleOption MakeOption() {
            IEnumerator<String> en = GetOptions();
            StyleOption ret = StyleOption.Default;
            while (en.MoveNext()) {
                string opt = en.Current;
                if (PredefinedOptions.Suicidal.Equals(opt)) {
                    ret |= StyleOption.Tempolaly;
                } else if (PredefinedOptions.NoSave.Equals(opt)) {
                    ret |= StyleOption.NoSaveLayout;
                } else if (PredefinedOptions.NoShrink.Equals(opt)) {
                    ret |= StyleOption.NoShrink;
                } else if (PredefinedOptions.Permanent.Equals(opt)) {
                    ret |= StyleOption.NoClose;
                }
            }
            return ret;
        }

        public class CtbFormHolder : SubformHolder {
            public static CtbFormHolder Create(CtbSubform ctb, string key) {
                LayoutState state = LayoutState.Right;
                LayoutStyle style = LayoutStyle.AllSide | LayoutStyle.Float;
                StyleOption sopts = ctb.MakeOption();
                CtbFormHolder holder = new CtbFormHolder(ctb, key, state, style, sopts);
                return holder;
            }

            protected readonly CtbSubform ctbOwner;
            protected readonly string key;
            protected CtbFormHolder(CtbSubform ctb, string key, LayoutState initial, LayoutStyle allowed, StyleOption opt)
                : base(initial, allowed, opt) {
                this.ctbOwner = ctb;
                this.key = ctb.ID + SepalatorPersist + key;
            }

            protected internal override string GetParsisitString() {
                return key;
            }
           
        }
	}
}
