using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

using CategoryTheory;

namespace DiagramUI
{
    /// <summary>
    /// Pure object label
    /// </summary>
    public class PureObjectLabel : IObjectLabel
    {
        #region Fields

        /// <summary>
        /// Associated object
        /// </summary>
        protected ICategoryObject obj;

        /// <summary>
        /// Name
        /// </summary>
        protected string name;

        /// <summary>
        /// Kind
        /// </summary>
        protected string kind;

        /// <summary>
        /// Type
        /// </summary>
        protected string type;

        /// <summary>
        /// The x coordinate
        /// </summary>
        protected int x;

        /// <summary>
        /// The y coorditate
        /// </summary>
        protected int y;

        /// <summary>
        /// The desktop
        /// </summary>
        protected IDesktop desktop;

        /// <summary>
        /// The parent
        /// </summary>
        protected INamedComponent parent;

        /// <summary>
        /// The wrappers sign
        /// </summary>
        private static bool wrappers;

        #endregion

        protected PureObjectLabel()
        {
        }
        public PureObjectLabel(string name, string kind, string type, int x, int y)
        {
            this.name = name;
            this.kind = kind;
            this.type = type;
            this.x = x;
            this.y = y;
        }

        #region IObjectLabel Members

        public ICategoryObject Object
        {
            get
            {
                if (!wrappers)
                {
                    if (obj is CategoryObjectWrapper)
                    {
                        CategoryObjectWrapper wrapper = obj as CategoryObjectWrapper;
                        ICategoryObject ob = wrapper.TheObject;
                        if (ob != null)
                        {
                            return ob;
                        }
                    }
                }
                return obj;
            }
            set
            {
                obj = value;
            }
        }

        #endregion

        #region INamedComponent Members

        public string Name
        {
            get
            {
                return name;
            }
        }

        public string Kind
        {
            get
            {
                return kind;
            }
        }

        public string Type
        {
            get
            {
                return type;
            }
        }

        public void Remove()
        {
        }

        public int X
        {
            get
            {
                return x;
            }
            set
            {
                x = value;
            }
        }

        public int Y
        {
            get
            {
                return y;
            }
            set
            {
                y = value;
            }
        }

        public IDesktop Desktop
        {
            get
            {
                return desktop;
            }
            set
            {
                desktop = value;
            }
        }

        public int Ord
        {
            get
            {
                return desktop.Components.IndexOf(this);
            }
        }

        /// <summary>
        /// Parent component
        /// </summary>
        public INamedComponent Parent
        {
            get
            {
                return parent;
            }
            set
            {
                parent = value;
            }
        }


        public INamedComponent GetRoot(IDesktop desktop)
        {
            return GetRoot(this, desktop);
        }

        /// <summary>
        /// Gets component name relatively desktop
        /// </summary>
        /// <param name="desktop">The desktop</param>
        /// <returns>Relalive name</returns>
        public virtual string GetName(IDesktop desktop)
        {
            return GetName(this, desktop);
        }



        /// <summary>
        /// Gets name relatively root
        /// </summary>
        public string RootName
        {
            get
            {
                return GetName(Desktop.Root);
            }
        }

        /// <summary>
        /// Root control
        /// </summary>
        public INamedComponent Root
        {
            get
            {
                return GetRoot(this);
            }
        }




        #endregion

        #region Specific members

        public static INamedComponent GetRoot(INamedComponent comp, IDesktop desktop)
        {
            if (comp.Desktop == desktop)
            {
                return comp;
            }
            return GetRoot(comp.Parent, desktop);
        }

        public void SetType()
        {
            kind = Object.GetType().ToString();
        }

        public static void SetType(ICollection c)
        {
            foreach (PureObjectLabel l in c)
            {
                l.SetType();
            }
        }


        static public void SetLabels(ICollection c)
        {
            foreach (IObjectLabel l in c)
            {
                ICategoryObject o = l.Object;
                o.Object = l;
            }
        }

        /// <summary>
        /// Suffix of alias
        /// </summary>
        /// <param name="str">alias</param>
        /// <returns>The suffix</returns>
        static public string Suffix(string str)
        {
            int n = str.LastIndexOf(".");
            return str.Substring(n + 1);
        }

