<?php

/**
 * This file is part of Zwii.
 * For full copyright and license information, please see the LICENSE
 * file that was distributed with this source code.
 *
 * @author Rémi Jean <remi.jean@outlook.com>
 * @copyright Copyright (C) 2008-2018, Rémi Jean
 * @author Frédéric Tempez <frederic.tempez@outlook.com>
 * @copyright Copyright (C) 2018-2023, Frédéric Tempez
 * @license CC Attribution-NonCommercial-NoDerivatives 4.0 International
 * @link http://zwiicms.fr/
 */


class install extends common
{

	public static $actions = [
		'index' => self::GROUP_VISITOR,
		"postinstall" => self::GROUP_VISITOR,
		'steps' => self::GROUP_ADMIN,
		'update' => self::GROUP_ADMIN
	];

	// Type de proxy
	public static $proxyType = [
		'tcp://' => 'TCP',
		'http://' => 'HTTP'
	];

	// Thèmes proposés à l'installation
	public static $themes = [];

	public static $newVersion;

	// Fichiers des Interface
	public static $i18nFiles = [];

	/**
	 * Pré-installation - choix de la langue
	 */
	public function index()
	{
		// Accès refusé
		if ($this->getData(['user']) !== []) {
			// Valeurs en sortie
			$this->addOutput([
				'access' => false
			]);
		}
		// Accès autorisé
		else {
			// Soumission du formulaire
			if ($this->isPost()) {
				$lang = $this->getInput('installLanguage');
				setcookie('ZWII_UI', $lang, time() + 3600, helper::baseUrl(false, false), '', helper::isHttps(), true);
				// Valeurs en sortie
				$this->addOutput([
					'redirect' => helper::baseUrl() . 'install/postinstall/' . $lang
				]);
			}
		}

		// Liste des langues UI disponibles
		if (is_dir(self::I18N_DIR)) {
			$dir = getcwd();
			chdir(self::I18N_DIR);
			$files = glob('*.json');
			// Ajouter une clé au tableau avec le code de langue
			foreach ($files as $file) {
				// La langue est-elle référencée ?
				if (array_key_exists(basename($file, '.json'), self::$languages)) {
					self::$i18nFiles[basename($file, '.json')] = self::$languages[basename($file, '.json')];
				}
			}
			chdir($dir);
		}

		$this->addOutput([
			'display' => self::DISPLAY_LAYOUT_LIGHT,
			'title' => helper::translate('Installation'),
			'view' => 'index'
		]);
	}

