using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;
using nft.util;
using nft.ui.mainframe;
using nft.framework;
using System.Xml;
using System.Diagnostics;

namespace nft.ui.command {
    public class CommandManager {
        public const char PathSepalator = '\\';
        public const char GroupSepalator = '|';
        public const char IDSuffixSepalator = '#';
        public static readonly CommandManager TheInstance = new CommandManager();

        protected ImageListIndexResolver imgCahce;
        protected Dictionary<string, CommandUI> commands;

        protected CommandManager() {
            commands = new Dictionary<string, CommandUI>();
            imgCahce = new ImageListIndexResolver();
        }

        public static string MakePath(IHasNameAndID owner, string suffix) {
            if (suffix != null && suffix.Length > 0)
                return owner.ID + IDSuffixSepalator + suffix;
            else
                return owner.ID;
        }

        public void RegisterCommand(IHasNameAndID owner, string suffix, CommandUI cui, CommandPathHint menubar, CommandPathHint toolbar) {
            if(toolbar!=null)
                Main.mainFrame.AddToolButton(cui, toolbar);
            if (menubar != null)
                Main.mainFrame.AddMenuItem(cui, menubar);
            RegisterCommand(suffix, owner, cui);
        }
        public void RegisterCommand(IHasNameAndID owner, string suffix, CommandUI cui, CommandPathHint menubar) {
            RegisterCommand(owner, suffix, cui, menubar, null);
        }

        public void RegisterCommand(IHasNameAndID owner, CommandUI cui, CommandPathHint menubar, CommandPathHint toolbar) {
            RegisterCommand(owner, null, cui, menubar, toolbar);
        }
        public void RegisterCommand(IHasNameAndID owner, CommandUI cui, CommandPathHint menubar) {
            RegisterCommand(owner, null, cui, menubar, null);
        }

        public void RegisterCommand(string name, IHasNameAndID owner, CommandUI cui) {
            string key = MakePath(owner, name);
            try {
                commands.Add(key, cui);
            } catch (Exception e) {
                Debug.WriteLine(cui);
            }
        }
    }

    public class CommandPathHint {
        protected string id;
        protected string parent;
        protected string before;
        protected string after;

        public CommandPathHint(XmlElement e) {
            this.ID = XmlUtil.GetAttribute(e, "id");
            this.Parent = XmlUtil.GetAttribute(e, "parent");
            this.Before = XmlUtil.GetAttribute(e, "before", null);
            this.After = XmlUtil.GetAttribute(e, "after", null);
        }

        public CommandPathHint(string id) {
            this.ID = id;
        }

        [Obsolete]
        public CommandPathHint(string id, string after, string before) {
            this.ID = id;
            this.After = after;
            this.Before = before;
        }

        #region getter and setter
        public string ID {
            get { return id; }
            set {
                if (value != null && value.Length == 0) {
                    id = null;
                } else {
                    id = value;
                }
            }
        }

        /// <summary>
        /// use "" to point out root node.
        /// null value will be replaced by "".
        /// </summary>
        public string Parent{
            get { return parent; }
            set {
                if (value == null) {
                    parent = "";
                } else {
                    parent = value;
                }
            }
        }

        public string Before{
            get { return before; }
            set {
                if (value != null && value.Length == 0) {
                    before = null;
                } else {
                    before = value;
                }
            }
        }

        public string After{
            get { return after; }
            set {
                if (value != null && value.Length == 0) {
                    after = null;
                } else {
                    after = value;
                }
            }
        }
        #endregion
    }

    public class CommandNode {
        private string name;
        private CommandNode parent;

        protected CommandNode() {
        }

        public CommandNode(string name, CommandNode parent) {
            InitNode(name, parent);
        }

        internal void InitNode(string name, CommandNode parent){
            Debug.Assert(parent.EnableChanged == null, "The CommandNode is already initialized.");
            this.name = name;
            this.parent = parent;
            parent.EnableChanged += new EventHandler(OnParentEnableChanged);
        }

        protected virtual void OnParentEnableChanged(object sender, EventArgs e) {
            FireEnableChangedEvent(sender, e);
        }

        public string Name { get { return name; } }
        public CommandNode Parent { get { return parent; } }

        public string FullPath {
            get {
                if (parent != null) {
                    return parent.FullPath + this.Name;
                } else {
                    return this.Name;
                }
            }
        }

        public event EventHandler EnableChanged;

        protected bool enable;
        public bool NodeEnable {
            get {
                return enable;
            }
            set {
                bool b = Enable;
                enable = value;
                if (b != value) {
                    FireEnableChangedEvent(this, null);
                }
            }
        }

        public virtual bool Enable {
            get {
                if (parent != null) {
                    return NodeEnable & parent.NodeEnable;
                } else {
                    return NodeEnable;
                }
            }
        }

        protected void FireEnableChangedEvent(object sender, EventArgs arg) {
            if (EnableChanged != null) {
                EnableChanged(sender, arg);
            }
        }
    }
}
