<?php
declare(strict_types = 1);

require_once(__DIR__ . '/AdminAlbums.class.php');

/**
 * Gestion des catégories.
 *
 * @license https://www.gnu.org/licenses/gpl-3.0.html
 * @link https://www.igalerie.org/
 */
class AdminCategory extends AdminAlbums
{
	/**
	 * Actions sur la sélection de catégories.
	 *
	 * @return void
	 */
	public static function actions(): void
	{
		if (isset($_POST['cancel']) || !isset($_POST['selection']))
		{
			return;
		}
		switch ($action = self::_getSelectedIds($selected_ids))
		{
			case 'activate' :
			case 'activate_reset_item_pubdt' :
				$r = Category::status($selected_ids, 1, $action == 'activate_reset_item_pubdt');
				if ($r < 0)
				{
					Report::error();
				}
				else if ($r < 1)
				{
					Report::info(__('Aucune catégorie n\'a été activée.'));
				}
				else
				{
					Report::success($r > 1
						? sprintf(__('%s catégories ont été activées.'), $r)
						: __('1 catégorie a été activée.'));
				}
				break;

			case 'deactivate' :
				$r = Category::status($selected_ids, 0);
				if ($r < 0)
				{
					Report::error();
				}
				else if ($r < 1)
				{
					Report::info(__('Aucune catégorie n\'a été désactivée.'));
				}
				else
				{
					Report::success($r > 1
						? sprintf(__('%s catégories ont été désactivées.'), $r)
						: __('1 catégorie a été désactivée.'));
				}
				break;

			case 'delete' :
				$r = Category::delete($selected_ids);
				if ($r < 0)
				{
					Report::error();
				}
				else if ($r < 1)
				{
					Report::info(__('Aucune catégorie n\'a été supprimée.'));
				}
				else
				{
					Report::success($r > 1
						? sprintf(__('%s catégories ont été supprimées.'), $r)
						: __('1 catégorie a été supprimée.'));
				}
				break;

			case 'move' :
				$r = Category::move($selected_ids, (int) $_POST['cat_id']);
				if ($r < 0)
				{
					Report::error();
				}
				else if ($r < 1)
				{
					Report::info(__('Aucune catégorie n\'a été déplacée.'));
				}
				else
				{
					Report::success($r > 1
						? sprintf(__('%s catégories ont été déplacées.'), $r)
						: __('1 catégorie a été déplacée.'));
				}
				break;

			case 'owner' :
			case 'reset_hits' :
				$r = $_POST['action'] == 'owner'
					? Category::owner($selected_ids, (int) $_POST['user_id'])
					: Category::resetHits($selected_ids);
				if ($r < 0)
				{
					Report::error();
				}
				else if ($r < 1)
				{
					Report::info(__('Aucune catégorie n\'a été modifiée.'));
				}
				else
				{
					Report::success($r > 1
						? sprintf(__('%s catégories ont été modifiées.'), $r)
						: __('1 catégorie a été modifiée.'));
				}
				break;
		}
	}

	/**
	 * Change les propriétés d'une catégorie
	 * (état, catégorie parente, propriétaire, nombre de vues).
	 *
	 * @return void
	 */
	public static function change(): void
	{
		$id = (int) $_GET['category_id'];

		if (!isset($_POST[$id]) || !isset($_POST['save']))
		{
			return;
		}

		Report::noChange();

		$r = function($r)
		{
			if ($r < 0)
			{
				Report::error();
			}
			if ($r > 0)
			{
				Report::success();
			}
		};

		if (isset($_POST[$id]['status']))
		{
			$r(Category::status([$id], (int) $_POST[$id]['status']),
				!empty($_POST[$id]['reset_item_pubdt']));
		}

		if (isset($_POST[$id]['category_parent']))
		{
			$r(Category::move([$id], (int) $_POST[$id]['category_parent']));
		}

		if (isset($_POST[$id]['owner']))
		{
			$r(Category::owner([$id], (int) $_POST[$id]['owner']));
		}

		if (isset($_POST[$id]['reset_hits']))
		{
			$r(Category::resetHits([$id]));
		}
	}

	/**
	 * Supprime une catégorie.
	 *
	 * @return void
	 */
	public static function delete(): void
	{
		if (isset($_POST['delete']) && Category::delete([(int) $_GET['category_id']]) == -1)
		{
			Report::error();
		}
	}

	/**
	 * Édite des informations.
	 *
	 * @return void
	 */
	public static function edit(): void
	{
		if (!$_POST || !isset($_POST['save']))
		{
			return;
		}

		App::checkboxes($_POST);

		$r = Category::edit($_POST);
		if ($r < 0)
		{
			Report::error();
			return;
		}

		if ($r < 1)
		{
			if ($_GET['section'] == 'category')
			{
				Report::info(__('Aucune catégorie n\'a été modifiée.'));
			}
		}
		else
		{
			if ($_GET['section'] == 'category')
			{
				Report::success($r > 1
					? sprintf(__('%s catégories ont été modifiées.'), $r)
					: __('1 catégorie a été modifiée.'));
			}
			else
			{
				Report::success();
			}
		}

		$_POST = [];
	}

