/// <summary>
        /// Imports the programs.
        /// </summary>
        /// <param name="delay">The delay.</param>
        /// <returns></returns>
        public int ImportPrograms(int delay)
        {
            const string EMPTY = "-";
             StringBuilder description = new StringBuilder();
             //string strTvChannel;
             //int idTvChannel;

             ImportStats stats = new ImportStats();
             ClearCache();
             Log.WriteFile("Starting processing of {0} schedule entries", _results.Data.Schedules.List.Count);

             TvdbLibAccess tvdb = null;

             _useTvDb = PluginSettings.UseTvDb;
             bool logdebug = PluginSettings.TvDbLogDebug;
             if (_useTvDb) {
               tvdb = new TvdbLibAccess(logdebug);
             }

             foreach (SchedulesDirect.SoapEntities.TVSchedule tvSchedule in _results.Data.Schedules.List)
             {
            if (ShowProgress != null)
               ShowProgress(this, stats);

            //GetEPGMapping(tvSchedule.Station.Trim() + XMLTVID, out idTvChannel, out strTvChannel);
            List<Channel> channelIdList = GetStationChannels(tvSchedule.Station.Trim());

            if (channelIdList.Count <= 0)
            {
               Log.WriteFile("Unable to find Program Channel: StationID: #{0} XMLTVID {1} ", tvSchedule.Station, XMLTVID);
               continue;
            }

            SchedulesDirect.SoapEntities.TVProgram tvProgram = _results.Data.Programs.ProgramById(tvSchedule.ProgramId);
            if (tvProgram == null)
            {
               Log.WriteFile("Unable to find programId #{0} specified in schedule at time {1)", tvSchedule.ProgramId, tvSchedule.StartTimeStr);
               continue;
            }

            description.Length = 0; // Clears the description string builder

            DateTime localStartTime = tvSchedule.StartTimeUtc.ToLocalTime();
            DateTime localEndTime = localStartTime + tvSchedule.Duration;

            //Program mpProgram = new Program(idTvChannel, localStartTime, localEndTime, tvProgram.Title, tvProgram.
            //MediaPortal.TV.Database.TVProgram mpProgram = new TVProgram(strTvChannel, localStartTime, localEndTime, tvProgram.Title);

            string zTitle          = tvProgram.Title;
            string zEpisode        = string.IsNullOrEmpty(tvProgram.Subtitle) ? EMPTY : tvProgram.Subtitle;
            //string zDate           = string.IsNullOrEmpty(tvProgram.OriginalAirDateStr) ? EMPTY : tvProgram.OriginalAirDate.Date.ToString();
            string zDate           = string.IsNullOrEmpty(tvProgram.OriginalAirDateStr) ? DateTime.MinValue.ToString() : tvProgram.OriginalAirDate.Date.ToString();
            string zSeriesNum      = string.IsNullOrEmpty(tvProgram.Series) ? EMPTY : tvProgram.Series;
            string zEpisodeNum     = string.IsNullOrEmpty(tvProgram.SyndicatedEpisodeNumber) ? EMPTY : tvProgram.SyndicatedEpisodeNumber;
            string zStarRating     = string.IsNullOrEmpty(tvProgram.StarRating) ? EMPTY : tvProgram.StarRatingNum.ToString() + "/8";
            string zClassification = string.IsNullOrEmpty(tvProgram.MPAARating) ? tvSchedule.TVRating : tvProgram.MPAARating;
            string zRepeat         = (tvProgram.IsRepeat(tvSchedule)) ? "Repeat" : string.Empty;

            int zRatingAge = NOTFOUND;
            if (!String.IsNullOrEmpty(zClassification))
               zRatingAge = GetRatingAge(zClassification);

            string zEpisodePart = EMPTY;
            string zGenre = EMPTY;

            if (tvSchedule.Part.Number > 0)
            {
               zEpisodePart = String.Format(
                   System.Globalization.CultureInfo.InvariantCulture, "..{0}/{1}", tvSchedule.Part.Number, tvSchedule.Part.Total);
            }
            else
            {
               zEpisodePart = EMPTY;
            }

            // MediaPortal only supports a single Genre so we use the (first) primary one
            SchedulesDirect.SoapEntities.ProgramGenre tvProgramGenres = _results.Data.Genres.ProgramGenreById(tvProgram.ID);
            if (tvProgramGenres != null && tvProgramGenres.List.Count > 0)
            {
               zGenre = tvProgramGenres.List[0].GenreClass;
            }
            else
            {
               zGenre = EMPTY;
            }

            // Add tags to description (temporary workaround until MediaPortal supports and displays more tags)
            if (!string.IsNullOrEmpty(tvProgram.Subtitle))
               description.Append(tvProgram.Subtitle).Append(": ");

            description.Append(tvProgram.Description);

            if (tvProgram.Year > 0 && _addExtraInfoToShowDescription)
               description.AppendFormat(" ({0} {1})", tvProgram.Year, tvProgram.StarRating);

            if (tvProgram.IsRepeat(tvSchedule) && _addExtraInfoToShowDescription)
            {
               if (string.IsNullOrEmpty(tvProgram.OriginalAirDateStr))
               {
                  description.Append(" (Repeat)");
               }
               else
               {
                  description.Append(" (First aired ").Append(tvProgram.OriginalAirDate.ToShortDateString()).Append(")");
               }
            }
            else if (tvProgram.IsNew(tvSchedule) && _addExtraInfoToShowDescription)
            {
               if (string.IsNullOrEmpty(tvProgram.OriginalAirDateStr))
               {
                  description.Append(" (New)");
               }
               else if (localStartTime.Subtract(tvProgram.OriginalAirDate).TotalDays > 60)
               {
                  // News may have New Attribute and OAD 8/3/1970
                  // The OAD of the "series"
                  description.Append(" (New)");
               }
               else
               {
                  description.Append(" (New: ").Append(tvProgram.OriginalAirDate.ToShortDateString()).Append(")");
               }
            }
            else if (_addExtraInfoToShowDescription)
            {
               if (!string.IsNullOrEmpty(tvProgram.OriginalAirDateStr))
               {
                  if (tvProgram.OriginalAirDate.Date == localStartTime.Date)
                     description.Append(" (New: " + tvProgram.OriginalAirDate.ToShortDateString() + ")");
                  else
                     description.Append(" (First Aired: " + tvProgram.OriginalAirDate.ToShortDateString() + ")");
               }
            }

            if (tvSchedule.HDTV && _addExtraInfoToShowDescription)
               description.Append(" (HDTV)");

            if (!string.IsNullOrEmpty(tvSchedule.Dolby) && _addExtraInfoToShowDescription)
               description.AppendFormat(" ({0})", tvSchedule.Dolby);

            if (tvProgram.Advisories != null && tvProgram.Advisories.Advisory.Count > 0 && _addExtraInfoToShowDescription)
            {
               description.AppendFormat(" ({0})", string.Join(", ", tvProgram.Advisories.Advisory.ToArray()));
            }

            // Converting Star Rating to 0-10 pre
            // http://forum.team-mediaportal.com/showpost.php?p=142866&postcount=9
            //SD Rating  <--> MP Rating
            //   1                1
            //   2                3
            //   3                4
            //   4                5
            //   5                6
            //   6                8
            //   7               10
            int mpStarRating = NOTFOUND;
            if (tvProgram.StarRatingNum == 1)
               mpStarRating = 1;
            else if (tvProgram.StarRatingNum > 1 && tvProgram.StarRatingNum <= 5)
               mpStarRating = tvProgram.StarRatingNum + 1;
            else if (tvProgram.StarRatingNum == 6)
               mpStarRating = 8;
            else if (tvProgram.StarRatingNum == 7)
               mpStarRating = 10;

            foreach (Channel pCh in channelIdList)
            {
               bool done = false;
               if (_useTvDb && tvdb.shouldWeGetTvDbForSeries(zTitle)) {
                 try {
                   // get season/episode info from thetvdb.com
                   string sid = tvdb.getSeriesId(zTitle);

                   if (sid != null || sid.Length >= 0) {

                     bool allowTailMatch = true;

                     // one particular hard-coded series that can't do tail-matching
                     if (zTitle.Equals("24")) {
                       allowTailMatch = false;
                     }

                     string sep = tvdb.getSeasonEpisode(zTitle,sid,zEpisode,tvProgram.OriginalAirDate,allowTailMatch);
                     if (sep.Length > 0) {
                       Program mpProgram = new Program(pCh.IdChannel,localStartTime,localEndTime,zTitle,description.ToString(),zGenre,Program.ProgramState.None,tvProgram.OriginalAirDate.Date,zSeriesNum,sep,zEpisode,zEpisodePart,mpStarRating,zClassification,zRatingAge);

                       UpdateProgram(mpProgram);
                       stats._iPrograms++;
                       done = true;
                     }
                   }
                 } catch (Exception ex) {
                   Log.Error("Error getting TvDb info.  Just using default info instead: {0}",ex.StackTrace);
                 }
               }

               if (!done) {
                 // don't use tvdb or use it but did not find a match
                 Program mpProgram = new Program(pCh.IdChannel,localStartTime,localEndTime,zTitle,description.ToString(),zGenre,Program.ProgramState.None,tvProgram.OriginalAirDate.Date,zSeriesNum,zEpisodeNum,zEpisode,zEpisodePart,mpStarRating,zClassification,zRatingAge);

                 UpdateProgram(mpProgram);
                 stats._iPrograms++;
               }

            }

            System.Threading.Thread.Sleep(delay);
             }
             if (_useTvDb && tvdb != null) {
               tvdb.closeCache();
             }
             return stats._iPrograms;
        }
        /// <summary>
        /// Imports the channels.
        /// </summary>
        /// <param name="delay">The delay in ms between each record.</param>
        /// <returns></returns>
        public int ImportChannels(int delay)
        {
            ClearCache();

             ImportStats stats = new ImportStats();

             if (_lineupHasChanged && _remapChannelsOnLineupChange)
            VerifyChannelMapping(delay);

             // Refresh the channel cache
             _mpChannelCache = (IList)Channel.ListAll();

             foreach (SchedulesDirect.SoapEntities.TVLineup lineup in _results.Data.Lineups.List)
             {
            Log.WriteFile("Processing lineup {0} [id={1} type={2} postcode={3}]", lineup.Name, lineup.ID, lineup.Type, lineup.PostalCode);
            foreach (SchedulesDirect.SoapEntities.TVStationMap tvStationMap in lineup.StationMap)
            {
               if (ShowProgress != null)
                  ShowProgress(this, stats);

               SchedulesDirect.SoapEntities.TVStation tvStation = _results.Data.Stations.StationById(tvStationMap.StationId);
               if (tvStation == null)
               {
                  Log.WriteFile("Unable to find stationId #{0} specified in lineup", tvStationMap.StationId);
                  continue;
               }

               if (tvStationMap.ChannelMajor < 0)
               {
                  Log.WriteFile("TVStationMap ChannelMajor Not Valid. StationID: {3} ChannelMajor: {0} ChannelMinor: {1} SchedulesDirectChannel: {2}", tvStationMap.ChannelMajor, tvStationMap.ChannelMinor, tvStationMap.SchedulesDirectChannel, tvStationMap.StationId);
                  continue;
               }

               Channel mpChannel = FindTVChannel(tvStation, tvStationMap, lineup.IsLocalBroadcast());
               // Update the channel and map it
               if (mpChannel != null)
               {
                  mpChannel.GrabEpg = false;
                  mpChannel.LastGrabTime = DateTime.Now;
                  mpChannel.ExternalId = BuildXmlTvId(lineup.IsLocalBroadcast(), tvStation, tvStationMap);  //tvStation.ID + XMLTVID;
                  if (_renameChannels)
                  {
                     string oldName = mpChannel.DisplayName;
                     mpChannel.DisplayName = BuildChannelName(tvStation, tvStationMap);
                     mpChannel.DisplayName = BuildChannelName(tvStation, tvStationMap);
                     RenameLogo(oldName, mpChannel.DisplayName);
                  }
                  stats._iChannels++;

                  mpChannel.Persist();

                  Log.WriteFile("Updated channel {1} [id={0} xmlid={2}]", mpChannel.IdChannel, mpChannel.DisplayName, mpChannel.ExternalId);
               }
               else if ((_createChannels == true && lineup.IsAnalogue() == false)
                  || (_createChannels == true && _createAnalogChannels == true && lineup.IsAnalogue() == true))
               {
                  // Create the channel
                  string cname = BuildChannelName(tvStation, tvStationMap);
                  string xId   = BuildXmlTvId(lineup.IsLocalBroadcast(), tvStation, tvStationMap);

                  mpChannel = new Channel(false, true, 0, Schedule.MinSchedule, false, Schedule.MinSchedule, 10000, true, xId, cname);
                  mpChannel.Persist();

                  TvLibrary.Implementations.AnalogChannel tuningDetail = new TvLibrary.Implementations.AnalogChannel();

                  tuningDetail.IsRadio = false;
                  tuningDetail.IsTv = true;
                  tuningDetail.Name = cname;
                  tuningDetail.Frequency = 0;
                  tuningDetail.ChannelNumber = tvStationMap.ChannelMajor;

                  //(int)PluginSettings.ExternalInput;
                  //tuningDetail.VideoSource = PluginSettings.ExternalInput;
                  tuningDetail.VideoSource = _ExternalInput; // PluginSettings.ExternalInput;

                  // Too much overhead using settings directly for country
                  if (_ExternalInputCountry != null)
                     tuningDetail.Country = _ExternalInputCountry; // PluginSettings.ExternalInputCountry;

                  if (lineup.IsLocalBroadcast())
                     tuningDetail.TunerSource = DirectShowLib.TunerInputType.Antenna;
                  else
                     tuningDetail.TunerSource = DirectShowLib.TunerInputType.Cable;

                  //mpChannel.XMLId                  = tvStation.ID + XMLTVID;
                  //mpChannel.Name                   = BuildChannelName(tvStation, tvStationMap);
                  //mpChannel.AutoGrabEpg            = false;
                  //mpChannel.LastDateTimeEpgGrabbed = DateTime.Now;
                  //mpChannel.External               = true; // This may change with cablecard support one day
                  //mpChannel.ExternalTunerChannel   = tvStationMap.ChannelMajor.ToString();
                  //mpChannel.Frequency              = 0;
                  //mpChannel.Number                 = (int)PluginSettings.ExternalInput;

                  tvLayer.AddTuningDetails(mpChannel, tuningDetail);

                  Log.WriteFile("Added channel {1} [id={0} xmlid={2}]", mpChannel.IdChannel, mpChannel.DisplayName, mpChannel.ExternalId);
                  stats._iChannels++;
               }
               else
               {
                  Log.WriteFile("Could not find a match for {0}/{1}", tvStation.CallSign, tvStationMap.Channel);
               }
               System.Threading.Thread.Sleep(delay);
            }
             }

             if (_lineupHasChanged && _remapChannelsOnLineupChange)
             {
            if (_mpUnMappedChannelCache != null)
            {
               foreach (Channel ch in _mpUnMappedChannelCache)
               {
                  ch.ExternalId = String.Empty;
                  ch.Persist();
               }
            }
             }

             if (_sortChannels)
            SortTVChannels();

             return stats._iChannels;
        }