        /// <summary>
        /// Checks whether str has prefix of component name 
        /// </summary>
        /// <param name="obj">Object</param>
        /// <param name="str">String to check</param>
        /// <returns>The component and null otherwise</returns>
        static public INamedComponent PrefixComponent(object obj, string str)
        {
            if (!(obj is IAssociatedObject))
            {
                return null;
            }
            IAssociatedObject ass = obj as IAssociatedObject;
            if (!(ass.Object is INamedComponent))
            {
                return null;
            }
            INamedComponent c = ass.Object as INamedComponent;
            int n = str.LastIndexOf(".");
            string s = str.Substring(0, n);
            if (s.Equals(c.Name))
            {
                return c;
            }
            else
            {
                return null;
            }
        }


        /// <summary>
        /// Gets root of the component
        /// </summary>
        /// <param name="component">The component</param>
        /// <returns>The root</returns>
        static public INamedComponent GetRoot(INamedComponent component)
        {
            IDesktop d = component.Desktop;
            IDesktop desk = d.Root;
            return GetRoot(component, desk);
        }


        /// <summary>
        /// Checks whether str has prefix of component name
        /// </summary>
        /// <param name="ao">Relative object</param>
        /// <param name="obj">Object</param>
        /// <param name="str">String to check</param>
        /// <returns>The component and null otherwise</returns>
        static public INamedComponent PrefixComponent(IAssociatedObject ao, object obj, string str)
        {
            if (!(obj is IAssociatedObject))
            {
                return null;
            }
            IAssociatedObject ass = obj as IAssociatedObject;
            if (!(ass.Object is INamedComponent))
            {
                return null;
            }
            INamedComponent c = ass.Object as INamedComponent;
            int n = str.LastIndexOf(".");
            string s = str.Substring(0, n);
            if (s.Equals(PureDesktop.GetRelativeName(ao, ass)))
            {
                return c;
            }
            else
            {
                return null;
            }
        }



        /// <summary>
        /// Gets aliases linked with object
        /// </summary>
        /// <param name="o"></param>
        /// <param name="list"></param>
        public static void GetObjectAliases(IAssociatedObject baseObject, object o, List<string> list)
        {
            IAssociatedObject ass = o as IAssociatedObject;
            IObjectLabel l = ass.Object as IObjectLabel;
            GetAliases(baseObject, l, list);
        }


        /// <summary>
        /// Gets aliases of associated object
        /// </summary>
        /// <param name="baseObject">Base object</param>
        /// <param name="lab">Label</param>
        /// <param name="list">List</param>
        static public void GetAliases(IAssociatedObject baseObject, IObjectLabel lab, List<string> list)
        {
            INamedComponent nc = baseObject.Object as INamedComponent;
            IDesktop d = nc.Desktop;
            if (!(lab.Object is IAlias))
            {
                return;
            }
            IAlias al = lab.Object as IAlias;
            foreach (string s in al.AliasNames)
            {
                string str = lab.GetName(d) + "." + s;
                if (list.Contains(str))
                {
                    continue;
                }
                list.Add(lab.GetName(d) + "." + s);
            }
        }


        /// <summary>
        /// Gets component name relatively desktop
        /// </summary>
        /// <param name="component">The component</param>
        /// <param name="desktop">The desktop</param>
        /// <returns>Relalive name</returns>
        public static string GetName(INamedComponent component, IDesktop desktop)
        {
            string name = component.Name + "";
            if (component.Desktop == desktop)
            {
                return name;
            }
            INamedComponent parent = component.Parent;
            if (parent == null)
            {
                return null;
            }
            string parentName = GetName(parent, desktop);
            if (parentName == null)
            {
                return null;
            }
            return parentName + "/" + name;
        }

        /// <summary>
        /// Wrappers
        /// </summary>
        static public bool Wrappers
        {
            get
            {
                return wrappers;
            }
            set
            {
                wrappers = value;
            }
        }


        #endregion

    }
}
