using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Serialization;
using System.Collections;



using DiagramUI;
using CategoryTheory;

namespace Motion6D
{
    [Serializable()]
    public class ReferenceFrameArrow : ISerializable, ICategoryArrow, IRemovableObject
    {
        #region Fields
        IPosition source;
        IReferenceFrame target;
        object obj;
        #endregion

        #region Constructors

        public ReferenceFrameArrow()
        {
        }

        public ReferenceFrameArrow(SerializationInfo info, StreamingContext context)
        {
        }

        #endregion

        #region ISerializable Members

        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
        {
        }

        #endregion

        #region ICategoryArrow Members

        ICategoryObject ICategoryArrow.Source
        {
            get
            {
                return source as ICategoryObject;
            }
            set
            {
                if (!(value is IPosition))
                {
                    CategoryException.ThrowIllegalSourceException();
                }
                IPosition position = value as IPosition;
                if (position.Parent != null)
                {
                    throw new CategoryException("Root", this);
                }
                source = position;
            }
        }

        ICategoryObject ICategoryArrow.Target
        {
            get
            {
                return target as ICategoryObject;
            }
            set
            {
                if (!(value is IReferenceFrame))
                {
                    CategoryException.ThrowIllegalTargetException();
                }
                IAssociatedObject sa = source as IAssociatedObject;
                IAssociatedObject ta = value as IAssociatedObject;
                INamedComponent ns = sa.Object as INamedComponent;
                INamedComponent nt = ta.Object as INamedComponent;
                if ((nt.Root != nt) | (ns.Root != ns))
                {
                    if (nt.Root.Ord >= ns.Root.Ord)
                    {
                        throw new Exception("Illegal order");
                    }
                }
                target = value as IReferenceFrame;
                source.Parent = target;
                target.Children.Add(source);
            }
        }

        bool ICategoryArrow.IsMonomorphism
        {
            get { throw new Exception("The method or operation is not implemented."); }
        }

        bool ICategoryArrow.IsEpimorphism
        {
            get { throw new Exception("The method or operation is not implemented."); }
        }

        bool ICategoryArrow.IsIsomorphism
        {
            get { throw new Exception("The method or operation is not implemented."); }
        }

        ICategoryArrow ICategoryArrow.Compose(ICategory category, ICategoryArrow next)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        #endregion

        #region IAssociatedObject Members

        object IAssociatedObject.Object
        {
            get
            {
                return obj;
            }
            set
            {
                obj = value;
            }
        }

        #endregion

        #region IRemovableObject Members

        void IRemovableObject.RemoveObject()
        {
            source.Parent = null;
            if (target != null)
            {
                target.Children.Remove(source);
            }
        }

        #endregion

        #region Specific Members

        static public List<IPosition> Prepare(IDesktop desktop)
        {
            List<IPosition> frames = new List<IPosition>();
            ICollection objs = desktop.AllComponents;
            foreach (object o in objs)
            {
                if (!(o is IObjectLabel))
                {
                    continue;
                }
                IObjectLabel lab = o as IObjectLabel;
                ICategoryObject co = lab.Object;
                if (!(co is IReferenceFrame))
                {
                    if (co is IPosition)
                    {
                        IPosition p = co as IPosition;
                        if (p.Parent == null)
                        {
                            frames.Add(p);
                        }
                    }
                    continue;
                }
                IReferenceFrame f = co as IReferenceFrame;
                if (f.Parent != null)
                {
                    continue;
                }
                prepare(f, frames);
            }
            return frames;
        }

        public static void Update(List<IPosition> frames)
        {
            foreach (IPosition frame in frames)
            {
                frame.Update();
            }
        }


        private static void prepare(IReferenceFrame frame, List<IPosition> frames)
        {
            List<IPosition> children = frame.Children;
            frames.Add(frame);
            foreach (IPosition p in children)
            {
                if (frames.Contains(p))
                {
                    continue;
                }
                if (p is IReferenceFrame)
                {
                    IReferenceFrame f = p as IReferenceFrame;
                    prepare(f, frames);
                }
                else
                {
                    frames.Add(p);
                }
            }
        }

        #endregion
    }
}
