<?php
declare(strict_types = 1);

/**
 * Méthodes de base de données pour PostgreSQL.
 *
 * @license https://www.gnu.org/licenses/gpl-3.0.html
 * @link https://www.igalerie.org/
 */
class DBLayer
{
	/**
	 * Nom du SGBD.
	 *
	 * @var string
	 */
	const NAME = 'PostgreSQL';

	/**
	 * Numéro de port du serveur par défaut.
	 *
	 * @var string
	 */
	const PORT_DEFAULT = '5432';

	/**
	 * Version minimale requise.
	 *
	 * @var string
	 */
	const VERSION_MIN = '9.5';



	/**
	 * Retourne des informations sur la base de données.
	 *
	 * @return array
	 */
	public static function getDetails(): array
	{
		return [];
	}

	/**
	 * Nettoie la base de données.
	 *
	 * @return bool
	 */
	public static function vacuum(): bool
	{
		return DB::execute('VACUUM');
	}



	/**
	 * Retourne le DSN pour se connecter à la base de données.
	 *
	 * @return string
	 */
	protected static function _getDSN(): string
	{
		return CONF_DB_TYPE . ':host=' . CONF_DB_HOST . ';port='
			 . CONF_DB_PORT . ';dbname=' . CONF_DB_NAME;
	}

	/**
	 * Paramètres d'initialisation.
	 *
	 * @param PDO $pdo
	 *
	 * @return bool
	 */
	protected static function _initialize(PDO $pdo): bool
	{
		return TRUE;
	}

	/**
	 * Nom de la séquence d'objets (uniquement pour PostgreSQL).
	 *
	 * @param array $seq
	 *
	 * @return mixed
	 */
	protected static function _seqName(array $seq = [])
	{
		return $seq ? $seq['table'] . '_' . $seq['column'] . '_seq' : NULL;
	}

	/**
	 * Code SQL à remplacer.
	 *
	 * @param string $sql
	 *
	 * @return string
	 */
	protected static function _replaceSQL(string $sql): string
	{
		// Remplacement de la fonction NOW().
		if (CONF_DB_DATE == 'php')
		{
			$sql = str_replace("NOW()", "'" . date('Y-m-d H:i:s') . "'::timestamp", $sql);
		}

		// INSERT IGNORE => ON CONFLICT DO NOTHING.
		if (strstr($sql, 'INSERT IGNORE'))
		{
			$sql = str_replace('INSERT IGNORE', 'INSERT', $sql) . ' ON CONFLICT DO NOTHING';
		}

		// ALTER TABLE ... MODIFY ...
		$sql = preg_replace(
			'`ALTER\s+TABLE\s+([^\s]+)\s+MODIFY\s+([^\s]+)\s+(.+)`',
			'ALTER TABLE $1 ALTER COLUMN $2 TYPE $3',
			$sql
		);

		// Clause LIMIT.
		$sql = preg_replace('`LIMIT\s+(\d+),(\d+)`', 'LIMIT $2 OFFSET $1', $sql);

		// Addition de deux dates.
		$sql = preg_replace(
			'`DATE_ADD\(([^,]+),\s*INTERVAL\s+([^\)]+)\)`',
			'($1 + \'$2\')',
			$sql
		);

		// Conversion d'une date en secondes.
		$sql = str_replace(#1
			'TO_SECONDS(NOW())',
			'EXTRACT(EPOCH FROM localtimestamp::timestamp)',
			$sql
		);
		$sql = preg_replace(#2
			'`TO_SECONDS\(([^)]+)\)`',
			'EXTRACT(EPOCH FROM $1::timestamp)',
			$sql
		);

		// DATE_FORMAT() => to_char().
		$sql = preg_replace_callback('`DATE_FORMAT\(([^,]+),\s*([^\)]+)\)`', function($m)
		{
			$format = str_replace(['%Y', '%m', '%d', '%H', '%M', '%S'],
				['YYYY', 'MM', 'DD', 'HH24', 'MI', 'SS'], $m[2]);
			return sprintf('to_char(%s, %s)', $m[1], $format);
		}, $sql);

		// Autres parties à remplacer.
		$sql = strtr($sql,
		[
			'DATETIME' => 'TIMESTAMP',
			'INTEGER PRIMARY KEY AUTO_INCREMENT' => 'SERIAL PRIMARY KEY',
			'NOT REGEXP' => '!~*',
			'NOW()' => "date_trunc('second', localtimestamp)",
			'RAND()' => 'RANDOM()',
			'REGEXP' => '~*',
			'REGEXP_REPLACE' => 'REGEXP_REPLACE'
		]);

		return $sql;
	}
}
?>