	/**
	 * post Installation
	 */
	public function postInstall()
	{
		// Accès refusé
		if ($this->getData(['user']) !== []) {
			// Valeurs en sortie
			$this->addOutput([
				'access' => false
			]);
		}
		// Accès autorisé
		else {
			// Soumission du formulaire
			if ($this->isPost()) {

				$success = true;

				// Validation de la langue transmise
				$lang = array_key_exists($this->getUrl(2), self::$languages) ? $this->getUrl(2) : 'fr_FR';

				// Double vérification pour le mot de passe
				if ($this->getInput('installPassword', helper::FILTER_STRING_SHORT, true) !== $this->getInput('installConfirmPassword', helper::FILTER_STRING_SHORT, true)) {
					self::$inputNotices['installConfirmPassword'] = 'Incorrect';
					$success = false;
				}
				// Utilisateur
				$userFirstname = $this->getInput('installFirstname', helper::FILTER_STRING_SHORT, true);
				$userLastname = $this->getInput('installLastname', helper::FILTER_STRING_SHORT, true);
				$userMail = $this->getInput('installMail', helper::FILTER_MAIL, true);
				$userId = $this->getInput('installId', helper::FILTER_ID, true);

				// Création de l'utilisateur si les données sont complétées.
				// success retour de l'enregistrement des données
				$success = $this->setData([
					'user',
					$userId,
					[
						'firstname' => $userFirstname,
						'forgot' => 0,
						'group' => self::GROUP_ADMIN,
						'lastname' => $userLastname,
						'pseudo' => 'Admin',
						'signature' => 1,
						'mail' => $userMail,
						'password' => $this->getInput('installPassword', helper::FILTER_PASSWORD, true),
						'language' => $lang
					]
				]);

				// Compte créé, envoi du mail et création des données du site
				if ($success) { // Formulaire complété envoi du mail
					// Envoie le mail
					// Sent contient true si réussite sinon code erreur d'envoi en clair
					$sent = $this->sendMail(
						$userMail,
						'Installation de votre site',
						'Bonjour' . ' <strong>' . $userFirstname . ' ' . $userLastname . '</strong>,<br><br>' .
						'Voici les détails de votre installation.<br><br>' .
						'<strong>URL du site :</strong> <a href="' . helper::baseUrl(false) . '" target="_blank">' . helper::baseUrl(false) . '</a><br>' .
						'<strong>Identifiant du compte :</strong> ' . $this->getInput('installId') . '<br>',
						null
					);

					// Nettoyer les cookies de langue d'une précédente installation
					helper::deleteCookie('ZWII_CONTENT');

					// Installation du site de test
					if (
						$this->getInput('installDefaultData', helper::FILTER_BOOLEAN) === false
						&& $lang === 'fr_FR'
					) {
						$this->initData('page', self::$i18nContent, true);
						$this->initData('module', self::$i18nContent, true);
						$this->setData(['module', 'blog', 'posts', 'mon-premier-article', 'userId', $userId]);
						$this->setData(['module', 'blog', 'posts', 'mon-deuxieme-article', 'userId', $userId]);
						$this->setData(['module', 'blog', 'posts', 'mon-troisieme-article', 'userId', $userId]);
					}

					// Jeu réduit pour les pages étrangères
					if ($lang !== 'fr_FR') {
						$this->initData('page', self::$i18nContent, false);
						$this->initData('module', self::$i18nContent, false);
					}

					// Sauvegarder la configuration du Proxy
					$this->setData(['config', 'proxyType', $this->getInput('installProxyType')]);
					$this->setData(['config', 'proxyUrl', $this->getInput('installProxyUrl')]);
					$this->setData(['config', 'proxyPort', $this->getInput('installProxyPort', helper::FILTER_INT)]);

					// Images exemples livrées dans tous les cas
					try {
						// Décompression dans le dossier de fichier temporaires
						if (file_exists(self::TEMP_DIR . 'files.tar.gz')) {
							unlink(self::TEMP_DIR . 'files.tar.gz');
						}
						if (file_exists(self::TEMP_DIR . 'files.tar')) {
							unlink(self::TEMP_DIR . 'files.tar');
						}
						copy('core/module/install/ressource/files.tar.gz', self::TEMP_DIR . 'files.tar.gz');
						$pharData = new PharData(self::TEMP_DIR . 'files.tar.gz');
						$pharData->decompress();
						// Installation
						$pharData->extractTo(__DIR__ . '/../../../', null, true);
					} catch (Exception $e) {
						$success = $e->getMessage();
					}

					// Nettoyage
					unlink(self::TEMP_DIR . 'files.tar.gz');
					unlink(self::TEMP_DIR . 'files.tar');
					helper::deleteCookie('ZWII_UI');


					// Créer le dossier des fontes
					if (!is_dir(self::DATA_DIR . 'fonts')) {
						mkdir(self::DATA_DIR . 'fonts');
					}

					// Installation du thème sélectionné
					$dataThemes = file_get_contents('core/module/install/ressource/themes/themes.json');
					$dataThemes = json_decode($dataThemes, true);
					$themeId = $dataThemes[$this->getInput('installTheme', helper::FILTER_STRING_SHORT)]['filename'];
					if ($themeId !== 'default') {
						$theme = new theme;
						$theme->import('core/module/install/ressource/themes/' . $themeId);
					}

					// Copie des thèmes dans les fichiers
					if (!is_dir(self::FILE_DIR . 'source/theme')) {
						mkdir(self::FILE_DIR . 'source/theme');
					}
					$this->copyDir('core/module/install/ressource/themes', self::FILE_DIR . 'source/theme');
					unlink(self::FILE_DIR . 'source/theme/themes.json');

					// Copie des langues de l'UI et génération de la base de données
					if (is_dir(self::I18N_DIR) === false) {
						mkdir(self::I18N_DIR);
					}

					// Créer la base de données des langues
					copy('core/module/install/ressource/i18n/languages.json', self::DATA_DIR . 'languages.json');
					$this->copyDir('core/module/install/ressource/i18n', self::I18N_DIR);
					unlink(self::I18N_DIR . 'languages.json');

					// Créer sitemap
					$this->createSitemap();
					// Mise à jour de la liste des pages pour TinyMCE
					$this->listPages();

					// Valeurs en sortie
					$this->addOutput([
						'redirect' => helper::baseUrl(false),
						'notification' => $sent === true ? helper::translate('Installation terminée') : $sent,
						'state' => ($sent === true && $success === true) ? true : null
					]);
				}
			}

			// Affichage du formulaire

			// Récupération de la liste des thèmes
			$dataThemes = file_get_contents('core/module/install/ressource/themes/themes.json');
			$dataThemes = json_decode($dataThemes, true);
			self::$themes = helper::arrayColumn($dataThemes, 'name');

			// Valeurs en sortie
			$this->addOutput([
				'display' => self::DISPLAY_LAYOUT_LIGHT,
				'title' => helper::translate('Installation'),
				'view' => 'postinstall'
			]);
		}
	}