	/**
	 * Édite les coordonnées de géolocalisation.
	 *
	 * @return void
	 */
	public static function editGeolocation(): void
	{
		$id = (int) $_GET['category_id'];

		if (!isset($_POST[$id]) || !isset($_POST['save'])
		 || !isset($_POST[$id]['latitude']) || is_array($_POST[$id]['latitude'])
		 || !isset($_POST[$id]['longitude']) || is_array($_POST[$id]['longitude']))
		{
			return;
		}

		$lat = Utility::trimAll((string) $_POST[$id]['latitude']);
		$long = Utility::trimAll((string) $_POST[$id]['longitude']);
		if ($lat !== '' || $long !== '')
		{
			if (is_string($coords = Geolocation::checkCoordinates($lat, $long)))
			{
				$_POST = [];
				Report::warning($coords);
				return;
			}
		}

		$r = Geolocation::editCategories([$id => $_POST[$id]]);
		if ($r < 0)
		{
			Report::error();
			return;
		}

		if ($r < 1)
		{
			Report::noChange();
		}
		else
		{
			Report::success();
		}

		$_POST = [];
	}

	/**
	 * Récupération des catégories de la page courante.
	 *
	 * @return void
	 */
	public static function getCategories(): void
	{
		$user_prefs = Auth::$infos['user_prefs']['category'];

		if ($user_prefs['display'] == 'grid')
		{
			if ($_GET['q_pageless'] != $_GET['q'])
			{
				App::redirect($_GET['q_pageless']);
			}
			return;
		}

		// Nombre de catégories par page.
		$nb_per_page = $user_prefs['nb_per_page'];

		// Clause WHERE.
		if (isset($_GET['search']) && ($search = self::sqlWhereCategories()))
		{
			$sql_where = $search['sql'];
			$params = $search['params'];

			// Limitation à la catégorie courante.
			if (Template::$data['category']['id'] > 1)
			{
				$sql_where .= " AND cat_path LIKE :path";
				$params['path'] = DB::likeEscape(Template::$data['category']['path']) . '/%';
			}
		}
		else
		{
			$sql_where = "cat.parent_id = " . (int) $_GET['category_id'];
			$params = [];
		}

		// Clause LIMIT.
		$sql_limit = $nb_per_page * ($_GET['page'] - 1) . ",$nb_per_page";

		// Clause ORDER BY.
		$sql_order_by = self::getOrderBy(
			$user_prefs['order_by_column'],
			$user_prefs['order_by_order']
		);

		// Nombre de pages.
		if (isset($_GET['search']))
		{
			$sql = "SELECT COUNT(*) FROM {categories} AS cat WHERE $sql_where";
			if (!DB::execute($sql, $params))
			{
				return;
			}
			Template::$data['objects_count'] = DB::fetchVal();
		}
		Template::set('nb_pages', ceil(Template::$data['objects_count'] / $nb_per_page));

		// Récupération des catégories.
		$sql = "SELECT cat.*,
					   cat.cat_tb_params AS tb_params,
					   cat.cat_a_images + cat.cat_d_images AS cat_images,
					   cat.cat_a_videos + cat.cat_d_videos AS cat_videos,
					   cat_a_subalbs + cat_d_subalbs +
					   cat_a_subcats + cat_d_subcats AS cat_subcats,
					   CASE WHEN cat_filemtime IS NULL
							THEN 'category' ELSE 'album'
							 END AS cat_type,
					   i.item_id,
					   i.item_type,
					   i.item_path,
					   i.item_width,
					   i.item_height,
					   i.item_orientation,
					   i.item_adddt,
					   i.item_tb_params,
					   u.user_login,
					   u.user_nickname,
					   u.user_status,
					   p.cat_id AS p_cat_id
				  FROM {categories} AS cat
			 LEFT JOIN {users} AS u
					ON cat.user_id = u.user_id
			 LEFT JOIN {items} AS i
					ON cat.thumb_id = i.item_id
			 LEFT JOIN {passwords} AS p
				    ON cat.password_id = p.password_id
				 WHERE $sql_where
				   AND cat.cat_id > 1
			  ORDER BY $sql_order_by
			     LIMIT $sql_limit";
		if (!DB::execute($sql, $params))
		{
			return;
		}
		$categories = DB::fetchAll('cat_id');
		if (!self::_objectsNoResult(count($categories)))
		{
			return;
		}

		// Réglages des catégories.
		Parents::settings($categories);

		// Formatage des informations pour le template.
		foreach ($categories as &$i)
		{
			$formated_infos[] = self::getFormatedInfos($i);
		}
		Template::set('categories', $formated_infos);
	}

