<?php
declare(strict_types = 1);

/**
 * Gestion du mode sélection.
 *
 * @license https://www.gnu.org/licenses/gpl-3.0.html
 * @link https://www.igalerie.org/
 */
class Selection
{
	/**
	 * Nombre maximum de fichiers qu'un invité peut placer dans sa sélection.
	 *
	 * @var int
	 */
	CONST GUEST_MAX_ITEMS = 100;



	/**
	 * Ajoute des fichiers à la sélection.
	 *
	 * @param array $items_id
	 *   Identifiants des fichiers.
	 *
	 * @return int
	 *   Retourne le nombre de fichiers ajoutés,
	 *   ou -1 en cas d'erreur.
	 */
	public static function add(array $items_id): int
	{
		return self::_action('add', $items_id);
	}

	/**
	 * Supprime tous les fichiers de la sélection.
	 *
	 * @return int
	 *   Retourne le nombre de fichiers supprimés,
	 *   ou -1 en cas d'erreur.
	 */
	public static function delete(): int
	{
		if (Auth::$connected)
		{
			if (!DB::execute('DELETE FROM {selection} WHERE user_id = ?', Auth::$id))
			{
				return -1;
			}
			$count = DB::rowCount();
		}
		else
		{
			$count = count(self::getCookieItems());
			Auth::$prefs->delete('selection_items');
		}

		return (int) $count;
	}

	/**
	 * Le mode sélection est-il activé pour l'utilisateur actuel ?
	 *
	 * @return bool
	 */
	public static function isActivated(): bool
	{
		return Config::$params['selection'] && Config::$params['download_item']
			&& (!Config::$params['users'] || (Auth::$groupPerms['selection']
			&& Auth::$groupPerms['image_original']));
	}

	/**
	 * Retourne les identifiants des fichiers
	 * se trouvant dans la sélection d'un invité.
	 *
	 * @return array
	 */
	public static function getCookieItems(): array
	{
		$items_id = [];
		if (!empty($selection_items = Auth::$prefs->read('selection_items')))
		{
			$selection_items = explode(',', $selection_items);
			foreach ($selection_items as &$item)
			{
				if (count($items_id) >= self::GUEST_MAX_ITEMS)
				{
					break;
				}
				if (preg_match('`^\d{1,12}$`', (string) $item) && !in_array($item, $items_id))
				{
					$items_id[] = (int) $item;
				}
			}
		}
		return $items_id;
	}

	/**
	 * Retourne les identifiants des fichiers
	 * se trouvant dans la sélection.
	 *
	 * @return array
	 */
	public static function getItems(): array
	{
		$sql = '';
		if (Auth::$connected)
		{
			$sql = 'FROM {selection} AS sel
			   LEFT JOIN {items} AS i
					  ON sel.item_id = i.item_id
			   LEFT JOIN {categories} AS cat
					  ON i.cat_id = cat.cat_id
				   WHERE sel.user_id = :user_id';
			DB::params(['user_id' => Auth::$id]);
		}
		else if ($items_id = self::getCookieItems())
		{
			$sql = 'FROM {items} AS i
			   LEFT JOIN {categories} AS cat
					  ON i.cat_id = cat.cat_id
				   WHERE i.item_id IN (' . DB::inInt($items_id) . ')';
		}
		if ($sql)
		{
			$sql = "SELECT i.item_id
					  $sql
					   AND " . SQL::catPerms() . "
					   AND " . SQL::catPassword();
			if (DB::execute($sql))
			{
				return DB::fetchCol('item_id');
			}
		}
		return [];
	}

	/**
	 * Retourne la sous-requête SQL qui permet de déterminer
	 * si un fichier se trouve dans la sélection.
	 *
	 * @return string
	 */
	public static function getSQLItem(): string
	{
		$sql = '0';
		if (self::isActivated())
		{
			if (Auth::$connected)
			{
				$sql = 'SELECT 1
						  FROM {selection} AS sel
					     WHERE sel.item_id = i.item_id
						   AND sel.user_id = ' . Auth::$id . '
					     LIMIT 1';
			}
			else
			{
				$items_id = Auth::$prefs->read('selection_items');
				$regexp = '`^\d{1,12}(?:,\d{1,12}){0,' . self::GUEST_MAX_ITEMS . '}$`';
				if (preg_match($regexp, $items_id))
				{
					$items_id = DB::inInt(explode(',', $items_id));
					$sql = "SELECT CASE WHEN i.item_id IN ($items_id) THEN '1' ELSE '0' END";
				}
			}
		}
		return $sql;
	}

