/// <summary>
        /// Retrieves an RSS feed using the given Url, parses it and
        /// creates and new <see cref="RssFeed">RssFeed</see> object with the information.
        /// If an error occurs in the XML loading of the document, or parsing of
        /// the RSS feed, the error is trapped and stored inside the RssFeed's
        /// ErrorMessage property.
        /// </summary>
        /// <param name="Url">The url to retrieve the RSS feed from, this can
        /// be in the format of http:// and also file://.. (ftp?)</param>
        /// <returns>An <see cref="RssFeed">RssFeed</see> object with information
        /// retrieved from the feed.</returns>
        public RssFeed Retrieve(string Url)
        {
            RssFeed rssFeed = new RssFeed();
            rssFeed.Items = new RssItems();

            XmlTextReader xmlTextReader = new XmlTextReader(Url);
            XmlValidatingReader xmlValidatingReader = new XmlValidatingReader(xmlTextReader);
            xmlValidatingReader.ValidationType = ValidationType.None;

            XmlDocument xmlDoc= new XmlDocument();

            try
            {
                xmlDoc.Load(xmlTextReader);

                // Fire the load event
                if ( this.FeedLoaded != null )
                {
                    this.FeedLoaded(this, new EventArgs());
                }

                XmlNode rssXmlNode = null;

                // Loop child nodes till we find the rss one
                for (int i=0;i < xmlDoc.ChildNodes.Count;i++)
                {
                    System.Diagnostics.Debug.Write("Child: " +xmlDoc.ChildNodes[i].Name);
                    System.Diagnostics.Debug.WriteLine(" has " +xmlDoc.ChildNodes[i].ChildNodes.Count+" children");

                    if ( xmlDoc.ChildNodes[i].Name == this.rootNodeName && xmlDoc.ChildNodes[i].ChildNodes.Count > 0 )
                    {
                        rssXmlNode = xmlDoc.ChildNodes[i];

                        // Fire the found event
                        if ( this.RssNodeFound != null )
                        {
                            this.RssNodeFound(this,new EventArgs());
                        }

                        break;
                    }
                }

                if ( rssXmlNode != null )
                {
                    XmlNode channelXmlNode = null;

                    // Loop through the rss node till we find the channel
                    for (int i=0;i < rssXmlNode.ChildNodes.Count;i++)
                    {
                        System.Diagnostics.Debug.WriteLine("Rss child: "+rssXmlNode.ChildNodes[i].Name);
                        if ( rssXmlNode.ChildNodes[i].Name == this.channelNodeName && rssXmlNode.ChildNodes[i].ChildNodes.Count > 0 )
                        {
                            channelXmlNode = rssXmlNode.ChildNodes[i];

                            // Fire the found event
                            if ( this.ChannelNodeFound != null )
                            {
                                this.ChannelNodeFound(this,new EventArgs());
                            }

                            break;
                        }
                    }

                    // Found the channel node
                    if ( channelXmlNode != null )
                    {
                        // Loop through its children, copying details to the
                        // RssFeed struct, and parsing the items
                        for (int i=0;i < channelXmlNode.ChildNodes.Count;i++)
                        {
                            System.Diagnostics.Debug.WriteLine(channelXmlNode.ChildNodes[i].Name);
                            switch ( channelXmlNode.ChildNodes[i].Name )
                            {
                                case "title":
                                    {
                                        rssFeed.Title = channelXmlNode.ChildNodes[i].InnerText;
                                        break;
                                    }
                                case "description":
                                    {
                                        rssFeed.Description = channelXmlNode.ChildNodes[i].InnerText;
                                        break;
                                    }
                                case "language":
                                    {
                                        rssFeed.Language = channelXmlNode.ChildNodes[i].InnerText;
                                        break;
                                    }
                                case "copyright":
                                    {
                                        rssFeed.Copyright = channelXmlNode.ChildNodes[i].InnerText;
                                        break;
                                    }
                                case "webmaster":
                                    {
                                        rssFeed.Webmaster = channelXmlNode.ChildNodes[i].InnerText;
                                        break;
                                    }
                                case "pubDate":
                                    {
                                        rssFeed.PubDate = channelXmlNode.ChildNodes[i].InnerText;
                                        break;
                                    }
                                case "lastBuildDate":
                                    {
                                        rssFeed.LastBuildDate = channelXmlNode.ChildNodes[i].InnerText;
                                        break;
                                    }
                                case "category":
                                    {
                                        rssFeed.Category = channelXmlNode.ChildNodes[i].InnerText;
                                        break;
                                    }
                                case "generator":
                                    {
                                        rssFeed.Generator = channelXmlNode.ChildNodes[i].InnerText;
                                        break;
                                    }
                                case "ttl":
                                    {
                                        rssFeed.Ttl = channelXmlNode.ChildNodes[i].InnerText;
                                        break;
                                    }
                                case "rating":
                                    {
                                        rssFeed.Rating = channelXmlNode.ChildNodes[i].InnerText;
                                        break;
                                    }
                                case "skipHours":
                                    {
                                        rssFeed.Skiphours = channelXmlNode.ChildNodes[i].InnerText;
                                        break;
                                    }
                                case "skipDays":
                                    {
                                        rssFeed.Skipdays = channelXmlNode.ChildNodes[i].InnerText;
                                        break;
                                    }
                                case "managingEditor":
                                    {
                                        rssFeed.ManagingEditor = channelXmlNode.ChildNodes[i].InnerText;
                                        break;
                                    }
                                case "item":
                                    {
                                        rssFeed.Items.Add( this.getRssItem(channelXmlNode.ChildNodes[i]) );

                                        // Fire the found event
                                        if ( this.ItemAdded != null )
                                        {
                                            this.ItemAdded(this,new EventArgs());
                                        }

                                        break;
                                    }
                            }

                        }

                        // If rdf mode is set, then the channel node only contains
                        // information about the channel, it doesn't hold the item
                        // nodes. The item nodes are children of the root node in
                        // an RDF document, so we use this instead.
                        if ( this.RdfMode )
                        {
                            for (int i=0;i < rssXmlNode.ChildNodes.Count;i++)
                            {
                                switch ( rssXmlNode.ChildNodes[i].Name )
                                {
                                    case "item":
                                        {
                                            rssFeed.Items.Add( this.getRssItem(rssXmlNode.ChildNodes[i]) );

                                            // Fire the found event
                                            if ( this.ItemAdded != null )
                                            {
                                                this.ItemAdded(this,new EventArgs());
                                            }

                                            break;
                                        }
                                }
                            }
                        }
                    }
                    else
                    {
                        rssFeed.ErrorMessage = "Unable to find rss <seehannel> node";

                        // Fire the error event
                        if ( this.Error != null )
                        {
                            RssReaderErrorEventArgs args = new RssReaderErrorEventArgs();
                            args.Message = rssFeed.ErrorMessage;
                            this.Error(this,args);
                        }
                    }

                }
                else
                {
                    rssFeed.ErrorMessage = "Unable to find root <rss> node";

                    // Fire the error event
                    if ( this.Error != null )
                    {
                        RssReaderErrorEventArgs args = new RssReaderErrorEventArgs();
                        args.Message = rssFeed.ErrorMessage;
                        this.Error(this,args);
                    }
                }

            }
            catch (XmlException err)
            {
                //
                rssFeed.ErrorMessage = "Xml error: " +err.Message;

                // Fire the error event
                if ( this.Error != null )
                {
                    RssReaderErrorEventArgs args = new RssReaderErrorEventArgs();
                    args.Message = rssFeed.ErrorMessage;
                    this.Error(this,args);
                }
                return rssFeed;
            }

            return rssFeed;
        }
 /// <summary>
 /// A simplified method of creating a HTML (or any document) from an
 /// RSS Feed. See <see cref="RssHtmlMaker">RssHtmlMaker</see>
 /// </summary>
 /// <param name="Feed">The <see cref="RssFeed">RssFeed</see> object to
 /// get the tokens' data from.</param>
 /// <param name="Template">The overall HTML template (or any other format)
 /// to replace the tokens in.</param>
 /// <param name="ItemPrefix">A string template that is prepended to the beginning
 /// of each RSS item.</param>
 /// <param name="ItemSuffix">A string template that is apppended to the end
 /// of each RSS item.</param>
 /// <returns>A string with the templates provided parsed of their tokens, with
 /// the data values in their place.</returns>
 public static string CreateHtml(RssFeed Feed,string Template,string ItemPrefix,string ItemSuffix)
 {
     return new RssHtmlMaker().GetHtmlContents(Feed,Template,ItemPrefix,ItemSuffix);
 }
 /// <summary>
 /// A simplified method of creating a HTML (or any document) from an
 /// RSS Feed. See <see cref="RssHtmlMaker">RssHtmlMaker</see>
 /// </summary>
 /// <param name="Feed">The <see cref="RssFeed">RssFeed</see> object to
 /// get the tokens' data from.</param>
 /// <param name="Template">The overall HTML template (or any other format)
 /// to replace the tokens in.</param>
 /// <param name="ItemPrefix">A string template that is prepended to the beginning
 /// of each RSS item.</param>
 /// <param name="ItemSuffix">A string template that is apppended to the end
 /// of each RSS item.</param>
 /// <param name="MaxItems">The maximum number of RSS items to display.</param>
 /// <returns>A string with the templates provided parsed of their tokens, with
 /// the data values in their place.</returns>
 public static string CreateHtml(RssFeed Feed,string Template,string ItemPrefix,string ItemSuffix,int MaxItems)
 {
     RssHtmlMaker rssHtmlMaker = new RssHtmlMaker();
     rssHtmlMaker.MaxItems = MaxItems;
     return rssHtmlMaker.GetHtmlContents(Feed,Template,ItemPrefix,ItemSuffix);
 }
        /// <summary>
        /// Creates a HTML document, or any format - this is only limited by
        /// the template you provide - from the provided
        /// <see cref="RssFeed">RssFeed</see> object. The tokens described in the
        /// remarks section are replaced with their values inside the template.
        /// The items in the RSS feed are replaced using the ItemPrefix and ItemSuffix
        /// templates, where the suffix is placed face, and the suffix is appended on the end.
        /// </summary>
        /// <remarks>
        /// The following are a list of tokens which are replaced inside the main Template,
        /// with their corresponding values from the provided <see cref="RssFeed">RssFeed</see> 
        /// object. For details on each token, see its corresponding property in the 
        /// <see cref="RssFeed">RssFeed</see> object.
        /// <list type="bullet">
        /// <item>%Title%</item>
        /// <item>%Description%</item>
        /// <item>%Link%</item>
        /// <item>%Language%</item>
        /// <item>%Copyright%</item>
        /// <item>%Webmaster%</item>
        /// <item>%PubDate%</item>
        /// <item>%LastBuildDate%</item>
        /// <item>%Category%</item>
        /// <item>%Generator%</item>
        /// <item>%Ttl%</item>
        /// <item>%Rating%</item>
        /// <item>%Skiphours%</item>
        /// <item>%Skipdays%</item>
        /// <item>%Skipdays%</item>
        /// <item>%Items% - This is replaced by the parsed template of the items</item>
        /// </list>
        /// The following are a list of tokens which are replaced inside the ItemPrefix
        /// and ItemSuffix templates, with their corresponding values from the 
        /// provided <see cref="RssItem">RssItem</see> object. For details
        /// on each token, see its corresponding property in 
        /// the <see cref="RssItem">RssItem</see> object.
        /// <list type="bullet">
        /// <item>%Title%</item>
        /// <item>%Description%</item>
        /// <item>%Link%</item>
        /// <item>%Author%</item>
        /// <item>%Comments%</item>
        /// <item>%Pubdate%</item>
        /// <item>%Guid%</item>
        /// </list>
        /// </remarks>
        /// <param name="Feed">The <see cref="RssFeed">RssFeed</see> object to
        /// get the tokens' data from.</param>
        /// <param name="Template">The overall HTML template (or any other format)
        /// to replace the tokens in.</param>
        /// <param name="ItemPrefix">A string template that is prepended to the beginning
        /// of each RSS item.</param>
        /// <param name="ItemSuffix">A string template that is apppended to the end
        /// of each RSS item.</param>
        /// <returns>A string with the templates provided parsed of their tokens, with
        /// the data values in their place.</returns>
        public string GetHtmlContents(RssFeed Feed,string Template,string ItemPrefix,string ItemSuffix)
        {
            string result = Template;

            // Replace all template tokens
            result = result.Replace("%Title%",Feed.Title);
            result = result.Replace("%Description%",Feed.Description);
            result = result.Replace("%Link%",Feed.Link);
            result = result.Replace("%Language%",Feed.Language);
            result = result.Replace("%Copyright%",Feed.Copyright);
            result = result.Replace("%Webmaster%",Feed.Webmaster);
            result = result.Replace("%PubDate%",Feed.PubDate);
            result = result.Replace("%LastBuildDate%",Feed.LastBuildDate);
            result = result.Replace("%Category%",Feed.Category);
            result = result.Replace("%Generator%",Feed.Generator);
            result = result.Replace("%Ttl%",Feed.Ttl);
            result = result.Replace("%Rating%",Feed.Rating);
            result = result.Replace("%Skiphours%",Feed.Skiphours);
            result = result.Replace("%Skipdays%",Feed.Skipdays);
            result = result.Replace("%Skipdays%",Feed.ManagingEditor);

            // Parse item template
            string itemsContent = "";
            string tempContent = "";

            if ( maxItems == 0 || maxItems > Feed.Items.Count )
            {
                maxItems = Feed.Items.Count;
            }

            for (int i=0;i < maxItems;i++)
            {
                // Parse prefix template
                tempContent  = ItemPrefix;
                tempContent  = tempContent.Replace("%Title%",Feed.Items[i].Title);
                tempContent  = tempContent.Replace("%Description%",Feed.Items[i].Description);
                tempContent  = tempContent.Replace("%Link%",Feed.Items[i].Link);
                tempContent  = tempContent.Replace("%Author%",Feed.Items[i].Author);
                tempContent  = tempContent.Replace("%Comments%",Feed.Items[i].Comments);
                tempContent  = tempContent.Replace("%Pubdate%",Feed.Items[i].Pubdate);
                tempContent  = tempContent.Replace("%Guid%",Feed.Items[i].Guid);

                itemsContent += tempContent;

                // Parse suffix template
                tempContent  = ItemSuffix;
                tempContent  = tempContent.Replace("%Title%",Feed.Items[i].Title);
                tempContent  = tempContent.Replace("%Description%",Feed.Items[i].Description);
                tempContent  = tempContent.Replace("%Link%",Feed.Items[i].Link);
                tempContent  = tempContent.Replace("%Author%",Feed.Items[i].Author);
                tempContent  = tempContent.Replace("%Comments%",Feed.Items[i].Comments);
                tempContent  = tempContent.Replace("%Pubdate%",Feed.Items[i].Pubdate);
                tempContent  = tempContent.Replace("%Guid%",Feed.Items[i].Guid);

                itemsContent += tempContent;
            }

            // Replace %items% with items
            result = result.Replace("%Items%",itemsContent);

            return result;
        }