	/**
	 * Formate les informations d'une catégorie.
	 *
	 * @param array $i
	 *   Informations brutes de la catégorie.
	 * @param array $parents_infos
	 *   Informations brutes des catégories parentes.
	 *
	 * @return array
	 */
	public static function getFormatedInfos(array &$i, array &$parents_infos = []): array
	{
		$cat_type = $i['cat_filemtime'] === NULL ? 'category' : 'album';

		$is_geolocation_post_lat = (isset($_POST[$i['cat_id']]['latitude'])
			&& !Utility::isEmpty($_POST[$i['cat_id']]['latitude']));
		$is_geolocation_post_long = (isset($_POST[$i['cat_id']]['longitude'])
			&& !Utility::isEmpty($_POST[$i['cat_id']]['longitude']));

		return
		[
			// Paramètres de base.
			'id' => $i['cat_id'],
			'is_empty' => $i['thumb_id'] == -1,
			'parent_id' => $i['parent_id'],
			'gallery_link' => $i['cat_id'] > 1 && $i['cat_status']
				&& ($i['cat_a_images'] + $i['cat_a_videos']) > 0
				? App::getURLGallery($cat_type . '/' . $i['cat_id'])
				: NULL,
			'link' => App::getURL($cat_type . '/' . $i['cat_id']),
			'path' => $i['cat_path'],
			'type' => $cat_type,
			'type_text' => $cat_type == 'album' ? __('Album') : __('Catégorie'),

			// Propriétaire.
			'user_id' => $i['user_id'],
			'user_link' => App::getURL('user/' . $i['user_id']),
			'user_nickname' => User::getNickname($i['user_login'], $i['user_nickname']),

			// Dates.
			'crtdt' => L10N::dt(__('%A %d %B %Y à %H:%M:%S'), $i['cat_crtdt']),

			// Géolocalisation.
			'geolocation' =>
			[
				'latitude' => $is_geolocation_post_lat
					? $_POST[$i['cat_id']]['latitude']
					: $i['cat_lat'],
				'latitude_map' => $is_geolocation_post_lat
					? $_POST[$i['cat_id']]['latitude']
					: ($i['cat_lat']
						?? Config::$params['pages_params']['worldmap']['center_lat']),
				'longitude' => $is_geolocation_post_long
					? $_POST[$i['cat_id']]['longitude']
					: $i['cat_long'],
				'longitude_map' => $is_geolocation_post_long
					? $_POST[$i['cat_id']]['longitude']
					: ($i['cat_long']
						?? Config::$params['pages_params']['worldmap']['center_long']),
				'marker' => (int) ($i['cat_lat'] !== NULL && $i['cat_long'] !== NULL)
			],

			// État.
			'activated' => $i['cat_status'] == 1,
			'deactivated' => $i['cat_status'] == 0,
			'status_text' => L10N::getTextStatus((int) $i['cat_status']),

			// Vignette.
			'thumb_file' => $i['thumb_id'] == 0
				? App::getFileSource('/cache/external/'
					. App::hashFilename((string) $i['cat_id'], ['ext']))
				: App::getFileSource((string) $i['item_path']),
			'thumb_id' => $i['thumb_id'],
			'thumb_mime' => Item::getTypeMime($i['item_type']),
			'thumb_size' => function(int $max_width, int $max_height) use ($i): array
			{
				return Image::getResizedSize((int) $i['item_width'],
					(int) $i['item_height'], $max_width, $max_height,
					(int) $i['item_orientation']);
			},
			'thumb_src' => function() use ($i)
			{
				$thumb_src = ($i['thumb_id'] == -1)
					? ''
					: App::getThumbSource('cat', $i, self::$thumbSize, self::$thumbQuality);
				return htmlspecialchars($thumb_src);
			},
			'thumb_type' => Item::isVideo($i['item_type']) ? 'video' : 'image',

			// Informations.
			'description' => $_POST[$i['cat_id']]['item_desc'] ?? $i['cat_desc'],
			'dirname' => $_POST[$i['cat_id']]['cat_path'] ?? basename($i['cat_path']),
			'title' => $_POST[$i['cat_id']]['cat_name'] ?? $i['cat_name'],
			'url' => $_POST[$i['cat_id']]['cat_url'] ?? $i['cat_url'],

			// Statistiques.
			'stats' => self::getFormatedStats($i),

			// Réglages : permissions.
			'commentable' => self::_getPermission($i, 'commentable'),
			'creatable' => self::_getPermission($i, 'creatable'),
			'downloadable' => self::_getPermission($i, 'downloadable'),
			'uploadable' => self::_getPermission($i, 'uploadable'),
			'votable' => self::_getPermission($i, 'votable'),
			'parent_commentable' => (int) ($i['parent_commentable'] ?? 0),
			'parent_creatable' => (int) ($i['parent_creatable'] ?? 0),
			'parent_downloadable' => (int) ($i['parent_downloadable'] ?? 0),
			'parent_uploadable' => (int) ($i['parent_uploadable'] ?? 0),
			'parent_votable' => (int) ($i['parent_votable'] ?? 0),

			// Réglages : critères de tri.
			'orderby_1' => self::_getFormatedOrderBy($i, 'orderby_1'),
			'orderby_2' => self::_getFormatedOrderBy($i, 'orderby_2'),
			'orderby_3' => self::_getFormatedOrderBy($i, 'orderby_3'),
			'sortby_1' => self::_getFormatedOrderBy($i, 'sortby_1'),
			'sortby_2' => self::_getFormatedOrderBy($i, 'sortby_2'),
			'sortby_3' => self::_getFormatedOrderBy($i, 'sortby_3'),

			// Mot de passe.
			'password' => self::_getPassword($i),
			'password_parent' => self::_getPasswordParent('', $i, $parents_infos, FALSE),
			'password_parent_link' => self::_getPasswordParent('link', $i, $parents_infos, FALSE),
			'password_parent_name' => self::_getPasswordParent('name', $i, $parents_infos, FALSE)
		];
	}

