public List<TVProgramme> GetTVProgrammesUsingEPGRequests(List<EPGRequest> EPGrequests, bool omitDescriptions, TVProgrammeType matchType)
        {
            Stopwatch timePerformance = new Stopwatch();
            timePerformance.Start();

            List<TVProgramme> mainOutput = new List<TVProgramme>();

            ScheduleEntry[] schedEntries;
            Service service;
            foreach (EPGRequest epgRequest in EPGrequests)
            {
                // Get the service from the object store
                service = GetServiceByID(epgRequest.TVServiceID);
                if (service == null)
                {
                    DebugError("Could not find service with ID " + epgRequest.TVServiceID);
                    continue;  // break if service not found
                }

                List<TVProgramme> svcOutput = new List<TVProgramme>();

                // Get entries in time range using API function (about 8-95 times faster!)
                DateTime startTime = new DateTime(epgRequest.StartTime, DateTimeKind.Utc);
                DateTime stopTime = new DateTime(epgRequest.StopTime, DateTimeKind.Utc);
                schedEntries = service.GetScheduleEntriesBetween(startTime, stopTime);

                TVProgramme tvp;
                foreach (ScheduleEntry se in schedEntries)
                {
                    if (se == null) continue;

                    // Include programme?  (i.e. does it match the requested type)
                    bool includeMe;
                    if (matchType == TVProgrammeType.All)
                        includeMe = true;
                    else
                        includeMe = Conversion.isProgrammeType(se.Program, matchType);

                    if (includeMe)
                    {
                        tvp = Conversion.TVProgrammeFromScheduleEntry(se, omitDescriptions);
                        if (tvp != null)
                            svcOutput.Add(tvp);
                    }

                }

                // Sort each service's lineup by start time (prob not necessary)
                CommonEPG.Comparers.TVProgrammeStartTimeComparer comparer = new CommonEPG.Comparers.TVProgrammeStartTimeComparer();
                svcOutput.Sort(comparer);

                mainOutput.AddRange(svcOutput);

                svcOutput.Clear();
                svcOutput = null;
            }

            timePerformance.Stop();
            DebugNormal("Time to fetch EPG programmes on " + EPGrequests.Count.ToString() + " services: " + timePerformance.Elapsed.TotalMilliseconds.ToString() + "ms");

            return mainOutput;
        }
        public List<TVProgramme> SearchTVProgrammesByDateRange(DateRange dateRange, string searchText, EPGSearchTextType searchTextType, EPGSearchMatchType searchMatchType, out bool resultsWereTruncated, string[] serviceIDs)
        {
            resultsWereTruncated = false;
            Stopwatch timePerformance = new Stopwatch();
            timePerformance.Start();

            List<TVProgramme> mainOutput = new List<TVProgramme>();

            List<Service> services = ListOfServicesFromIDs(serviceIDs);
            int limiter = 50;
            foreach (Service service in services)
            {
                List<TVProgramme> svcOutput = new List<TVProgramme>();

                // Get entries in time range using API function (about 8-95 times faster)
                ScheduleEntry[] schedEntries = service.GetScheduleEntriesBetween(dateRange.StartTime, dateRange.StopTime);

                TVProgramme tvp;
                foreach (ScheduleEntry se in schedEntries)
                {
                    // Some schedule entries can be null
                    if (se == null) continue;

                    if (!se.IsLatestVersion) continue;

                    Program p = se.Program;
                    if (p == null) continue;

                    List<string> lstSearchFields = new List<string>();
                    if ((searchTextType != EPGSearchTextType.Credits))
                        if (!String.IsNullOrEmpty(p.Title))
                            lstSearchFields.Add(p.Title);

                    if ((searchTextType == EPGSearchTextType.TitleAndEpisodeTitle) || (searchTextType == EPGSearchTextType.TitlesAndDescription) || (searchTextType == EPGSearchTextType.AllTextFields))
                        if (!String.IsNullOrEmpty(p.EpisodeTitle))
                            lstSearchFields.Add(p.EpisodeTitle);

                    if ((searchTextType == EPGSearchTextType.TitlesAndDescription) || (searchTextType == EPGSearchTextType.AllTextFields))
                        if (!string.IsNullOrEmpty(p.Description))
                            lstSearchFields.Add(p.Description);

                    // if (searchTextType == EPGSearchTextType.Credits)  TODO
                    bool match = (StringListMatch(lstSearchFields, searchMatchType, searchText));
                    lstSearchFields.Clear();
                    lstSearchFields = null;

                    if (match)
                    {
                        tvp = Conversion.TVProgrammeFromScheduleEntry(se);
                        if (tvp != null)
                            mainOutput.Add(tvp);

                        if (limiter-- < 1)
                        {
                            resultsWereTruncated = true;
                            break;
                        }

                    }
                }

                if (limiter < 1) break;
            }

            // Sort by start time (prob not necessary)
            CommonEPG.Comparers.TVProgrammeStartTimeComparer comparer = new CommonEPG.Comparers.TVProgrammeStartTimeComparer();
            mainOutput.Sort(comparer);

            timePerformance.Stop();
            DebugNormal("Time to search EPG programmes : " + timePerformance.Elapsed.TotalMilliseconds.ToString() + "ms");

            return mainOutput;
        }