/[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 12:20:50	58
+++ trunk/libxmltv/Core/XMLTVRuntimeInstance.cs	2013/03/10 12:58:40	107
@@ -9,6 +9,7 @@
 using System.Reflection;
 using System.Globalization;
 using System.Diagnostics;
+using System.Xml.Linq;
 
 namespace libxmltv.Core
 {
@@ -23,62 +24,77 @@
     {
         [NonSerialized]
         Thread worker;
-        public XMLTVRuntimeInstance()
+        public XMLTVRuntimeInstance() { init(); }
+        public XMLTVRuntimeInstance(string xmlfile) : this(xmlfile, null) { }
+        public XMLTVRuntimeInstance(string xmlfile, EventHandler<EventArgs> handler)
+            : this()
         {
+            this.OnInstanceCreated += handler;
+            worker = new Thread(new ParameterizedThreadStart(CreateInstance)); worker.Start(xmlfile);
         }
-        public XMLTVRuntimeInstance(string xmlfile) 
-        {
-            worker = new Thread(new ParameterizedThreadStart(CreateInstance));
-            //CreateInstance(xmlfile);
-            worker.Start(xmlfile);
-        }
-        //public XMLTVRuntimeInstance(string xmlfile) : this(xmlfile, null) { }
-        //public XMLTVRuntimeInstance(string xmlfile, EventHandler<CancelEventArgs> t) { CreateInstance(xmlfile,t); }
         private void CreateInstance(object xmlfile)
-        {            
-            //CancelEvent = t;
-            using (XMLTVInstance instance = new XMLTVInstance(xmlfile.ToString(), this))
+        {
+            using (XMLTVInstance instance = new XMLTVInstance(xmlfile.ToString()))
             {
-                if (OnInstanceCreated != null)
-                {
-                    OnInstanceCreated.Invoke(this,new EventArgs());
-                }
+                this.LoadFromInstance(instance.GetInstance());
+                OnCreatedInstance(this, new EventArgs());
             }
         }
+        
+        private void OnCreatedInstance(object sender, EventArgs e)
+        {
+            if (OnInstanceCreated != null) { OnInstanceCreated.Invoke(sender, e); }
+        }
+
+        private void init()
+        {
+            this.Source = new XMLTVSource();
+            this.Channels = new List<IXMLTVChannel>();
+            this.Programs = new List<IXMLTVProgram>();
+            this.XmlFile_Name = string.Empty;
+            this.XmlFile_FullName = string.Empty;
+            this.XmlDoc = string.Empty;
+            this.OnInstanceCreated = null;
+            this.ExtraEntries = new List<IExtraMetaData>();
+        }
+
+        #region IXMLTVRuntimeInstance members
+        private bool _IsAborting;
+        public bool IsAborting { get { return _IsAborting; } private set { _IsAborting = value; } }
+
 
-        //internal XMLTVInstance Instance { get; private set; }
+        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; } }
 
-        #region IXMLTV_LOADER members
-        private System.IO.FileInfo _XmlFile;
-        public System.IO.FileInfo XmlFile { get { return _XmlFile; } set { _XmlFile = value; } }
         private string _XmlDoc;
         public string XmlDoc { get { return _XmlDoc; } set { _XmlDoc = value; } }
-        #endregion
-        #region IXMLTV_PARSER Members
         private IXMLTVSource _Source;
         public IXMLTVSource Source { get { return _Source; } set { _Source = value; } }
-        private Dictionary<string, IXMLTVChannel> _Channels;
-        public Dictionary<string, IXMLTVChannel> Channels { get { return _Channels; } set { _Channels = value; } }
-        private Dictionary<int, IXMLTVProgram> _Programs;
-        public Dictionary<int, IXMLTVProgram> Programs { get { return _Programs; } set { _Programs = value; } }
-        #endregion   
-    
+        private List<IXMLTVChannel> _Channels;
+        public List<IXMLTVChannel> Channels { get { return _Channels; } set { _Channels = value; } }
+        private List<IXMLTVProgram> _Programs;
+        public List<IXMLTVProgram> Programs { get { return _Programs; } set { _Programs = value; } }
+
+        private List<IExtraMetaData> _ExtraEntries;
+        public List<IExtraMetaData> 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; }
-
-        public IXMLTVSerializer<XMLTVRuntimeInstance> Serializer
-        {
-            get 
-            {
-                ///* 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); 
-            }
-        }
+        #endregion
+        #region ISerializer<XMLTVRuntimeInstance> members
+        public IXMLTVSerializer<XMLTVRuntimeInstance> Serializer { get { return new XMLTVSerializer<XMLTVRuntimeInstance>(this); } }
+        #endregion
+        #region IDestroyInstance member
         public void DestroyInstance()
         {
             xmltv_logger.Debug.WriteLine("Destoying Instance of: '{0}'", this.GetType().Name);
@@ -93,76 +109,56 @@
                 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);
+                    while (worker.IsAlive) { worker.Abort(); Application.DoEvents(); }
                 }
+                else { xmltv_logger.Debug.WriteLine("Instance of: '{0}'- already destroyed.", this.GetType().Name); }
             }
         }
