/**
  * Steps through the installation process of a package.
  */
 protected function install()
 {
     try {
         // open package file
         if (!FileUtil::isURL($this->packageArchive->getArchive())) {
             $this->assignPackageInfo();
         }
         switch ($this->step) {
             // prepare package installation
             case '':
                 // download package file if necessary
                 if (FileUtil::isURL($this->packageArchive->getArchive())) {
                     // get return value and update entry in
                     // package_installation_queue with this value
                     $archive = $this->packageArchive->downloadArchive();
                     $sql = "UPDATE\twcf" . WCF_N . "_package_installation_queue\n\t\t\t\t\t\t\tSET\tarchive = '" . escapeString($archive) . "' \n\t\t\t\t\t\t\tWHERE\tqueueID = " . $this->queueID;
                     WCF::getDB()->sendQuery($sql);
                     $this->assignPackageInfo();
                 }
                 // check package file
                 $this->checkArchive();
                 // show confirm package installation site if necessary
                 if ($this->confirmInstallation == 1 && $this->parentQueueID == 0) {
                     $this->nextStep = 'confirm';
                 } else {
                     if ($this->parentQueueID == 0) {
                         $this->nextStep = 'installationFrame';
                     } else {
                         $this->nextStep = 'requirements';
                     }
                 }
                 HeaderUtil::redirect('index.php?page=Package&action=' . $this->action . '&queueID=' . $this->queueID . '&step=' . $this->nextStep . '&packageID=' . PACKAGE_ID . SID_ARG_2ND_NOT_ENCODED);
                 exit;
                 break;
                 // show confirm package installation site
             // show confirm package installation site
             case 'confirm':
                 // get requirements
                 $requirements = $this->packageArchive->getRequirements();
                 $openRequirements = $this->packageArchive->getOpenRequirements();
                 $updatableInstances = array();
                 $missingPackages = 0;
                 foreach ($requirements as $key => $requirement) {
                     if (isset($openRequirements[$requirement['name']])) {
                         $requirements[$key]['open'] = 1;
                         $requirements[$key]['action'] = $openRequirements[$requirement['name']]['action'];
                         if (!isset($requirements[$key]['file'])) {
                             $missingPackages++;
                         }
                     } else {
                         $requirements[$key]['open'] = 0;
                     }
                 }
                 // get other instances
                 if ($this->action == 'install') {
                     $updatableInstances = $this->packageArchive->getUpdatableInstances();
                 }
                 WCFACP::getMenu()->setActiveMenuItem('wcf.acp.menu.link.package');
                 WCF::getTPL()->assign(array('archive' => $this->packageArchive, 'package' => $this->package, 'requiredPackages' => $requirements, 'missingPackages' => $missingPackages, 'updatableInstances' => $updatableInstances, 'excludingPackages' => $this->packageArchive->getConflictedExcludingPackages(), 'excludedPackages' => $this->packageArchive->getConflictedExcludedPackages()));
                 WCF::getTPL()->display('packageInstallationConfirm');
                 exit;
                 break;
             case 'changeToUpdate':
                 // get package id
                 $updatePackageID = 0;
                 if (isset($_REQUEST['updatePackageID'])) {
                     $updatePackageID = intval($_REQUEST['updatePackageID']);
                 }
                 // check package id
                 $updatableInstances = $this->packageArchive->getUpdatableInstances();
                 if (!isset($updatableInstances[$updatePackageID])) {
                     throw new IllegalLinkException();
                 }
                 // update queue entry
                 $sql = "UPDATE\twcf" . WCF_N . "_package_installation_queue\n\t\t\t\t\t\tSET\taction = 'update',\n\t\t\t\t\t\t\tpackageID = " . $updatePackageID . "\n\t\t\t\t\t\tWHERE\tqueueID = " . $this->queueID;
                 WCF::getDB()->sendQuery($sql);
                 HeaderUtil::redirect('index.php?page=Package&action=update&queueID=' . $this->queueID . '&step=installationFrame&packageID=' . PACKAGE_ID . SID_ARG_2ND_NOT_ENCODED);
                 exit;
                 break;
                 // cancel the installation
             // cancel the installation
             case 'cancel':
                 $this->packageArchive->deleteArchive();
                 $sql = "DELETE FROM\twcf" . WCF_N . "_package_installation_queue\n\t\t\t\t\t\tWHERE\t\tqueueID = " . $this->queueID;
                 WCF::getDB()->sendQuery($sql);
                 HeaderUtil::redirect('index.php?page=PackageList&packageID=' . PACKAGE_ID . SID_ARG_2ND_NOT_ENCODED);
                 break;
                 // show the installation frame
             // show the installation frame
             case 'installationFrame':
                 $this->calcProgress(0);
                 $this->nextStep = 'requirements';
                 WCF::getTPL()->assign(array('nextStep' => $this->nextStep));
                 WCF::getTPL()->display('packageInstallationFrame');
                 exit;
                 break;
                 // check if this package depends on other packages
             // check if this package depends on other packages
             case 'requirements':
                 if ($this->installPackageRequirements()) {
                     $this->calcProgress(1);
                     $this->nextStep = 'exclusions';
                 } else {
                     WCF::getTPL()->display('packageInstallationRequirements');
                     exit;
                 }
                 break;
                 // check for conflicted exclusions
             // check for conflicted exclusions
             case 'exclusions':
                 $this->checkExclusions();
                 $this->calcProgress(1);
                 $this->nextStep = 'package';
                 break;
                 // install package itself
             // install package itself
             case 'package':
                 // install selectable package requirements
                 $this->installSelectablePackageRequirements();
                 // install package
                 $this->installPackage();
                 $this->calcProgress(2);
                 $this->nextStep = 'parent';
                 break;
                 // manage parent packages (these are needed by plugins)
             // manage parent packages (these are needed by plugins)
             case 'parent':
                 $this->installPackageParent();
                 $this->rebuildConfigFiles();
                 $this->calcProgress(3);
                 $this->nextStep = 'packageInstallationPlugins';
                 break;
                 // install packageInstallationPlugins
             // install packageInstallationPlugins
             case 'packageInstallationPlugins':
                 if ($this->hasPackageInstallationPlugins()) {
                     $this->installPackageInstallationPlugins();
                 }
                 $this->calcProgress(4);
                 $this->nextStep = 'execPackageInstallationPlugins';
                 break;
                 // At this point execution of packageInstallationPlugins starts. The getNextStep method will return
                 // the class name of the first available packageInstallationPlugin. Thus in the next installation step
                 // this switch will jump into the default: directive. The default: directive will then be called for
                 // every available packageInstallationPlugin. The actual execution of the respective packageInstallationPlugin
                 // is being done there.
             // At this point execution of packageInstallationPlugins starts. The getNextStep method will return
             // the class name of the first available packageInstallationPlugin. Thus in the next installation step
             // this switch will jump into the default: directive. The default: directive will then be called for
             // every available packageInstallationPlugin. The actual execution of the respective packageInstallationPlugin
             // is being done there.
             case 'execPackageInstallationPlugins':
                 $this->loadPackageInstallationPlugins();
                 $this->calcProgress(5);
                 $this->nextStep = $this->getNextPackageInstallationPlugin('');
                 break;
                 // check if this package has optional packages
             // check if this package has optional packages
             case 'optionals':
                 // update package version before installing optionals
                 $this->updatePackageVersion();
                 // install optional packages
                 if ($this->installPackageOptionals()) {
                     $this->calcProgress(6);
                     $this->nextStep = 'finish';
                 } else {
                     WCF::getTPL()->display('packageInstallationOptionals');
                     exit;
                 }
                 break;
                 // finish installation
             // finish installation
             case 'finish':
                 $this->calcProgress(7);
                 $this->nextStep = $this->finishInstallation();
                 break;
                 // start rollback of all installations in the active process
             // start rollback of all installations in the active process
             case 'rollback':
                 // delete packages that are not rollbackable
                 $sql = "DELETE FROM\twcf" . WCF_N . "_package_installation_queue\n\t\t\t\t\t\tWHERE\t\tprocessNo = " . $this->processNo . "\n\t\t\t\t\t\t\t\tAND (\n\t\t\t\t\t\t\t\t\taction <> 'install'\n\t\t\t\t\t\t\t\t\tOR cancelable = 0\n\t\t\t\t\t\t\t\t)";
                 WCF::getDB()->sendQuery($sql);
                 // enable rollback for all other packages
                 $sql = "UPDATE\twcf" . WCF_N . "_package_installation_queue\n\t\t\t\t\t\tSET\taction = 'rollback',\n\t\t\t\t\t\t\tdone = 0\n\t\t\t\t\t\tWHERE\tprocessNo = " . $this->processNo . "\n\t\t\t\t\t\t\tAND action = 'install'\n\t\t\t\t\t\t\tAND cancelable = 1";
                 WCF::getDB()->sendQuery($sql);
                 HeaderUtil::redirect('index.php?page=Package&action=openQueue&processNo=' . $this->processNo . '&packageID=' . PACKAGE_ID . SID_ARG_2ND_NOT_ENCODED);
                 exit;
                 break;
                 // execute PackageInstallationPlugins
             // execute PackageInstallationPlugins
             default:
                 $this->executePackageInstallationPlugin($this->step);
                 $this->nextStep = $this->getNextPackageInstallationPlugin($this->step);
         }
         WCF::getTPL()->assign(array('nextStep' => $this->nextStep));
         WCF::getTPL()->display('packageInstallationNext');
     } catch (SystemException $e) {
         $this->showPackageInstallationException($e);
     }
 }