	/**
	 * Formate les statistiques d'une catégorie.
	 *
	 * @param array $i
	 *   Informations brutes de la catégorie.
	 *
	 * @return array
	 */
	public static function getFormatedStats(array &$i): array
	{
		$a_items = (int) ($i['cat_a_images'] + $i['cat_a_videos']);
		$d_items = (int) ($i['cat_d_images'] + $i['cat_d_videos']);
		$subcats = (int) ($i['cat_a_subalbs'] + $i['cat_d_subalbs']
				 + $i['cat_a_subcats'] + $i['cat_d_subcats']);

		return
		[
			// Albums.
			'a_albums' => L10N::formatNumber((int) $i['cat_a_albums']),
			'd_albums' => L10N::formatNumber((int) $i['cat_d_albums']),
			't_albums' => L10N::formatNumber((int) ($i['cat_a_albums'] + $i['cat_d_albums'])),

			// Photos.
			'a_images' => L10N::formatNumber((int) $i['cat_a_images']),
			'd_images' => L10N::formatNumber((int) $i['cat_d_images']),
			't_images' => L10N::formatNumber((int) ($i['cat_a_images'] + $i['cat_d_images'])),

			// Vidéos.
			'a_videos' => L10N::formatNumber((int) $i['cat_a_videos']),
			'd_videos' => L10N::formatNumber((int) $i['cat_d_videos']),
			't_videos' => L10N::formatNumber((int) ($i['cat_a_videos'] + $i['cat_d_videos'])),

			// Fichiers (photos + vidéos).
			'a_items' => L10N::formatNumber($a_items),
			'd_items' => L10N::formatNumber($d_items),
			't_items' => L10N::formatNumber($a_items + $d_items),

			// Sous-objets.
			't_subcats' => L10N::formatNumber($subcats),
			't_childs' => L10N::formatNumber(
				$i['cat_filemtime'] === NULL ? $subcats : $a_items + $d_items
			),

			// Votes.
			'a_votes' => L10N::formatNumber((int) $i['cat_a_votes']),
			'd_votes' => L10N::formatNumber((int) $i['cat_d_votes']),
			't_votes' => L10N::formatNumber((int) ($i['cat_a_votes'] + $i['cat_d_votes'])),
			't_votes_link' => $i['cat_a_votes'] + $i['cat_d_votes'] > 0
				? App::getURL('votes/' . $i['cat_type'] . '/' . $i['cat_id'])
				: NULL,

			// Note.
			'a_rating' => L10N::formatRating((int) $i['cat_a_rating']),
			'd_rating' => L10N::formatRating((int) $i['cat_d_rating']),
			't_rating' => L10N::formatRating(
				(int) (($i['cat_a_rating'] > 0 && $i['cat_d_rating'] > 0)
					? ($i['cat_a_rating'] + $i['cat_d_rating']) / 2
					: ($i['cat_a_rating'] > 0 ? $i['cat_a_rating'] : $i['cat_d_rating']))
			),

			// Poids.
			'a_filesize' => $i['cat_a_size']
				? L10N::formatFilesize($i['cat_a_size'])
				: 0,
			'd_filesize' => $i['cat_d_size']
				? L10N::formatFilesize($i['cat_d_size'])
				: 0,
			't_filesize' => $i['cat_a_size'] + $i['cat_d_size']
				? L10N::formatFilesize($i['cat_a_size'] + $i['cat_d_size'])
				: 0,

			// Commentaires.
			'a_comments' => L10N::formatNumber((int) $i['cat_a_comments']),
			'd_comments' => L10N::formatNumber((int) $i['cat_d_comments']),
			't_comments' => L10N::formatNumber(
				(int) ($i['cat_a_comments'] + $i['cat_d_comments'])
			),
			't_comments_link' => $i['cat_a_comments'] + $i['cat_d_comments'] > 0
				? App::getURL('comments/' . $i['cat_type'] . '/' . $i['cat_id'])
				: NULL,

			// Favoris.
			'a_favorites' => L10N::formatNumber((int) $i['cat_a_favorites']),
			'd_favorites' => L10N::formatNumber((int) $i['cat_d_favorites']),
			't_favorites' => L10N::formatNumber(
				(int) ($i['cat_a_favorites'] + $i['cat_d_favorites'])
			),

			// Vues.
			'a_hits' => L10N::formatNumber((int) $i['cat_a_hits']),
			'd_hits' => L10N::formatNumber((int) $i['cat_d_hits']),
			't_hits' => L10N::formatNumber((int) ($i['cat_a_hits'] + $i['cat_d_hits']))
		];
	}

