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

using CategoryTheory;

namespace DiagramUI
{
    /// <summary>
    /// Wrapper of object loaded from dll
    /// </summary>
    [Serializable()]
    public class LibraryObjectWrpapper : CategoryObjectWrapper, ISerializable
    {

        #region Fields

        /// <summary>
        /// The name
        /// </summary>
        private string name;

        /// <summary>
        /// The dll path
        /// </summary>
        private string filename;

        /// <summary>
        /// The properties
        /// </summary>
        protected object properties;


        #endregion

        #region Constructors

        public LibraryObjectWrpapper()
        {
        }

        public LibraryObjectWrpapper(SerializationInfo info, StreamingContext context)
        {
            filename = info.GetValue("FileName", typeof(string)) + "";
            name = info.GetValue("Name", typeof(string)) + "";
            try
            {
                properties = info.GetValue("Properties", typeof(object));
            }
            catch (Exception)
            {
            }
            init();
        }


        #endregion

        #region ISerializable Members

        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            info.AddValue("FileName", filename);
            info.AddValue("Name", name);
            if (theObject != null)
            {
                if (theObject is IPropertiesEditor)
                {
                    IPropertiesEditor pe = theObject as IPropertiesEditor;
                    object prop = pe.Properties;
                    info.AddValue("Properties", prop);
                }
            }
        }

        #endregion

        #region Specific members

        static public string[] GetNames(string filename)
        {
            Assembly ass = null;
            if (BinaryLoader.Object != null)
            {
                byte[] b = BinaryLoader.Object[filename];
                if (b != null)
                {
                    ass = Assembly.Load(b);
                }
            }
            if (ass == null)
            {
                ass = Assembly.LoadFile(filename);
            }
            IObjectFactory factory = GetFactory(ass);
            return factory.Names;
        }


        public void Set(string filename, string name)
        {
            this.filename = filename;
            this.name = name;
            init();
        }

        public string FileName
        {
            get
            {
                return filename;
            }
        }

        public string Name
        {
            get
            {
                return name;
            }
        }



        protected void init()
        {
            Assembly ass = null;
            if (BinaryLoader.Object != null)
            {
                byte[] b = BinaryLoader.Object[filename];
                if (b != null)
                {
                    ass = Assembly.Load(b);
                }
            }
            if (ass == null)
            {
                ass = Assembly.LoadFile(filename);
            }
            IObjectFactory factory = GetFactory(ass);
            theObject = factory[name];
            if (theObject is IPropertiesEditor)
            {
                if (properties != null)
                {
                    IPropertiesEditor pe = theObject as IPropertiesEditor;
                    pe.Properties = properties;
                }
            }
        }

        static public IObjectFactory GetFactory(Assembly ass)
        {
            Type[] types = ass.GetTypes();

            foreach (Type type in types)
            {
                if (type.GetInterface("IObjectFactory") != null)
                {
                    FieldInfo fi = type.GetField("Object");
                    if (fi != null)
                    {
                        return fi.GetValue("Object") as IObjectFactory;
                    }
                    else
                    {
                        return type.GetConstructor(new Type[] { }).Invoke(new object[] { }) as IObjectFactory;
                    }
                }
            }
            return null;

        }

        #endregion

    }
}