	/**
	 * Étapes de mise à jour
	 */
	public function steps()
	{
		switch ($this->getInput('step', helper::FILTER_INT)) {
			// Préparation
			case 1:
				$success = true;
				// RAZ la mise à jour auto
				$this->setData(['core', 'updateAvailable', false]);
				// Backup du dossier Data
				helper::autoBackup(self::BACKUP_DIR, ['backup', 'tmp', 'file']);
				// Sauvegarde htaccess
				if ($this->getData(['config', 'autoUpdateHtaccess'])) {
					$success = copy('.htaccess', '.htaccess' . '.bak');
				}
				// Nettoyage des fichiers d'installation précédents
				if (file_exists(self::TEMP_DIR . 'update.tar.gz') && $success) {
					$success = unlink(self::TEMP_DIR . 'update.tar.gz');
				}
				if (file_exists(self::TEMP_DIR . 'update.tar') && $success) {
					$success = unlink(self::TEMP_DIR . 'update.tar');
				}
				// Valeurs en sortie
				$this->addOutput([
					'display' => self::DISPLAY_JSON,
					'content' => [
						'success' => $success,
						'data' => null
					]
				]);
				break;
			// Téléchargement
			case 2:
				file_put_contents(self::TEMP_DIR . 'update.tar.gz', helper::getUrlContents(common::ZWII_UPDATE_URL . common::ZWII_UPDATE_CHANNEL . '/update.tar.gz'));
				$md5origin = helper::getUrlContents(common::ZWII_UPDATE_URL . common::ZWII_UPDATE_CHANNEL . '/update.md5');
				$md5origin = (explode(' ', $md5origin));
				$md5target = md5_file(self::TEMP_DIR . 'update.tar.gz');
				// Valeurs en sortie
				$this->addOutput([
					'display' => self::DISPLAY_JSON,
					'content' => [
						'success' => $md5origin[0] === $md5target,
						'data' => null
					]
				]);
				break;
			// Installation
			case 3:
				$success = true;
				// Check la réécriture d'URL avant d'écraser les fichiers
				$rewrite = helper::checkRewrite();
				// Décompression et installation
				try {
					// Décompression dans le dossier de fichier temporaires
					$pharData = new PharData(self::TEMP_DIR . 'update.tar.gz');
					$pharData->decompress();
					// Installation
					$pharData->extractTo(__DIR__ . '/../../../', null, true);
				} catch (Exception $e) {
					$success = $e->getMessage();
				}
				// Nettoyage du dossier
				if (file_exists(self::TEMP_DIR . 'update.tar.gz')) {
					unlink(self::TEMP_DIR . 'update.tar.gz');
				}
				if (file_exists(self::TEMP_DIR . 'update.tar')) {
					unlink(self::TEMP_DIR . 'update.tar');
				}
				// Valeurs en sortie
				$this->addOutput([
					'display' => self::DISPLAY_JSON,
					'content' => [
						'success' => $success,
						'data' => $rewrite
					]
				]);
				break;
			// Configuration
			case 4:
				$success = true;
				$rewrite = $this->getInput('data');
				// Réécriture d'URL
				if ($rewrite === "true") { // Ajout des lignes dans le .htaccess
					$fileContent = file_get_contents('.htaccess');
					$rewriteData = PHP_EOL .
						'# URL rewriting' . PHP_EOL .
						'<IfModule mod_rewrite.c>' . PHP_EOL .
						"\tRewriteEngine on" . PHP_EOL .
						"\tRewriteBase " . helper::baseUrl(false, false) . PHP_EOL .
						"\tRewriteCond %{REQUEST_FILENAME} !-f" . PHP_EOL .
						"\tRewriteCond %{REQUEST_FILENAME} !-d" . PHP_EOL .
						"\tRewriteRule ^(.*)$ index.php?$1 [L]" . PHP_EOL .
						'</IfModule>' . PHP_EOL .
						'# URL rewriting' . PHP_EOL;
					$fileContent = str_replace('# URL rewriting', $rewriteData, $fileContent);
					file_put_contents(
						'.htaccess',
						$fileContent
					);
				}
				// Recopie htaccess
				if (
					$this->getData(['config', 'autoUpdateHtaccess']) &&
					$success && file_exists('.htaccess.bak')
				) {
					// L'écraser avec le backup
					$success = copy('.htaccess.bak', '.htaccess');
					// Effacer le backup
					unlink('.htaccess.bak');
				}

				/**
				 * Met à jour les dictionnaires des langues depuis les modèles installés
				 */

				// Langues installées
				$installedUI = $this->getData(['languages']);

				// Langues disponibles avec la mise à jour
				$store = json_decode(file_get_contents('core\module\install\ressource\i18n\languages.json'), true);
				$store = $store['languages'];

				foreach ($installedUI as $key => $value) {
					if ($store[$key]['version'] > $value['version']) {
						echo copy('core/module/install/ressource/i18n/' . $key . '.json', self::I18N_DIR . $key . '.json');
						$this->setData(['languages', $key, $store[$key]]);
					}
				}

				// Valeurs en sortie
				$this->addOutput([
					'display' => self::DISPLAY_JSON,
					'content' => [
						'success' => $success,
						'data' => null
					]
				]);
		}
	}

	/**
	 * Mise à jour
	 */
	public function update()
	{
		// Nouvelle version
		self::$newVersion = helper::getUrlContents(common::ZWII_UPDATE_URL . common::ZWII_UPDATE_CHANNEL . '/version');
		// Valeurs en sortie
		$this->addOutput([
			'display' => self::DISPLAY_LAYOUT_LIGHT,
			'title' => helper::translate('Mise à jour'),
			'view' => 'update'
		]);
	}

}