	/**
	 * Retourne une liste des catégories géolocalisées.
	 * Si plusieurs catégories ont des coordonnées identiques,
	 * une seule catégorie sera listée.
	 *
	 * @return array
	 */
	public static function getGeoCategories(): array
	{
		$sql = 'SELECT cat_id AS id,
					   cat_name AS name,
					   cat_lat AS latitude,
					   cat_long AS longitude,
					   cat_lat || "," || cat_long AS location
				  FROM {categories}
				 WHERE cat_lat IS NOT NULL
				   AND cat_long IS NOT NULL
			  ORDER BY cat_id DESC';
		if (!DB::execute($sql))
		{
			return [];
		}
		$categories = [];
		foreach (array_values(DB::fetchAll('location')) as &$i)
		{
			$categories[$i['name']] = $i;
		}
		uksort($categories, 'Utility::alphaSort');
		return array_values($categories);
	}

	/**
	 * Récupération des informations de la catégorie courante.
	 *
	 * @return void
	 */
	public static function getInfos(): void
	{
		if ($_GET['category_id'] == 1
		&& !in_array($_GET['section'], ['category', 'category-items', 'category-sort']))
		{
			App::redirect('category/1');
			return;
		}

		// Type de catégorie.
		$sql_type = (substr($_GET['section'], 0, 3) == 'alb')
			? ' AND cat_filemtime IS NOT NULL '
			: ' AND cat_filemtime IS NULL ';

		// Récupération des informations.
		$sql = "SELECT cat.*,
					   cat.cat_a_images + cat.cat_d_images AS cat_images,
					   cat.cat_a_videos + cat.cat_d_videos AS cat_videos,
					   cat.cat_a_subalbs + cat.cat_d_subalbs +
					   cat.cat_a_subcats + cat.cat_d_subcats AS cat_subcats,
					   cat.cat_tb_params AS tb_params,
					   CASE WHEN cat.cat_filemtime IS NULL
						    THEN 'category' ELSE 'album'
							 END AS cat_type,
					   i.item_id,
					   i.item_type,
					   i.item_path,
					   i.item_width,
					   i.item_height,
					   i.item_orientation,
					   i.item_adddt,
					   i.item_tb_params,
					   u.user_login,
					   u.user_nickname,
					   u.user_status,
					   p.cat_id AS p_cat_id
				  FROM {categories} AS cat
			 LEFT JOIN {users} AS u
				    ON cat.user_id = u.user_id
			 LEFT JOIN {items} AS i
				    ON cat.thumb_id = i.item_id
			 LEFT JOIN {passwords} AS p
				    ON cat.password_id = p.password_id
				 WHERE cat.cat_id = ?
					   $sql_type";
		if (!DB::execute($sql, $_GET['category_id']))
		{
			return;
		}
		if (!isset((self::$catInfos = DB::fetchRow())['cat_id']))
		{
			$_GET['page'] = 1;
			self::_objectsNoResult(0);
			return;
		}

		// Aucun fichier dans la catégorie.
		if ((self::$catInfos['cat_images'] + self::$catInfos['cat_videos']) < 1)
		{
			if (isset($_GET['search']) && self::$catInfos['cat_id'] > 1)
			{
				App::redirect(self::getURLSectionCatOne());
			}
			if (strstr($_GET['section'], 'thumb'))
			{
				App::redirect(self::$catInfos['cat_type'] . '/' . self::$catInfos['cat_id']);
			}
		}

		// Nombre de catégories.
		if (in_array($_GET['section'], ['album', 'category']))
		{
			Template::set('objects_count', (self::$catInfos['cat_type'] == 'album'
				? self::$catInfos['cat_images'] + self::$catInfos['cat_videos']
				: self::$catInfos['cat_subcats']));
		}

		// Fil d'Ariane.
		$parents_infos = Template::breadcrumb(self::$catInfos);

		// Réglages.
		self::$catInfos = [self::$catInfos];
		Parents::settings(self::$catInfos);
		self::$catInfos = self::$catInfos[0];

		// Formatage des informations.
		$formated = self::getFormatedInfos(self::$catInfos, $parents_infos);
		Template::set('category', $formated);

		// Lien vers la galerie.
		Template::set('gallery_link', $formated['gallery_link']);

		// Nombre de fichiers.
		if ($_GET['section'] == 'category-items')
		{
			$objects_count = self::$catInfos['cat_a_images'] + self::$catInfos['cat_d_images']
				+ self::$catInfos['cat_a_videos'] + self::$catInfos['cat_d_videos'];
			Template::set('objects_count', $objects_count);
		}

		// Géolocalisation.
		Template::set('geolocation',
		[
			'lat' => Config::$params['pages_params']['worldmap']['center_lat'],
			'long' => Config::$params['pages_params']['worldmap']['center_long'],
			'layer' => Config::$params['geolocation_default_layer'],
			'zoom' => Config::$params['pages_params']['worldmap']['zoom']
		]);
	}

	/**
	 * Retourne la clause ORDER BY pour la récupération des catégories.
	 *
	 * @param string $column
	 * @param string $order
	 *
	 * @return string
	 */
	public static function getOrderBy(string $column, string $order): string
	{
		$order_by = SQL::catOrderBy(sprintf('cat_%s %s', $column, $order));
		$order_by .= ', cat_id ' . $order;

		return $order_by;
	}

