<?php
namespace TYPO3\CMS\Install\Updates;

/**
 * This file is part of the TYPO3 CMS project.
 *
 * It is free software; you can redistribute it and/or modify it under
 * the terms of the GNU General Public License, either version 2
 * of the License, or any later version.
 *
 * For the full copyright and license information, please read the
 * LICENSE.txt file that was distributed with this source code.
 *
 * The TYPO3 project - inspiring people to share!
 */

/**
 * Contains the update class to create and alter tables, fields and keys to comply to the database schema
 *
 * @author Stephan Großberndt <stephan@grossberndt.de>
 */
class FinalDatabaseSchemaUpdate extends AbstractDatabaseSchemaUpdate {

	/**
	 * Constructor function.
	 */
	public function __construct() {
		parent::__construct();
		$this->title = 'Update database schema: Modify tables and fields';
	}

	/**
	 * Checks if an update is needed
	 *
	 * @param string &$description The description for the update
	 * @return bool TRUE if an update is needed, FALSE otherwise
	 */
	public function checkForUpdate(&$description) {
		$contextService = $this->objectManager->get('TYPO3\\CMS\\Install\\Service\\ContextService');
		$description = 'There are tables or fields in the database which need to be changed.<br /><br />' .
		'This update wizard can be run only when there are no other update wizards left to make sure they have all needed fields unchanged.<br /><br />' .
		'If you want to apply changes selectively, <a href="Install.php?install[action]=importantActions&amp;install[context]=' . $contextService->getContextString() . '&amp;install[controller]=tool">go to Database Analyzer</a>.';

		$databaseDifferences = $this->getDatabaseDifferences();
		$updateSuggestions = $this->schemaMigrationService->getUpdateSuggestions($databaseDifferences);

		return isset($updateSuggestions['change']);
	}

	/**
	 * Second step: Show tables, fields and keys to create or update
	 *
	 * @param string $inputPrefix input prefix, all names of form fields have to start with this. Append custom name in [ ... ]
	 * @return string HTML output
	 */
	public function getUserInput($inputPrefix) {
		$result = '';

		$databaseDifferences = $this->getDatabaseDifferences();
		$updateSuggestions = $this->schemaMigrationService->getUpdateSuggestions($databaseDifferences);

		if (!isset($updateSuggestions['change'])) {
			return $result;
		}

		$fieldsList = '
			<p>
				Change the following fields in tables:
			</p>
			<fieldset>
				<ol class="t3-install-form-label-after">%s</ol>
			</fieldset>';
		$keysList = '
			<p>
				Change the following keys in tables:
			</p>
			<fieldset>
				<ol class="t3-install-form-label-after">%s</ol>
			</fieldset>';
		$item = '
			<li class="labelAfter">
				<label><strong>%1$s</strong>: %2$s</label>
			</li>';

		$fieldItems = array();
		$keyItems = array();
		foreach ($databaseDifferences['diff'] as $tableName => $difference) {
			if ($difference['fields']) {
				$fieldNames = array();
				foreach ($difference['fields'] as $fieldName => $sql) {
					$fieldNames[] = $fieldName;
				}
				$fieldItems[] = sprintf($item, $tableName, implode(', ', $fieldNames));
			}
			if ($difference['keys']) {
				$keyNames = array();
				foreach ($difference['keys'] as $keyName => $sql) {
					$keyNames[] = $keyName;
				}
				$keyItems[] = sprintf($item, $tableName, implode(', ', $keyNames));
			}
		}
		if (!empty($fieldItems)) {
			$result .= sprintf($fieldsList, implode('', $fieldItems));
		}
		if (!empty($keyItems)) {
			$result .= sprintf($keysList, implode('', $keyItems));
		}

		return $result;
	}


	/**
	 * Performs the database update.
	 *
	 * @param array &$dbQueries Queries done in this update
	 * @param mixed &$customMessages Custom messages
	 * @return bool TRUE on success, FALSE on error
	 */
	public function performUpdate(array &$dbQueries, &$customMessages) {
		// First perform all add update statements to database
		$databaseDifferences = $this->getDatabaseDifferences();
		$updateStatements = $this->schemaMigrationService->getUpdateSuggestions($databaseDifferences);

		$customMessagesArray = array();
		foreach ((array)$updateStatements['change'] as $query) {
			$GLOBALS['TYPO3_DB']->admin_query($query);
			$dbQueries[] = $query;
			if ($GLOBALS['TYPO3_DB']->sql_error()) {
				$customMessagesArray[] = 'SQL-ERROR: ' . htmlspecialchars($GLOBALS['TYPO3_DB']->sql_error());
			}
		}

		if (!empty($customMessagesArray)) {
			$customMessages = 'Update process not fully processed. This can happen because of dependencies of table fields and ' .
				'indexes. Please repeat this step! Following errors occurred:' . LF . LF . implode(LF, $customMessagesArray);
		}

		return count($customMessagesArray) === 0;
	}
}