-        private bool _IsAborting;
-        public bool IsAborting
-        {
-            get { return _IsAborting; }
-            private set { _IsAborting = value; }
-        }
+        #endregion
+        #region  IRuntimeInstanceLoader<XMLTVRuntimeInstance> member
         public XMLTVRuntimeInstance LoadFromInstance(XMLTVRuntimeInstance instance)
         {
             if (instance == null)
             {
                 throw new NullReferenceException("Failed to load from instance because the instance is null.");
             }
-            
-            if (instance.Source != null)
+            xmltv_logger.Debug.WriteLine("Loading from instance...");
+            CloneFromInstance(ref instance);            
+            xmltv_logger.Debug.WriteLine("Loaded from instance...");
+            if (this.Source != null)
             {
-                xmltv_logger.Debug.WriteLine("Loading from instance...");
-                xmltv_logger.Info.WriteLine("Source Loaded: '{0}' Created by '{1}' - original source file: '{2}'", instance.Source.SourceName, instance.Source.GeneratorName, instance.XmlFile.FullName);
+                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("The Instance's Source Property is null.");
-                throw new NullReferenceException("The Instance's Source Property is null.");
+                xmltv_logger.Error.WriteLine("Source Property is null.");
+                throw new NullReferenceException("Source Property is null.");
             }
-            if (instance.Channels != null)
+            if (this.Channels != null)
             {
-                xmltv_logger.Info.WriteLine("Source Loaded: '{0}' Channels from source '{1}'", instance.Channels.Count, instance.Source.SourceName);
+                xmltv_logger.Info.WriteLine("Source Loaded: '{0}' Channels from source '{1}'", this.Channels.Count, this.Source.SourceName);
             }
             else
             {
-                xmltv_logger.Error.WriteLine("The Instance's Channels Property is null.");
-                throw new NullReferenceException("The Instance's Channels Property is null.");
+                xmltv_logger.Error.WriteLine("Channels Property is null.");
+                throw new NullReferenceException("Channels Property is null.");
             }
-            if (instance.Programs != null)
+            if (this.Programs != null)
             {
-                xmltv_logger.Info.WriteLine("Source Loaded: '{0}' Programs from source '{1}", instance.Programs.Count, instance.Source.SourceName);
+                xmltv_logger.Info.WriteLine("Source Loaded: '{0}' Programs from source '{1}'", this.Programs.Count, this.Source.SourceName);
             }
             else
             {
-                xmltv_logger.Error.WriteLine("The Instance's Programs Property is null.");
-                throw new NullReferenceException("The Instance's Programs Property is null.");
-            }
-            CloneFromInstance(ref instance);
-            //if (OnInstanceCreated != null)
-            //{
-            //    OnInstanceCreated.Invoke(this, new EventArgs());
-            //}
+                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)
         {
-            //if (!instance.GetType().IsSerializable)
-            //{
-            //    throw new ArgumentException("Loaded instance is not serializable.", "instance");
-            //}
-            //if (Object.ReferenceEquals(instance, null))
-            //{
-            //    throw new NullReferenceException("Failed to load from instance because the instance is null.");
-            //}
+            xmltv_logger.Debug.WriteLine("Cloning from instance...");
             BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
             CultureInfo culture = CultureInfo.CurrentCulture;
             Type t = typeof(XMLTVRuntimeInstance);
@@ -170,15 +166,18 @@
             {
                 try
                 {
-                    if (field.IsNotSerialized)
+                    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;
                     }
-                    
-                    var f = instance.GetType().GetField(field.Name, flags);
-                    
-                    var v = f.GetValue(instance);
-                    field.SetValue(this, v);
                 }
                 catch (Exception ex)
                 {
@@ -189,13 +188,8 @@
             {
                 try
                 {
-                    //if (property.Attributes.HasFlag(FieldAttributes.NotSerialized))
-                    //{
-                    //    continue;
-                    //}
                     var f = instance.GetType().GetProperty(property.Name);
                     object value = null;
-
                     try
                     {
                         value = f.GetValue(instance, null);
@@ -203,7 +197,15 @@
                     catch (ArgumentException ex) { if (ex.Message == "Property get method not found.") { Debug.WriteLine(ex.ToString()); } else { throw ex; } }
                     try
                     {
-                        property.SetValue(this, value, null);
+                        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; } }
 
@@ -213,31 +215,241 @@
                     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 void CreateLoader(string xml_file, XMLTVRuntimeInstance instance)
+        private XMLTVRuntimeInstance gInstance;
+        public XMLTVRuntimeInstance GetInstance() { return gInstance; }
+        public XMLTVInstance(string xmlfile) 
         {
-            //XMLTVLoader loader = new XMLTVLoader(xml_file, instance);
-            XMLTVLoader.CreateInstance(xml_file, instance);
+            try
+            {
+                CreateLoader(xmlfile);
+                CreateParser();
+            }
+            catch (ThreadAbortException ex) { Debug.WriteLine(ex.ToString()); }
+            catch (Exception ex)
+            {
+                xmltv_logger.Error.WriteLine(ex.ToString());
+            }
         }
-        private void CreateParser(XMLTVRuntimeInstance instance)
+
+        private void CreateLoader(string xml_file)
         {
-            //XMLTVParser parser = new XMLTVParser(instance);
-            XMLTVParser.CreateInstance(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()
+        {
+            var doc = XDocument.Parse(this.GetInstance().XmlDoc);
+            var root_element = doc.Root;            
+            CreateHandlerForRootNode(root_element);
+            var nodes = doc.Root.Elements().ToList();
 
-        public void Dispose()
+            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 Enterprise.Logging.ReportProgressEventArgs((int)progress));
+                Application.DoEvents();
+            }
+        }
+
+
+        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; } }
+                            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;
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            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);
+        }
+
+        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; } }
+                            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)
+                                {
+                                    handler_type = type;
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            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);                
+            }
+            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);
+                }
+            }
+        }
+        #endregion
+        
     }
 }

 

  ViewVC Help
Powered by ViewVC 1.1.22