	/**
	 * Récupère les paramètres des réglages des objets d'une catégorie.
	 *
	 * @return void
	 */
	public static function getSettingsParams(): void
	{
		foreach (Category::getOrderByParams()['order'] as $value => &$text)
		{
			$order[] =
			[
				'text' => $text,
				'value' => $value
			];
		}
		Template::set('orderby', $order);

		foreach (Category::getOrderByParams()['album'] as $value => &$text)
		{
			$album[] =
			[
				'text' => $text,
				'value' => $value
			];
		}
		Template::set('sortby_album', $album);

		foreach (Category::getOrderByParams()['category'] as $value => &$text)
		{
			$category[] =
			[
				'text' => $text,
				'value' => $value
			];
		}
		Template::set('sortby_category', $category);
	}

	/**
	 * Récupération des sous-catégories de la catégorie courante
	 * pour la page de tri manuel des catégories.
	 *
	 * @return void
	 */
	public static function getSortCategories(): void
	{
		$sql = 'SELECT cat.cat_id,
					   thumb_id,
					   cat_name,
					   cat_status,
					   item_id,
					   item_type,
					   item_path,
					   item_width,
					   item_height,
					   item_orientation,
					   item_adddt
				  FROM {categories} AS cat
			 LEFT JOIN {items} AS i
				    ON cat.thumb_id = i.item_id
				 WHERE cat.parent_id = ?
				   AND cat.cat_id > 1
			  ORDER BY cat_position ASC';
		if (!DB::execute($sql, $_GET['category_id']))
		{
			return;
		}

		$categories = [];
		foreach (DB::fetchAll() as &$i)
		{
			$categories[] =
			[
				'activated' => $i['cat_status'] == 1,
				'id' => (int) $i['cat_id'],
				'is_empty' => $i['thumb_id'] == -1,
				'title' => $i['cat_name'],
				'thumb_src' => function() use ($i)
				{
					$thumb_src = App::getThumbSource(
						'cat', $i, self::$thumbSize, self::$thumbQuality
					);
					return htmlspecialchars($thumb_src);
				},
				'type' => Item::isImage($i['item_type']) ? 'image' : 'video'
			];
		}
		Template::set('categories', $categories);
	}

	/**
	 * Récupère tous les fichiers d'une catégorie afin d'y
	 * choisir une vignette pour cette catégotie.
	 *
	 * @return void
	 */
	public static function getThumbItems(): void
	{
		$nb_per_page = 54;

		// Clause LIMIT.
		$sql_limit = $nb_per_page * ($_GET['page'] - 1) . ",$nb_per_page";

		// Récupération des fichiers de la page courante.
		$sql_status = self::$catInfos['cat_status'] == '1' ? "'1'" : "'-1', '0'";
		$sql = "SELECT *
				  FROM {items}
				 WHERE item_path LIKE ?
				   AND item_status IN ($sql_status)
			  ORDER BY item_id DESC
			     LIMIT $sql_limit";
		if (!DB::execute($sql, DB::likeEscape(self::$catInfos['cat_path']) . '/%'))
		{
			return;
		}
		$items_infos = DB::fetchAll();

		// Nombre de pages.
		$nb_items = self::$catInfos['cat_status']
			? self::$catInfos['cat_a_images'] + self::$catInfos['cat_a_videos']
			: self::$catInfos['cat_d_images'] + self::$catInfos['cat_d_videos'];
		Template::$data['objects_count'] = $nb_items;
		Template::set('nb_pages', ceil($nb_items / $nb_per_page));

		// Formatage des données de template.
		$items = [];
		foreach ($items_infos as &$i)
		{
			$items[] =
			[
				'duration_text' => $i['item_duration']
					? App::formatDuration($i['item_duration'])
					: '00:00',
				'id' => (int) $i['item_id'],
				'title' => $i['item_name'],
				'thumb_src' => function() use ($i)
				{
					$thumb_src = App::getThumbSource(
						'item', $i, self::$thumbSize, self::$thumbQuality
					);
					return htmlspecialchars($thumb_src);
				},
				'type' => Item::isImage($i['item_type']) ? 'image' : 'video'
			];
		}
		Template::set('items', $items);
	}

	/**
	 * Création d'une nouvelle catégorie.
	 *
	 * @return void
	 */
	public static function newCategory(): void
	{
		if (isset($_POST['new_category'])
		&& isset($_POST['title']) && !Utility::isEmpty($_POST['title'])
		&& isset($_POST['type']) && in_array($_POST['type'], ['album', 'category']))
		{
			$cat_id = Category::create(
				$_POST['type'],
				$_POST['title'],
				'',
				(int) isset($_POST['activate']),
				(int) $_GET['category_id'],
				Auth::$id
			);
			switch ($cat_id)
			{
				case -1 :
				case 0 :
					Report::error();
					break;

				case 1 :
					Report::warning(
						__('Une catégorie ou un album avec le même titre existe déjà.')
					);
					break;

				default :
					Report::success($_POST['type'] == 'album'
						? __('L\'album a été créé.')
						: __('La catégorie a été créée.'));
			}
		}
	}

	/**
	 * Enregistre le tri manuel des fichiers d'un album.
	 *
	 * @return void
	 */
	public static function sortAlbum(): void
	{
		self::_sort('album');
	}