	/**
	 * Retourne les statistiques des fichiers se trouvant dans la sélection.
	 *
	 * @return array
	 */
	public static function getStats(): array
	{
		$stats = ['count' => 0, 'filesize' => 0];
		$sql = '';
		if (Auth::$connected)
		{
			$sql = 'FROM {selection} AS sel
			   LEFT JOIN {items} AS i
					  ON sel.item_id = i.item_id
			   LEFT JOIN {categories} AS cat
					  ON i.cat_id = cat.cat_id
				   WHERE sel.user_id = :user_id';
			DB::params(['user_id' => Auth::$id]);
		}
		else if ($items_id = self::getCookieItems())
		{
			$sql = 'FROM {items} AS i
			   LEFT JOIN {categories} AS cat
					  ON i.cat_id = cat.cat_id
				   WHERE item_id IN (' . DB::inInt($items_id) . ')';
		}
		if ($sql)
		{
			$sql = "SELECT COUNT(*) AS count,
						   SUM(item_filesize) AS filesize
						   $sql
					   AND " . SQL::catPerms() . "
					   AND " . SQL::catPassword();
			if (DB::execute($sql))
			{
				$stats = DB::fetchRow();
			}
		}
		$stats['filesize'] = (int) $stats['filesize'];
		$stats['filesize_formated'] = L10N::formatFilesize($stats['filesize']);
		return $stats;
	}

	/**
	 * Retire des fichiers de la sélection.
	 *
	 * @param array $items_id
	 *   Identifiants des fichiers.
	 *
	 * @return int
	 *   Retourne le nombre de fichiers retirés,
	 *   ou -1 en cas d'erreur.
	 */
	public static function remove(array $items_id): int
	{
		return self::_action('remove', $items_id);
	}



	/**
	 * Ajoute ou retire des fichiers à la sélection.
	 *
	 * @param string $action
	 *   Action à effectuer : 'add' ou 'remove'.
	 * @param array $items_id
	 *   Identifiants des fichiers.
	 *
	 * @return int
	 *   Retourne le nombre de fichier affectés,
	 *   ou -1 en cas d'erreur.
	 */
	private static function _action(string $action, array $items_id): int
	{
		if (!$items_id)
		{
			return 0;
		}

		// Vérification de l'existence des fichiers et des permissions d'accès.
		$sql = 'SELECT item_id,
					   password_id
				  FROM {items} AS i
			 LEFT JOIN {categories} AS cat USING (cat_id)
				 WHERE item_id IN (' . DB::inInt($items_id) . ')
				   AND ' . SQL::catPerms() . '
				   AND ' . SQL::catPassword();
		if (!DB::execute($sql))
		{
			return -1;
		}
		if (!$items_id = DB::fetchCol('item_id'))
		{
			return 0;
		}

		// Membres.
		if (Auth::$connected)
		{
			$user_id = Auth::$id;
			$sql = $action == 'add'
				? "INSERT IGNORE INTO {selection}
					(user_id, item_id, selection_date) VALUES ($user_id, ?, NOW())"
				: "DELETE FROM {selection} WHERE user_id = $user_id AND item_id = ?";
			if (!DB::execute($sql, array_map(function($v){return[$v];}, $items_id)))
			{
				return -1;
			}

			$items_affected = DB::rowCount();
		}

		// Invités.
		else
		{
			$items_affected = 0;
			$items_id_prefs = [];
			$add_items = function(array $array, bool $count = FALSE)
			use (&$items_affected, &$items_id_prefs): void
			{
				foreach ($array as &$item)
				{
					if (count($items_id_prefs) >= self::GUEST_MAX_ITEMS)
					{
						break;
					}
					if (preg_match('`^\d{1,12}$`', (string) $item)
					&& !in_array($item, $items_id_prefs))
					{
						$items_id_prefs[] = (int) $item;
						if ($count)
						{
							$items_affected++;
						}
					}
				}
			};
			$remove_items = function(array $array, bool $count = FALSE)
			use (&$items_affected, &$items_id_prefs): void
			{
				foreach ($array as &$item)
				{
					if (preg_match('`^\d{1,12}$`', (string) $item)
					&& ($key = array_search($item, $items_id_prefs)) !== FALSE)
					{
						unset($items_id_prefs[$key]);
						if ($count)
						{
							$items_affected++;
						}
					}
				}
			};

			if (!empty($selection_items = Auth::$prefs->read('selection_items')))
			{
				$add_items(explode(',', $selection_items));
			}
			if ($action == 'add')
			{
				$add_items($items_id, TRUE);
			}
			else
			{
				$remove_items($items_id, TRUE);
			}

			Auth::$prefs->add('selection_items', implode(',', $items_id_prefs));
		}

		return $items_affected;
	}
}
?>