/**
  * uninstall app
  *
  * @param Tinebase_Model_Application $_application
  * @throws Setup_Exception
  */
 protected function _uninstallApplication(Tinebase_Model_Application $_application, $uninstallAll = false)
 {
     if ($this->_backend === null) {
         throw new Setup_Exception('No setup backend available');
     }
     Setup_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . ' Uninstall ' . $_application);
     try {
         $applicationTables = Tinebase_Application::getInstance()->getApplicationTables($_application);
     } catch (Zend_Db_Statement_Exception $zdse) {
         Setup_Core::getLogger()->err(__METHOD__ . '::' . __LINE__ . " " . $zdse);
         throw new Setup_Exception('Could not uninstall ' . $_application . ' (you might need to remove the tables by yourself): ' . $zdse->getMessage());
     }
     $disabledFK = FALSE;
     $db = Tinebase_Core::getDb();
     do {
         $oldCount = count($applicationTables);
         if ($_application->name == 'Tinebase') {
             $installedApplications = Tinebase_Application::getInstance()->getApplications(NULL, 'id');
             if (count($installedApplications) !== 1) {
                 throw new Setup_Exception_Dependency('Failed to uninstall application "Tinebase" because of dependencies to other installed applications.');
             }
         }
         foreach ($applicationTables as $key => $table) {
             Setup_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . " Remove table: {$table}");
             try {
                 // drop foreign keys which point to current table first
                 $foreignKeys = $this->_backend->getExistingForeignKeys($table);
                 foreach ($foreignKeys as $foreignKey) {
                     Setup_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . " Drop index: " . $foreignKey['table_name'] . ' => ' . $foreignKey['constraint_name']);
                     $this->_backend->dropForeignKey($foreignKey['table_name'], $foreignKey['constraint_name']);
                 }
                 // drop table
                 $this->_backend->dropTable($table);
                 if ($_application->name != 'Tinebase') {
                     Tinebase_Application::getInstance()->removeApplicationTable($_application, $table);
                 }
                 unset($applicationTables[$key]);
             } catch (Zend_Db_Statement_Exception $e) {
                 // we need to catch exceptions here, as we don't want to break here, as a table
                 // might still have some foreign keys
                 // this works with mysql only
                 $message = $e->getMessage();
                 Setup_Core::getLogger()->warn(__METHOD__ . '::' . __LINE__ . " Could not drop table {$table} - " . $message);
                 // remove app table if table not found in db
                 if (preg_match('/SQLSTATE\\[42S02\\]: Base table or view not found/', $message) && $_application->name != 'Tinebase') {
                     Tinebase_Application::getInstance()->removeApplicationTable($_application, $table);
                     unset($applicationTables[$key]);
                 } else {
                     Setup_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . " Disabling foreign key checks ... ");
                     if ($db instanceof Zend_Db_Adapter_Pdo_Mysql) {
                         $db->query("SET FOREIGN_KEY_CHECKS=0");
                     }
                     $disabledFK = TRUE;
                 }
             }
         }
         if ($oldCount > 0 && count($applicationTables) == $oldCount) {
             throw new Setup_Exception('dead lock detected oldCount: ' . $oldCount);
         }
     } while (count($applicationTables) > 0);
     if ($disabledFK) {
         if ($db instanceof Zend_Db_Adapter_Pdo_Mysql) {
             Setup_Core::getLogger()->notice(__METHOD__ . '::' . __LINE__ . " Enabling foreign key checks again... ");
             $db->query("SET FOREIGN_KEY_CHECKS=1");
         }
     }
     if ($_application->name != 'Tinebase') {
         if (!$uninstallAll) {
             Tinebase_Relations::getInstance()->removeApplication($_application->name);
             Tinebase_Timemachine_ModificationLog::getInstance()->removeApplication($_application);
             // delete containers, config options and other data for app
             Tinebase_Application::getInstance()->removeApplicationData($_application);
         }
         // remove application from table of installed applications
         Tinebase_Application::getInstance()->deleteApplication($_application);
     }
     Setup_Uninitialize::uninitialize($_application);
     Setup_Core::getLogger()->info(__METHOD__ . '::' . __LINE__ . " Removed app: " . $_application->name);
 }