--- trunk/libxmltv/Core/XMLTVInstance.cs 2013/03/08 02:13:59 36 +++ trunk/libxmltv/Core/XMLTVRuntimeInstance.cs 2013/03/09 09:29:40 72 @@ -3,41 +3,279 @@ using System.Linq; 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; namespace libxmltv.Core { - internal class XMLTVRuntimeInstance : MarshalByRefObject, IXMLTVRuntimeInstance + [Serializable] + internal class XMLTVRuntimeInstance : MarshalByRefObject, + IXMLTVRuntimeInstance, + ISerializer, + IGetCreatedInstanceEvent, + ISetCreatedInstanceEvent, + IDestroyInstance, + IRuntimeInstanceLoader { - public XMLTVRuntimeInstance(string xmlfile) { CreateInstance(xmlfile); } - private void CreateInstance(string xmlfile) { Instance = new XMLTVInstance(xmlfile, this); } - internal XMLTVInstance Instance { get; private set; } - - #region IXMLTV_LOADER members - public System.IO.FileInfo XmlFile { get; set; } - public System.Xml.Linq.XDocument XmlDoc { get; set; } - #endregion - #region IXMLTV_PARSER Members - public IXMLTVSource Source { get; set; } - public Dictionary Channels { get; set; } - public Dictionary Programs { get; set; } - #endregion + [NonSerialized] + Thread worker; + public XMLTVRuntimeInstance() { init(); } + public XMLTVRuntimeInstance(string xmlfile) : this(xmlfile, null) { } + public XMLTVRuntimeInstance(string xmlfile, EventHandler handler) + : 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); } + } + + private void init() + { + this.Source = new XMLTVSource(); + this.Channels = new Dictionary(); + this.Programs = new Dictionary(); + this.XmlFile_Name = string.Empty; + this.XmlFile_FullName = string.Empty; + this.XmlDoc = string.Empty; + this.OnInstanceCreated = null; + } + + #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 Dictionary _Channels; + public Dictionary Channels { get { return _Channels; } set { _Channels = value; } } + private Dictionary _Programs; + public Dictionary Programs { get { return _Programs; } set { _Programs = value; } } + #endregion + #region IOnInstanceCreated members + [NonSerialized] + private EventHandler _OnInstanceCreated; + public EventHandler OnInstanceCreated { get { return _OnInstanceCreated; } set { _OnInstanceCreated = value; } } + #endregion + #region IGetCreatedInstanceEvent members + public EventHandler GetOnInstanceCreated() { return OnInstanceCreated; } + #endregion + #region ISetCreatedInstanceEvent members + public void SetOnInstanceCreated(EventHandler event_instance) { OnInstanceCreated = event_instance; } + #endregion + #region ISerializer members + public IXMLTVSerializer Serializer { get { return new XMLTVSerializer(this); } } + #endregion + #region IDestroyInstance member + public void DestroyInstance() + { + xmltv_logger.Debug.WriteLine("Destoying Instance of: '{0}'", this.GetType().Name); + this.IsAborting = true; + if (worker == null) + { + 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); } + } + } + #endregion + #region IRuntimeInstanceLoader member + public XMLTVRuntimeInstance LoadFromInstance(XMLTVRuntimeInstance instance) + { + if (instance == null) + { + throw new NullReferenceException("Failed to load from instance because the instance is null."); + } + CloneFromInstance(ref instance); + xmltv_logger.Debug.WriteLine("Loading from instance..."); + if (this.Source != null) + { + 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."); + } + xmltv_logger.Debug.WriteLine("Loaded from instance..."); + 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 + internal class XMLTVInstance : IGetInstance, IDisposable { - public XMLTVInstance(string xmlfile, XMLTVRuntimeInstance instance) - { - CreateLoader(xmlfile, instance); - CreateParser(instance); + private XMLTVRuntimeInstance gInstance; + public XMLTVRuntimeInstance GetInstance() { return gInstance; } + public XMLTVInstance(string xmlfile) + { + try + { + CreateLoader(xmlfile); + } + 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); + gInstance = new XMLTVRuntimeInstance(); + bool bound_to_ctor = false; + object raw_instance = null; + Assembly asm = Assembly.GetExecutingAssembly(); + var types = asm.GetTypes(); + + foreach (var type in types) + { + if (type.BaseType != null && type.BaseType == typeof(XMLTVBase)) + { + xmltv_logger.Verbose.Debug.WriteLine("Type: '{0}' Base: '{1}'", type.Name, type.BaseType == null ? "none" : type.BaseType.Name); + + BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; + CultureInfo culture = CultureInfo.CurrentCulture; + object[] args = new object[] { xml_file, gInstance }; + try + { + raw_instance = Activator.CreateInstance(type, flags, null, args, culture); + bound_to_ctor = true; + } + catch (Exception ex) + { + Debug.WriteLine(ex.ToString()); + } + } + } + if (!bound_to_ctor) { throw new Exception("Unable to find a compatible XMLTV Data Loader."); } + if (raw_instance == null) { throw new NullReferenceException("Found a compatible XMLTV Data Loader, but it returned invalid data."); } + IGetInstance getter_instance = (raw_instance as IGetInstance); + 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) { - XMLTVParser parser = new XMLTVParser(instance); + } + + public void Dispose() + { + //throw new NotImplementedException(); + } + + } }