--- trunk/libxmltv/Core/XMLTVProgram.cs 2013/03/09 10:27:39 73 +++ trunk/libxmltv/Core/XMLTVProgram.cs 2013/03/09 13:51:58 86 @@ -3,34 +3,256 @@ using System.Linq; using System.Text; using libxmltv.Interfaces; +using System.Xml.Linq; +using System.Reflection; +using System.IO; +using System.Diagnostics; +using System.Globalization; namespace libxmltv.Core { [Serializable] - internal class XMLTVProgram : IXMLTVProgram + internal class XMLTVProgram : XMLTVBase, IXMLTVProgram { - public XMLTVProgram() + public XMLTVProgram() : base(null,XMLTVConstants.PROGRAM_ELEMENT) { - Id = 0; - Start = new DateTime(); - Stop = new DateTime(); - Channel = new XMLTVChannel(); - Title = string.Empty; - SubTitle = string.Empty; - Description = string.Empty; + InternalDictionaryAddKnownProperties(); + + } + public XMLTVProgram(XMLTVRuntimeInstance instance, XElement node) + : base(instance, XMLTVConstants.PROGRAM_ELEMENT) + { + InternalDictionaryAddKnownProperties(); + try { + xmltv_logger.Verbose.Debug.WriteLine("Creating Instance of XMLTVProgram"); + Create(node); + xmltv_logger.Verbose.Debug.WriteLine("Created Instance of XMLTVProgram"); + UpdateInstance(); + } + catch (IOException ex) { Debug.WriteLine(ex.ToString()); } } #region IXMLTVProgram members - public int Id { get; set; } - public DateTime Start { get; set; } - public DateTime Stop { get; set; } - public IXMLTVChannel Channel { get; set; } - public string Title { get; set; } - public string SubTitle { get; set; } - public string Description { get; set; } + //public int Id { get; set; } + //public DateTime Start { get; set; } + //public DateTime Stop { get; set; } + //public IXMLTVChannel Channel { get; set; } + //public string Title { get; set; } + //public string SubTitle { get; set; } + //public string Description { get; set; } + + private void InternalDictionaryAddKnownProperties() + { + Properties = new Dictionary(); + Properties.Add("Id", 0); + Properties.Add(XMLTVConstants.Programs.ProgramStart, new DateTime()); + Properties.Add(XMLTVConstants.Programs.ProgramStop, new DateTime()); + Properties.Add(XMLTVConstants.Programs.ProgramChannelId, string.Empty); + Properties.Add(XMLTVConstants.Programs.ProgramTitle, string.Empty); + Properties.Add(XMLTVConstants.Programs.ProgramSubTitle, string.Empty); + Properties.Add(XMLTVConstants.Programs.ProgramDescription, string.Empty); + } + + public Dictionary Properties { get; private set; } + + private void InternalDictionaryTestOrThrow() + { + if (Properties == null) { throw new NullReferenceException("Properties collection has not been initialized."); } + if (Properties.Count == 0) { throw new IndexOutOfRangeException("Properties collection has 0 elements."); } + } + private void InternalProperyExistsOrThrow(string name) + { + InternalDictionaryTestOrThrow(); + if (!Properties.ContainsKey(name)) { throw new KeyNotFoundException(string.Format("Property '{0}' does not exist", name)); } + } + public object GetProperty(string name) + { + InternalProperyExistsOrThrow(name); + return Properties[name]; + } + public void SetProperty(string name, object value) + { + InternalProperyExistsOrThrow(name); + Properties[name] = value; + } #endregion public override string ToString() { - return string.Format("{0}: {1} - {2} ({3}) ['{4}' <==> '{5}']", Id, Title, SubTitle, Channel.ToString(), Start.ToString("yyyy/MM/dd hh:mm tt"), Stop.ToString("yyyy/MM/dd hh:mm tt")); + return string.Format("{0}: {1} - {2} ({3}) ['{4}' <==> '{5}']", + GetProperty("Id").ToString(), + GetProperty(XMLTVConstants.Programs.ProgramTitle).ToString(), + GetProperty(XMLTVConstants.Programs.ProgramSubTitle), ToString(), + GetProperty(XMLTVConstants.Programs.ProgramChannelId).ToString(), + ((DateTime)GetProperty(XMLTVConstants.Programs.ProgramStart)).ToString("yyyy/MM/dd hh:mm tt"), + ((DateTime)GetProperty(XMLTVConstants.Programs.ProgramStop)).ToString("yyyy/MM/dd hh:mm tt")); + } + + + + + private void UpdateInstance() + { + bool found_field = false; + var instance_type = this.GetInstance().GetType(); + var fields = instance_type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance); + foreach (var field in fields) + { + if (field.FieldType == typeof(List)) + { + found_field = true; + try + { + + var list = (List)field.GetValue(this.GetInstance()); + this.SetProperty("Id", list.Count + 1); + list.Add(this); + xmltv_logger.Verbose.Debug.WriteLine("Updating instance with program information: {0}", this.ToString()); + field.SetValue(this.GetInstance(), list); + break; + } + catch (Exception ex) + { + xmltv_logger.Verbose.Error.WriteLine("Unable to update instance with program information."); + xmltv_logger.Verbose.Error.WriteLine(ex.ToString()); + } + } + } + if (!found_field) + { + xmltv_logger.Verbose.Error.WriteLine("Unable to update instance with program information."); + } } + + private void Create(XElement node) + { + //if (node.HasAttributes) + //{ + // var start = node.Attribute(XMLTVConstants.Programs.ProgramStart); + // this.Start = start == null ? new DateTime() : ParseDate(start.Value); + // if (!this.Start.Equals(new DateTime())) { xmltv_logger.Verbose.Debug.WriteLine("\tprogram_start: {0}", start); } + + // var stop = node.Attribute(XMLTVConstants.Programs.ProgramStop); + // this.Stop = stop == null ? new DateTime() : ParseDate(stop.Value); + // if (!this.Stop.Equals(new DateTime())) { xmltv_logger.Verbose.Debug.WriteLine("\tprogram_stop: {0}", stop); } + + // var channelid = node.Attribute(XMLTVConstants.Programs.ProgramChannelId); + // if (!string.IsNullOrEmpty(this.Description)) { xmltv_logger.Verbose.Debug.WriteLine("\tprogram_channelid: {0}", channelid); } + // IXMLTVChannel channel = new XMLTVChannel(); + // string _channelid = channelid == null ? string.Empty : channelid.Value; + // this.Channel = this.GetInstance().Channels.Find(m => m.Id == _channelid); + // if (this.Channel == null) { this.Channel = new XMLTVChannel(); } + // if (!string.IsNullOrEmpty(_channelid)) { xmltv_logger.Verbose.Debug.WriteLine("\tprogram_channel: {0}", this.Channel.ToString()); } //} + //try + //{ + // var title = node.Descendants(XMLTVConstants.Programs.ProgramTitle).FirstOrDefault(); + // this.Title = title == null ? string.Empty : title.Value; + //} + //catch (Exception) { this.Title = string.Empty; } + //if (!string.IsNullOrEmpty(this.Title)) { xmltv_logger.Verbose.Debug.WriteLine("\tprogram_title: {0}", this.Title == string.Empty ? "empty" : this.Title); } + //try + //{ + // var subtitle = node.Descendants(XMLTVConstants.Programs.ProgramSubTitle).FirstOrDefault(); + // this.SubTitle = subtitle == null ? string.Empty : subtitle.Value; + //} + //catch (Exception) { this.SubTitle = string.Empty; } + //if (!string.IsNullOrEmpty(this.SubTitle)) { xmltv_logger.Verbose.Debug.WriteLine("\tprogram_subtitle: {0}", this.SubTitle == string.Empty ? "empty" : this.SubTitle); } + //try + //{ + // var description = node.Descendants(XMLTVConstants.Programs.ProgramDescription).FirstOrDefault(); + // this.Description = description == null ? string.Empty : description.Value; ; + //} + //catch (Exception) { this.Description = string.Empty; } + //if (!string.IsNullOrEmpty(this.Description)) { xmltv_logger.Verbose.Debug.WriteLine("\tprogram_description: {0}", this.Description == string.Empty ? "empty" : this.Description); } + + //ParseExtraData(node); + + var nodes = node.Elements().ToList(); + foreach (var sub_node in nodes) + { + if (this.GetInstance().IsAborting) + { + break; + } + CreateHandlerForProgramMetaDataNode(sub_node); + } + } + private DateTime ParseDate(string timeStamp) + { + DateTime dt = new DateTime(); + try + { + dt = DateTime.ParseExact(timeStamp, "yyyyMMddHHmmss zzzz", System.Globalization.CultureInfo.CurrentCulture); + } + catch (Exception ex) { throw ex; } + return dt; + } + + private void CreateHandlerForProgramMetaDataNode(XElement node) + { + Type t = this.GetType(); + Assembly asm = t.Assembly; + var types = asm.GetTypes(); + var classes = types.ToList().FindAll( + m => + m.DeclaringType == t && + m.IsClass && + !m.IsSealed + ); + classes.TrimExcess(); + + object raw_instance = null; + BindingFlags flags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance; + CultureInfo culture = CultureInfo.CurrentCulture; + Type handler_type = null; + foreach (var type in classes) + { + if (type.BaseType != null && type.BaseType == typeof(XMLTVBase)) + { + 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.ToString()) + { + handler_type = type; + break; + } + } + } + } + } + } + if (handler_type == 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[] { ' ' })); + xmltv_logger.Verbose.Warn.WriteLine("Ignoring unhandled extra meta-data: {0}", node_text); + } + raw_instance = Activator.CreateInstance(handler_type, flags, null, new object[] { this, node }, culture); + } + + + + #region sub-classes + private class title : XMLTVBase + { + public title() : base(null, XMLTVConstants.Programs.ProgramTitle) { } + public title(XMLTVProgram instance, XElement node) + : base(instance, XMLTVConstants.Programs.ProgramTitle) + { + } + } + #endregion } }