	/**
	 * Enregistre le tri manuel des sous-catégories d'une catégorie.
	 *
	 * @return void
	 */
	public static function sortCategory(): void
	{
		self::_sort('category');
	}

	/**
	 * Définit les paramètres de template pour la section.
	 *
	 * @param string $tpl_filename
	 *
	 * @return void
	 */
	public static function tplSection(string $tpl_filename): void
	{
		Template::set('page', ['link' => App::getURL('category/1'), 'title' => __('Albums')]);
		Template::set('section', 'albums');
		Template::set('template',
		[
			'content' => $tpl_filename . '.tpl.php',
			'file' => 'category.tpl.php'
		]);
	}

	/**
	 * Modifie la vignette d'une catégorie.
	 *
	 * @return void
	 */
	public static function thumbChange(): void
	{
		if (!Utility::checkPost('thumb_id', '`^\d{1,12}$`'))
		{
			return;
		}

		// On vérifie que le fichier existe...
		$sql = 'SELECT item_path, item_status FROM {items} WHERE item_id = ?';
		if (!DB::execute($sql, (int) $_POST['thumb_id']))
		{
			Report::error();
			return;
		}
		if (!$item_infos = DB::fetchRow())
		{
			Report::warning(
				__('L\'identifiant que vous avez entré ne correspond à aucun fichier.')
			);
			return;
		}

		// ...et qu'il fait partie de la catégorie.
		$sql = 'SELECT thumb_id, cat_path, cat_status FROM {categories} WHERE cat_id = ?';
		if (!DB::execute($sql, (int) $_GET['category_id']))
		{
			Report::error();
			return;
		}
		if (!$cat_infos = DB::fetchRow())
		{
			return;
		}
		if ($cat_infos['thumb_id'] == $_POST['thumb_id'])
		{
			Report::noChange();
			return;
		}
		$cat_path = $cat_infos['cat_path'] . '/';
		if (substr($item_infos['item_path'], 0, strlen($cat_path)) != $cat_path
		|| $cat_infos['cat_status'] != $item_infos['item_status'])
		{
			Report::warning(__('Ce fichier ne se trouve pas dans cette catégorie.'));
			return;
		}

		// Mise à jour de la base de données.
		$sql = 'UPDATE {categories} SET thumb_id = ?, cat_tb_params = NULL WHERE cat_id = ?';
		if (!DB::execute($sql, [(int) $_POST['thumb_id'], (int) $_GET['category_id']]))
		{
			Report::error();
			return;
		}

		// Suppression de l'image externe et des
		// vignettes générées à partir de celle-ci.
		foreach (glob(GALLERY_ROOT . '/cache/thumbs/e' . $_GET['category_id'] . '-*') as $f)
		{
			File::unlink($f);
		}
		$external_file = GALLERY_ROOT . '/cache/external/'
			. App::hashFilename((string) $_GET['category_id'], ['ext']);
		if (file_exists($external_file))
		{
			File::unlink($external_file);
		}

		Report::success();
	}

	/**
	 * Utilise une image externe comme vignette d'une catégorie.
	 *
	 * @return void
	 */
	public static function thumbExternal(): void
	{
		Upload::contentLength();

		if (!isset($_FILES['external']))
		{
			return;
		}

		// Vérification du fichier.
		if (!$_FILES['external']['size'])
		{
			Report::warning(__('Fichier de taille nulle.'));
			return;
		}
		$types_mime = array_unique(array_map(['Item', 'getTypeMime'], Item::IMAGE_TYPES));
		if (!in_array($_FILES['external']['type'], $types_mime))
		{
			Report::warning(__('Type de fichier non supporté.'));
			return;
		}

		// Chemin du fichier envoyé.
		$external_dir = GALLERY_ROOT . '/cache/external';
		$filepath = Upload::filepath($_FILES['external'], $external_dir);
		if (is_array($filepath))
		{
			Report::warning($filepath['text']);
			return;
		}

		// On renomme le fichier.
		$hash = App::hashFilename((string) $_GET['category_id'], ['ext']);
		if (!File::rename($filepath, $external_dir . '/' . $hash))
		{
			Report::error(__('Impossible de renommer le fichier.'));
			return;
		}

		// Mise à jour de la base de données.
		$sql = 'UPDATE {categories} SET thumb_id = ?, cat_tb_params = NULL WHERE cat_id = ?';
		if (!DB::execute($sql, [0, (int) $_GET['category_id']]))
		{
			Report::error();
			return;
		}

		// Suppression des vignettes générées
		// à partir de l'image externe précédente.
		foreach (glob(GALLERY_ROOT . '/cache/thumbs/e' . $_GET['category_id'] . '-*') as $f)
		{
			File::unlink($f);
		}

		Report::success();
	}

	/**
	 * Choisi une nouvelle vignette selon une méthode spécifique.
	 *
	 * @return void
	 */
	public static function thumbMethod(): void
	{
		if (!isset($_POST['thumb_method']))
		{
			return;
		}

		switch (Category::thumb([$_POST['thumb_method'] => [$_GET['category_id']]],
		!empty($_POST['thumb_method_subcats'])))
		{
			case -1 :
				Report::error();
				break;

			case 0 :
				Report::noChange();
				break;

			default :
				Report::success();
				break;
		}
	}



