/// <summary>
    /// Cleans up the controller
    /// </summary>
    public void DeInit()
    {
      Log.Info("Controller: DeInit.");
      try
      {
        if (heartBeatMonitorThread != null)
        {
          if (!Service1.HasThreadCausedAnUnhandledException(heartBeatMonitorThread))
          {
            if (heartBeatMonitorThread.IsAlive)
            {
              Log.Info("Controller: HeartBeat monitor stopped...");
              try
              {
                heartBeatMonitorThread.Abort();
              }
              catch (Exception) {}
            }
          }
        }

        //stop the RTSP streamer server
        if (_streamer != null)
        {
          Log.Info("Controller: stop streamer...");
          _streamer.Stop();
          _streamer = null;
          Log.Info("Controller: streamer stopped...");
        }
        //stop the recording scheduler
        if (_scheduler != null)
        {
          Log.Info("Controller: stop scheduler...");
          _scheduler.Stop();
          _scheduler = null;
          Log.Info("Controller: scheduler stopped...");
        }
        //stop the epg grabber
        if (_epgGrabber != null)
        {
          Log.Info("Controller: stop epg grabber...");
          _epgGrabber.Stop();
          _epgGrabber = null;
          Log.Info("Controller: epg stopped...");
        }

        //clean up the tv cards
        FreeCards();

        Gentle.Common.CacheManager.Clear();
        if (GlobalServiceProvider.Instance.IsRegistered<ITvServerEvent>())
        {
          GlobalServiceProvider.Instance.Remove<ITvServerEvent>();
        }
      }
      catch (Exception ex)
      {
        Log.Error("TvController: Deinit failed - {0}", ex.Message);
      }
    }
    /// <summary>
    /// Initalizes the controller.
    /// It will update the database with the cards found on this system
    /// start the epg grabber and scheduler
    /// and check if its supposed to be a master or slave controller
    /// </summary>
    private bool InitController()
    {
      if (GlobalServiceProvider.Instance.IsRegistered<ITvServerEvent>())
      {
        GlobalServiceProvider.Instance.Remove<ITvServerEvent>();
      }
      GlobalServiceProvider.Instance.Add<ITvServerEvent>(this);
      try
      {
        //string threadname = Thread.CurrentThread.Name;
        //if (string.IsNullOrEmpty(threadname))
        //  Thread.CurrentThread.Name = "TVController";

        //load the database connection string from the config file
        Log.Info(@"{0}\gentle.config", PathManager.GetDataPath);
        string connectionString, provider;
        GetDatabaseConnectionString(out connectionString, out provider);
        string ConnectionLog = connectionString.Remove(connectionString.IndexOf(@"Password="******"Controller: using {0} database connection: {1}", provider, ConnectionLog);
        Gentle.Framework.ProviderFactory.SetDefaultProviderConnectionString(connectionString);

        _cards = new Dictionary<int, ITvCardHandler>();
        _localCardCollection = new TvCardCollection(this);

        //log all local ip adresses, usefull for debugging problems
        Log.Write("Controller: started at {0}", Dns.GetHostName());
        IPHostEntry local = Dns.GetHostEntry(Dns.GetHostName());
        foreach (IPAddress ipaddress in local.AddressList)
        {
          // Show only IPv4 family addresses
          if (ipaddress.AddressFamily == AddressFamily.InterNetwork)
          {
            Log.Info("Controller: local ip address:{0}", ipaddress.ToString());
          }
        }

        //get all registered servers from the database
        IList<Server> servers;
        try
        {
          servers = Server.ListAll();
        }
        catch (Exception ex)
        {
          Log.Error("Controller: Failed to fetch tv servers from database - {0}",
                    Utils.BlurConnectionStringPassword(ex.Message));
          return false;
        }

        // find ourself
        foreach (Server server in servers)
        {
          if (IsLocal(server.HostName))
          {
            Log.Info("Controller: server running on {0}", server.HostName);
            _ourServer = server;
            break;
          }
        }

        //we do not exist yet?
        if (_ourServer == null)
        {
          //then add ourself to the server
          if (servers.Count == 0)
          {
            //there are no other servers so we are the master one.
            Log.Info("Controller: create new server in database");
            _ourServer = new Server(false, Dns.GetHostName(), RtspStreaming.DefaultPort);
            _ourServer.IsMaster = true;
            _isMaster = true;
            _ourServer.Persist();
            Log.Info("Controller: new server created for {0} master:{1} ", Dns.GetHostName(), _isMaster);
          }
          else
          {
            Log.Error(
              "Controller: sorry, master/slave server setups are not supported. Since there is already another server in the db, we exit here.");
            return false;
          }
        }
        _isMaster = _ourServer.IsMaster;

        //enumerate all tv cards in this pc...
        TvBusinessLayer layer = new TvBusinessLayer();

        _maxFreeCardsToTry = Int32.Parse(layer.GetSetting("timeshiftMaxFreeCardsToTry", "0").Value);

        for (int i = 0; i < _localCardCollection.Cards.Count; ++i)
        {
          //for each card, check if its already mentioned in the database
          bool found = false;
          IList<Card> cards = _ourServer.ReferringCard();
          foreach (Card card in cards)
          {
            if (card.DevicePath == _localCardCollection.Cards[i].DevicePath)
            {
              found = true;
              break;
            }
          }
          if (!found)
          {
            // card is not yet in the database, so add it
            Log.Info("Controller: add card:{0}", _localCardCollection.Cards[i].Name);
            layer.AddCard(_localCardCollection.Cards[i].Name, _localCardCollection.Cards[i].DevicePath, _ourServer);
          }
        }
        //notify log about cards from the database which are removed from the pc
        IList<Card> cardsInDbs = Card.ListAll();
        int cardsInstalled = _localCardCollection.Cards.Count;
        foreach (Card dbsCard in cardsInDbs)
        {
          if (dbsCard.ReferencedServer().IdServer == _ourServer.IdServer)
          {
            bool found = false;
            for (int cardNumber = 0; cardNumber < cardsInstalled; ++cardNumber)
            {
              if (dbsCard.DevicePath == _localCardCollection.Cards[cardNumber].DevicePath)
              {
                Card cardDB = layer.GetCardByDevicePath(_localCardCollection.Cards[cardNumber].DevicePath);

                bool cardEnabled = cardDB.Enabled;
                bool cardPresent = _localCardCollection.Cards[cardNumber].CardPresent;

                if (cardEnabled && cardPresent)
                {
                  ITVCard unknownCard = _localCardCollection.Cards[cardNumber];

                  if (unknownCard is TvCardBase)
                  {
                    TvCardBase card = (TvCardBase)unknownCard;
                    if (card.PreloadCard)
                    {
                      try
                      {
                        Log.Info("Controller: preloading card :{0}", card.Name);
                        card.BuildGraph();
                        if (unknownCard is TvCardAnalog)
                        {
                          ((TvCardAnalog)unknownCard).ReloadCardConfiguration();
                        }
                      }
                      catch (Exception ex)
                      {
                        Log.Error("failed to preload card '{0}', ex = {1}", card.Name, ex);
                      }
                    }
                    else
                    {
                      Log.Info("Controller: NOT preloading card :{0}", card.Name);
                    }
                  }
                  else
                  {
                    Log.Info("Controller: NOT preloading card :{0}", unknownCard.Name);
                  }
                }

                found = true;
                break;
              }
            }
            if (!found)
            {
              Log.Info("Controller: card not found :{0}", dbsCard.Name);

              for (int i = 0; i < _localCardCollection.Cards.Count; ++i)
              {
                if (_localCardCollection.Cards[i].DevicePath == dbsCard.DevicePath)
                {
                  _localCardCollection.Cards[i].CardPresent = false;
                  break;
                }
              }

              // Fix mantis 0002790: Bad behavior when card count for IPTV = 0 
              if (dbsCard.Name.StartsWith("MediaPortal IPTV Source Filter"))
              {
                CardRemove(dbsCard.IdCard);
              }
            }
          }
        }

        Dictionary<int, ITVCard> localcards = new Dictionary<int, ITVCard>();

        cardsInDbs = Card.ListAll();
        foreach (Card card in cardsInDbs)
        {
          if (IsLocal(card.ReferencedServer().HostName))
          {
            for (int x = 0; x < _localCardCollection.Cards.Count; ++x)
            {
              if (_localCardCollection.Cards[x].DevicePath == card.DevicePath)
              {
                localcards[card.IdCard] = _localCardCollection.Cards[x];
                break;
              }
            }
          }
        }

        Log.Info("Controller: setup hybrid cards");
        IList<CardGroup> cardgroups = CardGroup.ListAll();
        foreach (CardGroup group in cardgroups)
        {
          IList<CardGroupMap> cards = group.CardGroupMaps();
          HybridCardGroup hybridCardGroup = new HybridCardGroup();
          foreach (CardGroupMap card in cards)
          {
            if (localcards.ContainsKey(card.IdCard))
            {
              localcards[card.IdCard].IsHybrid = true;
              Log.WriteFile("Hybrid card: " + localcards[card.IdCard].Name + " (" + group.Name + ")");
              HybridCard hybridCard = hybridCardGroup.Add(card.IdCard, localcards[card.IdCard]);
              localcards[card.IdCard] = hybridCard;
            }
          }
        }

        cardsInDbs = Card.ListAll();
        foreach (Card dbsCard in cardsInDbs)
        {
          if (localcards.ContainsKey(dbsCard.IdCard))
          {
            ITVCard card = localcards[dbsCard.IdCard];
            TvCardHandler tvcard = new TvCardHandler(dbsCard, card);
            _cards[dbsCard.IdCard] = tvcard;
          }

          // remove any old timeshifting TS files	
          try
          {
            string TimeShiftPath = dbsCard.TimeShiftFolder;
            if (string.IsNullOrEmpty(dbsCard.TimeShiftFolder))
            {
              TimeShiftPath = String.Format(@"{0}\Team MediaPortal\MediaPortal TV Server\timeshiftbuffer",
                                            Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData));
            }
            if (!Directory.Exists(TimeShiftPath))
            {
              Log.Info("Controller: creating timeshifting folder {0} for card \"{1}\"", TimeShiftPath, dbsCard.Name);
              Directory.CreateDirectory(TimeShiftPath);
            }

            Log.Debug("Controller: card {0}: current timeshiftpath = {1}", dbsCard.Name, TimeShiftPath);
            if (TimeShiftPath != null)
            {
              string[] files = Directory.GetFiles(TimeShiftPath);

              foreach (string file in files)
              {
                try
                {
                  FileInfo fInfo = new FileInfo(file);
                  bool delFile = (fInfo.Extension.ToUpperInvariant().IndexOf(".TSBUFFER") == 0);

                  if (!delFile)
                  {
                    delFile = (fInfo.Extension.ToUpperInvariant().IndexOf(".TS") == 0) &&
                              (fInfo.Name.ToUpperInvariant().IndexOf("TSBUFFER") > 0);
                  }
                  if (delFile)
                    File.Delete(fInfo.FullName);
                }
                catch (IOException) {}
              }
            }
          }
          catch (Exception exd)
          {
            Log.Info("Controller: Error cleaning old ts buffer - {0}", exd.Message);
          }
        }

        Log.Info("Controller: setup streaming");
        _streamer = new RtspStreaming(_ourServer.HostName, _ourServer.RtspPort);

        if (_isMaster)
        {
          _epgGrabber = new EpgGrabber(this);
          _epgGrabber.Start();
          _scheduler = new Scheduler(this);
          _scheduler.Start();
        }

        SetupHeartbeatThread();
        ExecutePendingDeletions();

        // Re-evaluate program states
        Log.Info("Controller: recalculating program states");
        TvDatabase.Program.ResetAllStates();
        Schedule.SynchProgramStatesForAll();
      }
      catch (Exception ex)
      {
        Log.Write("TvControllerException: {0}\r\n{1}", ex.ToString(), ex.StackTrace);
        return false;
      }

      Log.Info("Controller: initalized");
      return true;
    }