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

using CategoryTheory;
using DiagramUI;


namespace DataPerformer
{
    /// <summary>
    /// The link with data provider
    /// </summary>
    [Serializable()]
    public class DataLink : ICategoryArrow, ISerializable,
        IRemovableObject
    {

        /// <summary>
        /// Error message
        /// </summary>
        public static readonly string SetProviderBefore = "You should create measurements source before consumer";


        /// <summary>
        /// The source of this arrow
        /// </summary>
        private IDataConsumer source;

        /// <summary>
        /// The target of this arrow
        /// </summary>
        private IMeasurements target;

        /// <summary>
        /// Auxiliary field
        /// </summary>
        private int a = 0;

        /// <summary>
        /// Linked object
        /// </summary>
        protected object obj;


        /// <summary>
        /// Constuctor
        /// </summary>
        public DataLink()
        {
        }

        /// <summary>
        /// Deserializetion contructor
        /// </summary>
        /// <param name="info">Serialization info</param>
        /// <param name="context">Streaming context</param>
        public DataLink(SerializationInfo info, StreamingContext context)
        {
            a = (int)info.GetValue("A", typeof(int));
        }

        /// <summary>
        /// ISerializable interface implementation
        /// </summary>
        /// <param name="info">Serialization info</param>
        /// <param name="context">Streaming context</param>
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("A", a);
        }

        /// <summary>
        /// Creates correspond xml
        /// </summary>
        /// <param name="doc">document to create element</param>
        /// <returns>The created element</returns>
        /*public XmlElement CreateXml(XmlDocument doc)
        {
            XmlElement el = doc.CreateElement("DataLink");
            return el;
        }*/


        /// <summary>
        /// The source of this arrow
        /// </summary>
        public ICategoryObject Source
        {
            set
            {
                if (!(value is IDataConsumer))
                {
                    CategoryException.ThrowIllegalSourceException();
                }
                source = value as IDataConsumer;
            }

            get
            {
                return source as ICategoryObject;
            }
        }

        /// <summary>
        /// Measurements provider
        /// </summary>
        public IMeasurements Measurements
        {
            get
            {
                return target;
            }
        }

        /// <summary>
        /// The target of this arrow
        /// </summary>
        public ICategoryObject Target
        {
            get
            {
                return target as ICategoryObject;
            }
            set
            {
                if (!(value is IMeasurements))
                {
                    CategoryException.ThrowIllegalTargetException();
                }
                ICategoryObject s = source as ICategoryObject;
                INamedComponent ns = s.Object as INamedComponent;
                INamedComponent nt = value.Object as INamedComponent;
                if (nt.Root.Ord >= ns.Root.Ord)
                {
                    throw new Exception(SetProviderBefore);
                }
                target = value as IMeasurements;
                source.Add(target);
            }
        }

        public bool IsMonomorphism
        {
            get
            {
                return false;
            }
        }

        public bool IsEpimorphism
        {
            get
            {
                return false;
            }
        }

        public bool IsIsomorphism
        {
            get
            {
                return false;
            }
        }


        /// <summary>
        /// Composes this arrow "f" with next arrow "g" 
        /// </summary>
        /// <param name="category"> The category of arrow</param>
        /// <param name="next"> The next arrow "g" </param>
        /// <returns>Composition "fg" </returns>
        public ICategoryArrow Compose(ICategory category, ICategoryArrow next)
        {
            return null;
        }

        /// <summary>
        /// Associated object
        /// </summary>
        public object Object
        {
            get
            {
                return obj;
            }
            set
            {
                obj = value;
            }
        }

        /// <summary>
        /// The post remove operation
        /// </summary>
        public void RemoveObject()
        {
            source.Remove(target);
        }

    }
}
