private string getEventCategory(string title, string description, EventInformationTableEntry eventEntry)
        {
            if (RunParameters.Instance.Options.Contains("CUSTOMCATEGORYOVERRIDE"))
            {
                string customCategory = getCustomCategory(title, description);
                if (customCategory != null)
                {
                    return(customCategory);
                }
            }

            string category = AtscPsipProgramCategory.GetCategories(eventEntry);

            if (category != null)
            {
                return(category);
            }

            if (RunParameters.Instance.Options.Contains("CUSTOMCATEGORYOVERRIDE"))
            {
                return(null);
            }

            return(getCustomCategory(title, description));
        }
        /// <summary>
        /// Add an undefined category to the collection of undefined categories.
        /// </summary>
        /// <param name="number">The category ID.</param>
        /// <param name="description">The category description.</param>
        public static void AddUndefinedCategory(int number, string description)
        {
            if (undefinedCategories == null)
            {
                undefinedCategories = new Collection <AtscPsipProgramCategory>();
            }

            foreach (AtscPsipProgramCategory category in undefinedCategories)
            {
                if (category.number == number)
                {
                    return;
                }

                if (category.number > number)
                {
                    AtscPsipProgramCategory insertCategory = new AtscPsipProgramCategory(number, description);
                    insertCategory.usedCount = 1;
                    undefinedCategories.Insert(undefinedCategories.IndexOf(category), insertCategory);
                    return;
                }
            }

            AtscPsipProgramCategory addCategory = new AtscPsipProgramCategory(number, description);

            addCategory.usedCount = 1;
            undefinedCategories.Add(addCategory);
        }
        /// <summary>
        /// Get a list of the categories for an event.
        /// </summary>
        /// <param name="eventEntry">The event to be processed.</param>
        /// <returns>A list of comma separated categories or null if none exist.</returns>
        public static string GetCategories(EventInformationTableEntry eventEntry)
        {
            if (eventEntry.Descriptors == null)
            {
                return(null);
            }

            StringBuilder categoryString = new StringBuilder();

            foreach (DescriptorBase descriptorBase in eventEntry.Descriptors)
            {
                GenreDescriptor genreDescriptor = descriptorBase as GenreDescriptor;
                if (genreDescriptor != null)
                {
                    if (genreDescriptor.Attributes != null)
                    {
                        foreach (GenreAttribute genreAttribute in genreDescriptor.Attributes)
                        {
                            AtscPsipProgramCategory category = FindCategory(genreAttribute.Attribute);
                            if (category != null)
                            {
                                if (categoryString.Length != 0)
                                {
                                    categoryString.Append(",");
                                }
                                categoryString.Append(category.Description);

                                if (category.SampleEvent == null)
                                {
                                    category.SampleEvent = eventEntry.EventName.ToString();
                                }
                                category.UsedCount++;
                            }
                            else
                            {
                                AtscPsipProgramCategory.AddUndefinedCategory(genreAttribute.Attribute, eventEntry.EventName.ToString());
                            }
                        }
                    }
                }
            }

            if (categoryString.Length != 0)
            {
                return(categoryString.ToString());
            }
            else
            {
                return(null);
            }
        }
        /// <summary>
        /// Acquire and process ATSC PSIP Info data.
        /// </summary>
        /// <param name="dataProvider">A sample data provider.</param>
        /// <param name="worker">The background worker that is running this collection.</param>
        /// <returns>A CollectorReply code.</returns>
        public override CollectorReply Process(ISampleDataProvider dataProvider, BackgroundWorker worker)
        {
            AtscPsipProgramCategory.Load();
            CustomProgramCategory.Load();

            bool referenceTablesLoaded = MultiTreeDictionaryEntry.Load(Path.Combine(RunParameters.ConfigDirectory, "Huffman Dictionary ATSC PSIP T1.cfg"), Path.Combine(RunParameters.ConfigDirectory, "Huffman Dictionary ATSC PSIP T2.cfg"));

            if (!referenceTablesLoaded)
            {
                return(CollectorReply.ReferenceDataError);
            }

            getMasterGuideData(dataProvider, worker);
            if (worker.CancellationPending)
            {
                return(CollectorReply.Cancelled);
            }

            getVirtualChannelData(dataProvider, worker);
            if (worker.CancellationPending)
            {
                return(CollectorReply.Cancelled);
            }

            /*getRatingRegionData(dataProvider, worker);
             * if (worker.CancellationPending)
             *  return (CollectorReply.Cancelled);*/

            getExtendedTextData(dataProvider, worker);
            if (worker.CancellationPending)
            {
                return(CollectorReply.Cancelled);
            }

            getEventInformationData(dataProvider, worker);
            if (worker.CancellationPending)
            {
                return(CollectorReply.Cancelled);
            }

            OutputFile.UseUnicodeEncoding = MultipleString.UseUnicodeEncoding;

            return(CollectorReply.OK);
        }
        /// <summary>
        /// Create the EPG entries.
        /// </summary>
        public override void FinishFrequency()
        {
            if (RunParameters.Instance.DebugIDs.Contains("LOGPSIPEXTENDEDTEXT"))
            {
                ExtendedTextTable.LogEntries();
            }

            AtscPsipProgramCategory.LogCategoryUsage();

            if (VirtualChannelTable.Channels.Count == 0)
            {
                return;
            }

            Logger titleLogger       = null;
            Logger descriptionLogger = null;

            if (RunParameters.Instance.DebugIDs.Contains("LOGTITLES"))
            {
                titleLogger = new Logger("EPG Titles.log");
            }
            if (RunParameters.Instance.DebugIDs.Contains("LOGDESCRIPTIONS"))
            {
                descriptionLogger = new Logger("EPG Descriptions.log");
            }

            foreach (VirtualChannel channel in VirtualChannelTable.Channels)
            {
                TVStation station = TVStation.FindStation(channel.CollectionFrequency, channel.MajorChannelNumber, channel.MinorChannelNumber);
                if (station == null)
                {
                    station = new TVStation(channel.ShortName);
                    station.OriginalNetworkID = channel.CollectionFrequency;
                    station.TransportStreamID = channel.MajorChannelNumber;
                    station.ServiceID         = channel.MinorChannelNumber;
                    station.ChannelID         = channel.MajorChannelNumber + ":" + channel.MinorChannelNumber + ":" + channel.ShortName;
                    TVStation.AddStation(station);
                }

                station.Name = channel.ShortName;

                if (station.LogicalChannelNumber == -1)
                {
                    station.LogicalChannelNumber = (channel.MajorChannelNumber * 100) + channel.MinorChannelNumber;
                }

                station.MinorChannelNumber = channel.MinorChannelNumber;

                if (station.EPGCollection.Count == 0)
                {
                    foreach (EPGEntry epgEntry in channel.EPGCollection)
                    {
                        station.EPGCollection.Add(epgEntry);

                        if (titleLogger != null)
                        {
                            titleLogger.Write(epgEntry.ServiceID + " " +
                                              epgEntry.StartTime.ToShortDateString() + " " +
                                              epgEntry.StartTime.ToString("HH:mm") + " - " +
                                              epgEntry.StartTime.Add(epgEntry.Duration).ToString("HH:mm") + " " +
                                              epgEntry.EventName);
                        }

                        if (descriptionLogger != null && epgEntry.ShortDescription != null)
                        {
                            descriptionLogger.Write(epgEntry.ServiceID + " " +
                                                    " Evt ID " + epgEntry.EventID +
                                                    epgEntry.StartTime.ToShortDateString() + " " +
                                                    epgEntry.StartTime.ToString("HH:mm") + " - " +
                                                    epgEntry.StartTime.Add(epgEntry.Duration).ToString("HH:mm") + " " +
                                                    epgEntry.ShortDescription);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Compare this instance with another for sorting purposes.
        /// </summary>
        /// <param name="category">The other instance.</param>
        /// <param name="keyName">The name of the key to compare on.</param>
        /// <returns>Zero if the instances are equal, Greater than 0 if this instance is greater; less than zero otherwise.</returns>
        public int CompareForSorting(AtscPsipProgramCategory category, string keyName)
        {
            switch (keyName)
            {
                case "CategoryID":
                    if (number == category.CategoryID)
                        return (PSIPDescription.CompareTo(category.PSIPDescription));
                    else
                        return (number.CompareTo(category.CategoryID));
                case "Description":
                    if (PSIPDescription == category.PSIPDescription)
                        return (number.CompareTo(category.CategoryID));
                    else
                        return (PSIPDescription.CompareTo(category.PSIPDescription));
                case "WMCDescription":
                    string thisWMCDescription;
                    string otherWMCDescription;

                    if (WMCDescription != null)
                        thisWMCDescription = WMCDescription;
                    else
                        thisWMCDescription = string.Empty;

                    if (category.WMCDescription != null)
                        otherWMCDescription = category.WMCDescription;
                    else
                        otherWMCDescription = string.Empty;

                    if (thisWMCDescription == otherWMCDescription)
                        return (number.CompareTo(category.CategoryID));
                    else
                        return (thisWMCDescription.CompareTo(otherWMCDescription));
                case "DVBLogicDescription":
                    string thisLogicDescription;
                    string otherLogicDescription;

                    if (DVBLogicDescription != null)
                        thisLogicDescription = DVBLogicDescription;
                    else
                        thisLogicDescription = string.Empty;

                    if (category.DVBLogicDescription != null)
                        otherLogicDescription = category.DVBLogicDescription;
                    else
                        otherLogicDescription = string.Empty;

                    if (thisLogicDescription == otherLogicDescription)
                        return (number.CompareTo(category.CategoryID));
                    else
                        return (thisLogicDescription.CompareTo(otherLogicDescription));
                case "DVBViewerDescription":
                    string thisViewerDescription;
                    string otherViewerDescription;

                    if (DVBViewerDescription != null)
                        thisViewerDescription = DVBViewerDescription;
                    else
                        thisViewerDescription = string.Empty;

                    if (category.DVBViewerDescription != null)
                        otherViewerDescription = category.DVBViewerDescription;
                    else
                        otherViewerDescription = string.Empty;

                    if (thisViewerDescription == otherViewerDescription)
                        return (number.CompareTo(category.CategoryID));
                    else
                        return (thisViewerDescription.CompareTo(otherViewerDescription));
                default:
                    return (0);
            }
        }
        /// <summary>
        /// Add an undefined category to the collection of undefined categories.
        /// </summary>
        /// <param name="number">The category ID.</param>
        /// <param name="description">The category description.</param>
        public static void AddUndefinedCategory(int number, string description)
        {
            if (undefinedCategories == null)
                undefinedCategories = new Collection<AtscPsipProgramCategory>();

            foreach (AtscPsipProgramCategory category in undefinedCategories)
            {
                if (category.number == number)
                    return;

                if (category.number > number)
                {
                    AtscPsipProgramCategory insertCategory = new AtscPsipProgramCategory(number, description);
                    insertCategory.usedCount = 1;
                    undefinedCategories.Insert(undefinedCategories.IndexOf(category), insertCategory);
                    return;
                }
            }

            AtscPsipProgramCategory addCategory = new AtscPsipProgramCategory(number, description);
            addCategory.usedCount = 1;
            undefinedCategories.Add(addCategory);
        }
        /// <summary>
        /// Compare this instance with another for sorting purposes.
        /// </summary>
        /// <param name="category">The other instance.</param>
        /// <param name="keyName">The name of the key to compare on.</param>
        /// <returns>Zero if the instances are equal, Greater than 0 if this instance is greater; less than zero otherwise.</returns>
        public int CompareForSorting(AtscPsipProgramCategory category, string keyName)
        {
            switch (keyName)
            {
            case "CategoryID":
                if (number == category.CategoryID)
                {
                    return(PSIPDescription.CompareTo(category.PSIPDescription));
                }
                else
                {
                    return(number.CompareTo(category.CategoryID));
                }

            case "Description":
                if (PSIPDescription == category.PSIPDescription)
                {
                    return(number.CompareTo(category.CategoryID));
                }
                else
                {
                    return(PSIPDescription.CompareTo(category.PSIPDescription));
                }

            case "WMCDescription":
                string thisWMCDescription;
                string otherWMCDescription;

                if (WMCDescription != null)
                {
                    thisWMCDescription = WMCDescription;
                }
                else
                {
                    thisWMCDescription = string.Empty;
                }

                if (category.WMCDescription != null)
                {
                    otherWMCDescription = category.WMCDescription;
                }
                else
                {
                    otherWMCDescription = string.Empty;
                }

                if (thisWMCDescription == otherWMCDescription)
                {
                    return(number.CompareTo(category.CategoryID));
                }
                else
                {
                    return(thisWMCDescription.CompareTo(otherWMCDescription));
                }

            case "DVBLogicDescription":
                string thisLogicDescription;
                string otherLogicDescription;

                if (DVBLogicDescription != null)
                {
                    thisLogicDescription = DVBLogicDescription;
                }
                else
                {
                    thisLogicDescription = string.Empty;
                }

                if (category.DVBLogicDescription != null)
                {
                    otherLogicDescription = category.DVBLogicDescription;
                }
                else
                {
                    otherLogicDescription = string.Empty;
                }

                if (thisLogicDescription == otherLogicDescription)
                {
                    return(number.CompareTo(category.CategoryID));
                }
                else
                {
                    return(thisLogicDescription.CompareTo(otherLogicDescription));
                }

            case "DVBViewerDescription":
                string thisViewerDescription;
                string otherViewerDescription;

                if (DVBViewerDescription != null)
                {
                    thisViewerDescription = DVBViewerDescription;
                }
                else
                {
                    thisViewerDescription = string.Empty;
                }

                if (category.DVBViewerDescription != null)
                {
                    otherViewerDescription = category.DVBViewerDescription;
                }
                else
                {
                    otherViewerDescription = string.Empty;
                }

                if (thisViewerDescription == otherViewerDescription)
                {
                    return(number.CompareTo(category.CategoryID));
                }
                else
                {
                    return(thisViewerDescription.CompareTo(otherViewerDescription));
                }

            default:
                return(0);
            }
        }