	/**
	 * Retourne un critère de tri.
	 *
	 * @param array $i
	 *   Informations de la catégorie.
	 * @param string $criteria
	 *   Critère de tri.
	 *
	 * @return string
	 */
	private static function _getFormatedOrderBy(array &$i, string $criteria): string
	{
		if (!array_key_exists('cat_orderby', $i))
		{
			return [];
		}

		$order = Category::getOrderByParams()['order'];
		$category = Category::getOrderByParams()['category'];
		$album = Category::getOrderByParams()['album'];

		$c = explode('_', $criteria);

		$is_album = $i['cat_filemtime'] !== NULL;

		$db_data = $i['cat_orderby'] ? explode(',', $i['cat_orderby']) : ['default ASC'];

		$num = $c[1] - 1;
		if (!isset($db_data[$num]))
		{
			return '';
		}
		$db_data = explode(' ', trim($db_data[$num]));

		$infos = [];

		if ($c[0] == 'sortby')
		{
			foreach ($is_album ? $album : $category as $value => &$text)
			{
				if ($num > 0 && $value == 'default')
				{
					continue;
				}
				return $_POST[$i['cat_id']][$criteria] ?? $db_data[0];
			}
		}

		if ($c[0] == 'orderby')
		{
			foreach ($order as $value => &$text)
			{
				return $_POST[$i['cat_id']][$criteria] ?? $db_data[1];
			}
		}
	}

	/**
	 * Retourne le mot de passe de la catégorie.
	 *
	 * @param array $i
	 *   Informations de la catégorie.
	 *
	 * @return string
	 */
	private static function _getPassword(array &$i): string
	{
		return $_POST[$i['cat_id']]['password_id']
			?? ($i['password_id'] === NULL ? '' : '**********');
	}

	/**
	 * Retourne la permission $perm.
	 *
	 * @param array $i
	 *   Informations de la catégorie.
	 * @param string $perm
	 *   Nom de la permission à retourner.
	 *
	 * @return int
	 */
	private static function _getPermission(array &$i, string $perm): int
	{
		if (isset($_POST[$i['cat_id']]['settings']))
		{
			return (int) isset($_POST[$i['cat_id']][$perm]);
		}

		return empty($i['parent_' . $perm]) ? 0 : (int) $i['cat_' . $perm];
	}

	/**
	 * Enregistre le tri manuel de fichiers ou catégories.
	 *
	 * @return void
	 */
	private static function _sort($type): void
	{
		if (!isset($_POST['save']) || !isset($_POST['serial']))
		{
			return;
		}

		// Vérification du format de l'ordre des vignettes.
		$new_positions = (string) $_POST['serial'];
		if (!preg_match('`(?:i\[\]=\d{1,11}&)*(?:i\[\]=\d{1,11})`', $new_positions))
		{
			return;
		}

		// On le convertit en tableau.
		$new_positions = str_replace('i[]=', '', $new_positions);
		$new_positions = explode('&', $new_positions);

		// Récupération de la position actuelle
		// des fichiers ou des catégories.
		$cat_id = (int) $_GET['category_id'];
		if ($type == 'album')
		{
			$sql = 'SELECT item_id AS id,
						   item_position AS position
					  FROM {items}
					 WHERE cat_id = ?
				  ORDER BY position ASC';
		}
		else
		{
			$sql = 'SELECT cat_id AS id,
						   cat_position AS position
					  FROM {categories}
					 WHERE parent_id = ?
					   AND cat_id > 1
				  ORDER BY position ASC';
		}
		if (!DB::execute($sql, $cat_id))
		{
			Report::error();
			return;
		}
		$id_position = DB::fetchAll();

		// On vérifie que les données envoyées sont correctes.
		$array_1 = array_map('intval', array_column($id_position, 'id'));
		$array_2 = array_map('intval', $new_positions);
		sort($array_1);
		sort($array_2);
		if ($array_1 !== $array_2)
		{
			trigger_error('Corrupted data.', E_USER_NOTICE);
			Report::error();
			return;
		}

		// Paramètres de mise à jour.
		// On met à jour uniquement les positions qui ont changées.
		$params = [];
		foreach ($new_positions as $i => &$id)
		{
			if ($id_position[$i]['id'] != $id)
			{
				$params[] =
				[
					'id' => $id,
					'position' => $id_position[$i]['position']
				];
			}
		}
		if (!$params)
		{
			Report::noChange();
			return;
		}

		// Mise à jour de la base de données.
		if ($type == 'album')
		{
			$sql = "UPDATE {items}
					   SET item_position = :position
					 WHERE cat_id = $cat_id
					   AND item_id = :id";
		}
		else
		{
			$sql = "UPDATE {categories}
					   SET cat_position = :position
					 WHERE parent_id = $cat_id
					   AND cat_id = :id";
		}
		if (!DB::execute($sql, $params))
		{
			Report::error();
		}
		else if (DB::rowCount() < 1)
		{
			Report::noChange();
		}
		else
		{
			Report::success();
		}
	}
}
?>