/[xmltv_parser]/trunk/libxmltv/Core/XMLTVRuntimeInstance.cs
ViewVC logotype

Diff of /trunk/libxmltv/Core/XMLTVRuntimeInstance.cs

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

--- trunk/libxmltv/Core/XMLTVInstance.cs	2013/03/08 07:01:37	52
+++ trunk/libxmltv/Core/XMLTVRuntimeInstance.cs	2013/03/16 13:26:09	167
@@ -4,99 +4,485 @@
 using System.Text;
 using libxmltv.Interfaces;
 using System.ComponentModel;
+using System.Windows.Forms;
+using System.Threading;
+using System.Reflection;
+using System.Globalization;
+using System.Diagnostics;
+using System.Xml.Linq;
+using Enterprise.Logging;
+using System.IO;
 
 namespace libxmltv.Core
 {
     [Serializable]
-    internal class XMLTVRuntimeInstance : MarshalByRefObject, IXMLTVRuntimeInstance, ISerializer<XMLTVRuntimeInstance>
+    internal class XMLTVRuntimeInstance : MarshalByRefObject, 
+        IXMLTVRuntimeInstance, 
+        ISerializer<XMLTVRuntimeInstance>, 
+        IGetCreatedInstanceEvent, 
+        ISetCreatedInstanceEvent, 
+        IDestroyInstance, 
+        IRuntimeInstanceLoader<XMLTVRuntimeInstance>
     {
-        public XMLTVRuntimeInstance(string xmlfile) { CreateInstance(xmlfile); }
-        //public XMLTVRuntimeInstance(string xmlfile) : this(xmlfile, null) { }
-        //public XMLTVRuntimeInstance(string xmlfile, EventHandler<CancelEventArgs> t) { CreateInstance(xmlfile,t); }
-        private void CreateInstance(string xmlfile)
+        [NonSerialized]
+        Thread worker;
+        public XMLTVRuntimeInstance() { init(); }
+        public XMLTVRuntimeInstance(string xmlfile) : this(xmlfile, null) { }
+        public XMLTVRuntimeInstance(string xmlfile, EventHandler<EventArgs> handler)
+            : this()
         {
-            //CancelEvent = t;
-            using (XMLTVInstance instance = new XMLTVInstance(xmlfile, this))
+            this.OnInstanceCreated += handler;
+            worker = new Thread(new ParameterizedThreadStart(CreateInstance)); worker.Start(xmlfile);
+        }
+        private void CreateInstance(object xmlfile)
+        {
+            using (XMLTVInstance instance = new XMLTVInstance(xmlfile.ToString()))
             {
+                this.LoadFromInstance(instance.GetInstance());
+                OnCreatedInstance(this, new EventArgs());
             }
         }
+        
+        private void OnCreatedInstance(object sender, EventArgs e)
+        {
+            if (OnInstanceCreated != null) { OnInstanceCreated.Invoke(sender, e); }
+        }
 
-        //internal XMLTVInstance Instance { get; private set; }
+        private void init()
+        {
+            this.Source = new XMLTVSource();
+            this.Channels = new ChannelList();
+            this.Programs = new ProgramList();
+            this.XmlFile_Name = string.Empty;
+            this.XmlFile_FullName = string.Empty;
+            this.XmlDoc = string.Empty;
+            this.OnInstanceCreated = null;
+            this.ExtraEntries = new ExtraList();
+        }
 
-        #region IXMLTV_LOADER members
-        public System.IO.FileInfo XmlFile { get; set; }
-        public string XmlDoc { get; set; }
+        #region IXMLTVRuntimeInstance members
+        private bool _IsAborting;
+        public bool IsAborting { get { return _IsAborting; } private set { _IsAborting = value; } }
+
+
+        private string _XmlFile_Name;
+        public string XmlFile_Name { get { return _XmlFile_Name; } set { _XmlFile_Name = value; } }
+        private string _XmlFile_FullName;
+        public string XmlFile_FullName { get { return _XmlFile_FullName; } set { _XmlFile_FullName = value; } }
+
+        private string _XmlDoc;
+        public string XmlDoc { get { return _XmlDoc; } set { _XmlDoc = value; } }
+        private IXMLTVSource _Source;
+        public IXMLTVSource Source { get { return _Source; } set { _Source = value; } }
+        private ChannelList _Channels;
+        public ChannelList Channels { get { return _Channels; } set { _Channels = value; } }
+        private ProgramList _Programs;
+        public ProgramList Programs { get { return _Programs; } set { _Programs = value; } }
+
+        private ExtraList _ExtraEntries;
+        public ExtraList ExtraEntries { get { return _ExtraEntries; } set { _ExtraEntries = value; } }
+        #endregion       
+        #region IOnInstanceCreated members
+        [NonSerialized]
+        private EventHandler<EventArgs> _OnInstanceCreated;
+        public EventHandler<EventArgs> OnInstanceCreated { get { return _OnInstanceCreated; } set { _OnInstanceCreated = value; } }
+        #endregion
+        #region IGetCreatedInstanceEvent members
+        public EventHandler<EventArgs> GetOnInstanceCreated() { return OnInstanceCreated; }
+        #endregion
+        #region ISetCreatedInstanceEvent members
+        public void SetOnInstanceCreated(EventHandler<EventArgs> event_instance) { OnInstanceCreated = event_instance; }
+        #endregion
+        #region ISerializer<XMLTVRuntimeInstance> members
+        public IXMLTVSerializer<XMLTVRuntimeInstance> Serializer { get { return new XMLTVSerializer<XMLTVRuntimeInstance>(this); } }
         #endregion
-        #region IXMLTV_PARSER Members
-        public IXMLTVSource Source { get; set; }
-        public Dictionary<string, IXMLTVChannel> Channels { get; set; }
-        public Dictionary<int, IXMLTVProgram> Programs { get; set; }
-        #endregion   
-    
-        public IXMLTVSerializer<XMLTVRuntimeInstance> Serializer
+        #region IDestroyInstance member
+        public void DestroyInstance()
         {
-            get 
+            xmltv_logger.Debug.WriteLine("Destoying Instance of: '{0}'", this.GetType().Name);
+            this.IsAborting = true;
+            if (worker == null)
             {
-                ///* We have to set CancelEvent to null, before returning a new instance of the serializer otherwise all subscribers to the event will have to be marked as serializeable.
-                //   Most subscribers will be of type: System.Windows.Forms which is not marked as serializable and will fail to serialize. */
-                //if (CancelEvent != null) { CancelEvent = null; }
-                return new XMLTVSerializer<XMLTVRuntimeInstance>(this); 
+                xmltv_logger.Debug.WriteLine("Unable to destroy instance of: '{0}' - worker thread is null", this.GetType().Name);
+                return;
+            }
+            else
+            {
+                if (worker.IsAlive)
+                {
+                    xmltv_logger.Verbose.Debug.WriteLine("Requesting Instance to Abort...");
+                    while (worker.IsAlive) { worker.Abort(); Application.DoEvents(); }
+                }
+                else { xmltv_logger.Debug.WriteLine("Instance of: '{0}'- already destroyed.", this.GetType().Name); }
             }
         }
-        //public void Dispose()
-        //{
-        //    IsDisposing = true;
-        //    //throw new NotImplementedException();
-        //}
-        //public bool IsDisposing { get; private set; }
-
-
-        //private event EventHandler<CancelEventArgs> CancelEvent = null;
-
-        public bool IsAborting
+        #endregion
+        #region  IRuntimeInstanceLoader<XMLTVRuntimeInstance> member
+        public XMLTVRuntimeInstance LoadFromInstance(XMLTVRuntimeInstance instance)
         {
-            get
+            if (instance == null)
+            {
+                throw new NullReferenceException("Failed to load from instance because the instance is null.");
+            }
+            xmltv_logger.Debug.WriteLine("Loading from instance...");
+            CloneFromInstance(ref instance);            
+            xmltv_logger.Debug.WriteLine("Loaded from instance...");
+            if (this.Source != null)
             {
-                //if (CancelEvent != null)
-                //{
-                //    CancelEventArgs e = new CancelEventArgs();
-                //    CancelEvent.Invoke(this, e);
-                //    if (e.Cancel)
-                //    {
-                //        xmltv_logger.Log.Verbose.Debug.WriteLine("Detected Instance abort event...");
-                //    }
-                //    return e.Cancel;
-                //}
-                //return false;
-                return false;
+                xmltv_logger.Info.WriteLine("Source Loaded: '{0}' Created by '{1}' - original source file: '{2}'", this.Source.SourceName, this.Source.GeneratorName, this.XmlFile_FullName);
             }
+            else
+            {
+                xmltv_logger.Error.WriteLine("Source Property is null.");
+                throw new NullReferenceException("Source Property is null.");
+            }
+            if (this.Channels != null)
+            {
+                xmltv_logger.Info.WriteLine("Source Loaded: '{0}' Channels from source '{1}'", this.Channels.Count, this.Source.SourceName);
+            }
+            else
+            {
+                xmltv_logger.Error.WriteLine("Channels Property is null.");
+                throw new NullReferenceException("Channels Property is null.");
+            }
+            if (this.Programs != null)
+            {
+                xmltv_logger.Info.WriteLine("Source Loaded: '{0}' Programs from source '{1}'", this.Programs.Count, this.Source.SourceName);
+            }
+            else
+            {
+                xmltv_logger.Error.WriteLine("Programs Property is null.");
+                throw new NullReferenceException("Programs Property is null.");
+            }            
+            return instance;
         }
-
-
+        #endregion
+        #region CloneFromInstance
+        private void CloneFromInstance(ref XMLTVRuntimeInstance instance)
+        {
+            xmltv_logger.Debug.WriteLine("Cloning from instance...");
+            BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
+            CultureInfo culture = CultureInfo.CurrentCulture;
+            Type t = typeof(XMLTVRuntimeInstance);
+            foreach (var field in t.GetFields(flags))
+            {
+                try
+                {
+                    if (field.IsNotSerialized) { continue; }                    
+                    var f = instance.GetType().GetField(field.Name, flags);                    
+                    var v = f.GetValue(instance);
+                    if (v != null)
+                    {
+                        field.SetValue(this, v);
+                    }
+                    else
+                    {
+                        xmltv_logger.Debug.WriteLine("Attempted to set field: '{0}' with a null value.  The operation was aborted.", f.Name);
+                        continue;
+                    }
+                }
+                catch (Exception ex)
+                {
+                    throw new Exception(string.Format("Unable to copy value for field: '{0}' from instance", field.Name), ex);
+                }
+            }
+            foreach (var property in t.GetProperties(flags))
+            {
+                try
+                {
+                    var f = instance.GetType().GetProperty(property.Name);
+                    object value = null;
+                    try
+                    {
+                        value = f.GetValue(instance, null);
+                    }
+                    catch (ArgumentException ex) { if (ex.Message == "Property get method not found.") { Debug.WriteLine(ex.ToString()); } else { throw ex; } }
+                    try
+                    {
+                        if (value != null)
+                        {
+                            property.SetValue(this, value, null);
+                        }
+                        else
+                        {
+                            xmltv_logger.Debug.WriteLine("Attempted to set property: '{0}' with a null value.  The operation was aborted.", f.Name);
+                            continue;
+                        }
+                    }
+                    catch (ArgumentException ex) { if (ex.Message == "Property set method not found.") { Debug.WriteLine(ex.ToString()); } else { throw ex; } }
+
+                }
+                catch (Exception ex)
+                {
+                    throw new Exception(string.Format("Unable to copy value for property: '{0}' from instance", property.Name), ex);
+                }
+            }
+            xmltv_logger.Debug.WriteLine("Cloned from instance...");
+        }
+        #endregion
     }
 
-    internal class XMLTVInstance : IDisposable
+    internal class XMLTVInstance : IGetInstance<XMLTVRuntimeInstance>, IDisposable
     {
-        public XMLTVInstance(string xmlfile, XMLTVRuntimeInstance instance) 
-        { 
-            CreateLoader(xmlfile, instance);
-            CreateParser(instance);
+        public void Dispose()
+        {
+            //throw new NotImplementedException();
+        }
+
+        private XMLTVRuntimeInstance gInstance;
+        public XMLTVRuntimeInstance GetInstance() { return gInstance; }
+        public XMLTVInstance(string xmlfile) 
+        {
+            try
+            {
+                CreateLoader(xmlfile);
+                CreateParser();
+            }
+            catch (ThreadAbortException ex) { Debug.WriteLine(ex.ToString()); }
+            catch (Exception ex)
+            {
+                xmltv_logger.Error.WriteLine(ex.ToString());
+            }
         }
 
-        private void CreateLoader(string xml_file, XMLTVRuntimeInstance instance)
+        private void CreateLoader(string xml_file)
         {
-            //XMLTVLoader loader = new XMLTVLoader(xml_file, instance);
-            XMLTVLoader.CreateInstance(xml_file, instance);
+            xmltv_logger.Verbose.Debug.WriteLine("Creating loader handle");
+            gInstance = new XMLTVRuntimeInstance();
+            object raw_instance = null;
+            BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
+            CultureInfo culture = CultureInfo.CurrentCulture;
+            Assembly asm = Assembly.GetExecutingAssembly();
+            var types = asm.GetTypes();
+            Type handler_type = null;
+            foreach (var type in types)
+            {
+                if (type.BaseType != null && type.BaseType == typeof(XMLTVBase<XMLTVRuntimeInstance>))
+                {
+                    //xmltv_logger.Verbose.Debug.WriteLine("Type: '{0}' Base: '{1}'", type.Name, type.BaseType == null ? "none" : type.BaseType.Name);                  
+                    object[] args = new object[] { xml_file, gInstance };
+                    var iface = type.GetInterface("IXMLTVHandler", true);
+                    if (iface != null)
+                    {
+                        var handler_prop = type.GetProperty("Handler");
+                        if (handler_prop != null)
+                        {
+                            var ctors = type.GetConstructors(flags);
+                            bool has_string_ctor = false;
+                            foreach (var ctor in ctors) { if (ctor.GetParameters().Count() == 1 && ctor.GetParameters()[0].ParameterType == typeof(string)) { has_string_ctor = true; } }
+                            if (!has_string_ctor) { continue; }
+                            raw_instance = Activator.CreateInstance(type, flags, null, new object[] { xml_file}, culture);
+                            if (raw_instance != null)
+                            {
+                                object handler_value = handler_prop.GetValue(raw_instance, null);
+                                if (handler_value != null && handler_value.ToString() == xml_file)
+                                {
+                                    handler_type = type;
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                }                
+            }
+            if (handler_type == null) { throw new Exception("Unable to find a compatible XMLTV Data Loader."); }
+            xmltv_logger.Verbose.Debug.WriteLine("Created loader handle");
+            raw_instance = Activator.CreateInstance(handler_type, flags, null, new object[] {xml_file , gInstance }, culture);
+            if (raw_instance == null) { throw new NullReferenceException("Found a compatible XMLTV Data Loader, but it returned invalid data."); }
+            IGetInstance<XMLTVRuntimeInstance> getter_instance = (raw_instance as IGetInstance<XMLTVRuntimeInstance>);
+            if (getter_instance != null) { gInstance = getter_instance.GetInstance(); }
+            else { throw new Exception("Found a compatible XMLTV Data Loader, but was unable to obtain the instance holding the data"); }
         }
-        private void CreateParser(XMLTVRuntimeInstance instance)
+        private void CreateParser()
         {
-            //XMLTVParser parser = new XMLTVParser(instance);
-            XMLTVParser.CreateInstance(instance);
+            var doc = XDocument.Parse(this.GetInstance().XmlDoc);
+            var root_element = doc.Root;            
+            CreateHandlerForRootNode(root_element);
+            var nodes = doc.Root.Elements().ToList();
+
+            double total_nodes = nodes.Count;
+            double node_index = 0;
+            double progress = 0;
+            foreach(var node in nodes)
+            {
+                if (this.GetInstance().IsAborting)
+                {
+                    break;
+                }
+                if (!CreateHandlerForNode(node)) { xmltv_logger.Verbose.Debug.WriteLine("Unable to create handler for node: '{0}'", node.Name.ToString()); }
+                node_index++;
+                progress = 100.0 * (node_index / total_nodes);
+                xmltv_logger.ReportProgress(this, new ReportProgressEventArgs((int)progress, string.Format("Loading {0} ==> {1:00}%", this.gInstance.XmlFile_Name, (int)progress)));
+                Application.DoEvents();
+            }
         }
 
-        public void Dispose()
+
+        private void CreateHandlerForRootNode(XElement root)
+        {                        
+            if (root == null) { throw new NullReferenceException("Root element is null"); }
+            if (root.Name == null) { throw new NullReferenceException("Root element's Name is null"); }
+            var root_name =  root.Name.ToString();
+            xmltv_logger.Verbose.Debug.WriteLine("Creating handler for root: '{0}'", root_name.ToString());
+            object raw_instance = null;
+            BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
+            CultureInfo culture = CultureInfo.CurrentCulture;
+            Assembly asm = Assembly.GetExecutingAssembly();
+            var types = asm.GetTypes();
+            Type handler_type = null;
+            foreach (var type in types)
+            {
+                if (type.BaseType != null && type.BaseType == typeof(XMLTVBase<XMLTVRuntimeInstance>))
+                {                    
+                    var iface = type.GetInterface("IXMLTVHandler", true);
+                    if (iface != null)
+                    {
+                        var handler_prop = type.GetProperty("Handler");
+                        if (handler_prop != null)
+                        {
+                            var ctors = type.GetConstructors(flags);
+                            bool has_default_ctor = false;
+                            foreach (var ctor in ctors) { if (ctor.GetParameters().Count() == 0) { has_default_ctor = true; } }
+                            ctors = null;
+                            if (!has_default_ctor) { continue; }
+                            raw_instance = Activator.CreateInstance(type, flags, null, new object[0], culture);
+                            if (raw_instance != null)
+                            {
+                                object handler_value = handler_prop.GetValue(raw_instance, null);
+                                if (handler_value != null && handler_value.ToString() == root_name)
+                                {
+                                    handler_type = type;
+                                    handler_value = null;
+                                    raw_instance = null;
+                                    handler_prop = null;
+                                    iface = null;
+                                    break;
+                                }
+                                handler_value = null;
+                            }
+                            raw_instance = null;
+                        }
+                        handler_prop = null;
+                    }
+                    iface = null;
+                }
+            }
+            asm = null;
+            types = null;
+            if (handler_type == null) 
+            {
+                StringBuilder node_builder = new StringBuilder();
+                node_builder.AppendFormat("<{0} ", root.Name);
+                if (root.HasAttributes) { foreach (var attribute in root.Attributes()) { node_builder.AppendFormat("{0}=\"{1}\" ", attribute.Name, attribute.Value); } }
+                string node_text = string.Format("{0}>", node_builder.ToString().TrimEnd(new char[] { ' ' }));
+                throw new Exception(string.Format("Unable to find a compatible handler to parse node: {0}", node_text)); 
+            }
+            xmltv_logger.Verbose.Debug.WriteLine("Created handler for root: '{0}'", root_name.ToString());
+            raw_instance = Activator.CreateInstance(handler_type, flags, null, new object[] { gInstance }, culture);
+            raw_instance = null;
+            flags = 0;
+            culture = null;            
+        }
+
+        private bool CreateHandlerForNode(XElement node)
         {
-            //throw new NotImplementedException();
+            if (node == null) { throw new NullReferenceException("Node element is null"); }
+            if (node.Name == null) { throw new NullReferenceException("Node element's Name is null"); }
+            //var node_name = node.Name.ToString();
+
+            xmltv_logger.Verbose.Debug.WriteLine("Creating handler for node: '{0}'", node.Name.ToString());
+            object raw_instance = null;
+            BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
+            CultureInfo culture = CultureInfo.CurrentCulture;
+            Assembly asm = Assembly.GetExecutingAssembly();
+            var types = asm.GetTypes();
+            Type handler_type = null;
+            foreach (var type in types)
+            {
+                if (type.BaseType != null && type.BaseType == typeof(XMLTVBase<XMLTVRuntimeInstance>))
+                {
+                    var iface = type.GetInterface("IXMLTVHandler", true);
+                    if (iface != null)
+                    {
+                        var handler_prop = type.GetProperty("Handler");
+                        if (handler_prop != null)
+                        {
+                            var ctors = type.GetConstructors(flags);
+                            bool has_default_ctor = false;
+                            foreach (var ctor in ctors) { if (ctor.GetParameters().Count() == 0) { has_default_ctor = true; } }
+                            ctors = null;
+                            if (!has_default_ctor) { continue; }
+                            raw_instance = Activator.CreateInstance(type, flags, null, new object[0], culture);
+                            if (raw_instance != null)
+                            {
+                                object handler_value = handler_prop.GetValue(raw_instance, null);
+                                if (handler_value != null && handler_value.ToString() == node.Name.ToString())
+                                {
+                                    handler_type = type;
+                                    handler_value = null;
+                                    raw_instance = null;
+                                    handler_prop = null;
+                                    iface = null;
+                                    break;
+                                }
+                                handler_value = null;
+                            }
+                            raw_instance = null;
+                        }
+                        handler_prop = null;
+                    }
+                    iface = null;
+                }
+            }
+            asm = null;
+            types = null;
+            if (handler_type == null)
+            {
+                try
+                {
+                    raw_instance = Activator.CreateInstance(typeof(UnhandledNodeData), flags, null, new object[] { gInstance, node }, culture);
+                }
+                catch (Exception ex) { throw ex; }
+
+                if (raw_instance == null)
+                {
+                    StringBuilder node_builder = new StringBuilder();
+                    node_builder.AppendFormat("<{0} ", node.Name);
+                    if (node.HasAttributes) { foreach (var attribute in node.Attributes()) { node_builder.AppendFormat("{0}=\"{1}\" ", attribute.Name, attribute.Value); } }
+                    string node_text = string.Format("{0}>", node_builder.ToString().TrimEnd(new char[] { ' ' }));
+                    throw new Exception(string.Format("Unable to find a compatible handler to parse node: {0}", node_text));
+                }
+            }
+            else
+            {
+                xmltv_logger.Verbose.Debug.WriteLine("Created handler for node: '{0}'", node.Name.ToString());
+                raw_instance = Activator.CreateInstance(handler_type, flags, null, new object[] { gInstance, node }, culture);                
+            }
+            raw_instance = null;
+            flags = 0;
+            culture = null;
+            node = null;
+            return true;
+        }
+        #region UnhandledExtraMetaData
+        private class UnhandledNodeData : XMLTVBase<XMLTVRuntimeInstance>
+        {
+            public UnhandledNodeData() : base(null, null) { }
+            public UnhandledNodeData(XMLTVRuntimeInstance instance, XElement node)
+                : base(instance, null)
+            {
+                if (node == null) { throw new NullReferenceException("The node instance was null"); }
+                xmltv_logger.Verbose.Debug.WriteLine("Parsng unhandled node data: {0}", node.Name.ToString());
+                if (this.GetInstance() != null)
+                {
+                    ExtraMetaData data = new ExtraMetaData(node);
+                    instance.ExtraEntries.Add(data);
+                    data = null;
+                }
+                node = null;
+            }
         }
+        #endregion
+        
     }
 }

 

  ViewVC Help
Powered by ViewVC 1.1.22