<?php
declare(strict_types = 1);

/**
 * Gestion de la configuration.
 *
 * @license https://www.gnu.org/licenses/gpl-3.0.html
 * @link https://www.igalerie.org/
 */
class Config
{
	/**
	 * Paramètres de configuration en base de données.
	 *
	 * @var array
	 */
	const DB_PARAMS =
	[
		// Interface d'administration.
		'admin_link'                          => ['type' => 'bin',  'default' => 1],

		// Téléchargement d'albums.
		'albums_download'                     => ['type' => 'bin',  'default' => 0],

		// Application.
		'app_version'                         => ['type' => 'text', 'default' => ''],
		'app_history'                         => ['type' => 'text', 'default' => []],

		// Listes noires.
		'blacklist_emails'                    => ['type' => 'text', 'default' => ''],
		'blacklist_ips'                       => ['type' => 'text', 'default' => ''],
		'blacklist_names'                     => ['type' => 'text', 'default'
			=> "*best price*\n*casino*\n*cialis*\n*viagra*"],
		'blacklist_words'                     => ['type' => 'text', 'default'
			=> "<embed\n<html\n<img\n<meta\n<object\n<script\n"
			 . "<style\n[email\n[img\n[url\nhref =\nhref=\nsrc =\nsrc="],

		// Liste des albums.
		'browse'                              => ['type' => 'bin',  'default' => 1],
		'browse_ajax'                         => ['type' => 'bin',  'default' => 0],
		'browse_items_count'                  => ['type' => 'bin',  'default' => 0],
		'browse_sql_order_by'                 => ['type' => 'text', 'default' => 'cat_name ASC'],

		// Catégories.
		'categories_description_model'        => ['type' => 'bin',  'default' => 0],
		'categories_description_model_text'   => ['type' => 'text', 'default' => '{DESCRIPTION}'],
		'categories_sql_order_by'             => ['type' => 'text', 'default' => 'cat_name ASC'],
		'categories_stats'                    => ['type' => 'bin',  'default' => 1],
		'categories_stats_order'              => ['type' => 'text', 'default'
			=> self::CATEGORIES_STATS_ORDER],
		'categories_stats_params'             => ['type' => 'text', 'default'
			=> self::CATEGORIES_STATS_PARAMS],

		// Commentaires.
		'comments'                            => ['type' => 'bin',  'default' => 0],
		'comments_antiflood'                  => ['type' => 'int',  'default' => 60],
		'comments_emoji_delete'               => ['type' => 'bin',  'default' => 0],
		'comments_emoji_picker'               => ['type' => 'bin',  'default' => 1],
		'comments_maxchars'                   => ['type' => 'int',  'default' => 1000],
		'comments_maxlines'                   => ['type' => 'int',  'default' => 20],
		'comments_maxurls'                    => ['type' => 'int',  'default' => 1],
		'comments_moderate'                   => ['type' => 'bin',  'default' => 0],
		'comments_order_by'                   => ['type' => 'text', 'default' => 'ASC'],
		'comments_page_count'                 => ['type' => 'int',  'default' => 20],
		'comments_read_only'                  => ['type' => 'bin',  'default' => 0],
		'comments_required_email'             => ['type' => 'bin',  'default' => 0],
		'comments_required_website'           => ['type' => 'bin',  'default' => 0],
		'comments_url_to_link'                => ['type' => 'bin',  'default' => 1],
		'comments_url_to_link_maxlength'      => ['type' => 'int',  'default' => 40],

		// Mises à jour quotidiennes.
		'daily_update'                        => ['type' => 'text', 'default' => ''],

		// Dates.
		'dates_expiration'                    => ['type' => 'text', 'default' => []],
		'dates_publication'                   => ['type' => 'text', 'default' => []],

		// Diaporama.
		'diaporama'                           => ['type' => 'bin',  'default' => 1],
		'diaporama_auto_duration'             => ['type' => 'int',  'default' => 3],
		'diaporama_auto_loop'                 => ['type' => 'bin',  'default' => 0],
		'diaporama_auto_start'                => ['type' => 'bin',  'default' => 0],
		'diaporama_carousel'                  => ['type' => 'bin',  'default' => 1],
		'diaporama_carousel_thumbs_ratio'     => ['type' => 'text', 'default' => 'normal'],
		'diaporama_carousel_thumbs_size'      => ['type' => 'int',  'default' => 80],
		'diaporama_control_bars'              => ['type' => 'bin',  'default' => 1],
		'diaporama_fullscreen'                => ['type' => 'bin',  'default' => 0],
		'diaporama_fullscreen_mobile'         => ['type' => 'bin',  'default' => 1],
		'diaporama_keyboard'                  => ['type' => 'bin',  'default' => 1],
		'diaporama_over_image_description'    => ['type' => 'bin',  'default' => 0],
		'diaporama_over_image_title'          => ['type' => 'bin',  'default' => 0],
		'diaporama_show_informations'         => ['type' => 'bin',  'default' => 0],
		'diaporama_transition_duration'       => ['type' => 'int',  'default' => 500],
		'diaporama_transition_effect'         => ['type' => 'text', 'default' => 'fade'],
		'diaporama_zoom'                      => ['type' => 'bin',  'default' => 1],
		'diaporama_zoom_limit'                => ['type' => 'int',  'default' => 100],

		// Téléchargement.
		'download_item'                       => ['type' => 'bin',  'default' => 1],

		// Informations EXIF.
		'exif'                                => ['type' => 'bin',  'default' => 0],
		'exif_order'                          => ['type' => 'text', 'default'
			=> self::EXIF_ORDER],
		'exif_params'                         => ['type' => 'text', 'default'
			=> self::EXIF_PARAMS],

		// Favoris.
		'favorites'                           => ['type' => 'bin',  'default' => 1],
		'favorites_download'                  => ['type' => 'bin',  'default' => 0],

		// Galerie.
		'gallery_closed'                      => ['type' => 'bin',  'default' => 0],
		'gallery_closed_text'                 => ['type' => 'text', 'default' => ''],
		'gallery_description'                 => ['type' => 'text', 'default' => ''],
		'gallery_footer_text'                 => ['type' => 'text', 'default' => ''],
		'gallery_title'                       => ['type' => 'text', 'default' => ''],

		// Géolocalisation.
		'geolocation'                         => ['type' => 'bin',  'default' => 0],
		'geolocation_default_layer'           => ['type' => 'text', 'default' => 'map'],
		'geolocation_default_zoom'            => ['type' => 'int',  'default' => 12],

		// Informations IPTC.
		'iptc'                                => ['type' => 'bin',  'default' => 0],
		'iptc_get_data'                       => ['type' => 'bin',  'default' => 1],
		'iptc_order'                          => ['type' => 'text', 'default'
			=> self::IPTC_ORDER],
		'iptc_params'                         => ['type' => 'text', 'default'
			=> self::IPTC_PARAMS],
		'iptc_title_tag'                      => ['type' => 'text', 'default' => 'Headline'],

		// Fichiers.
		'items_description_model'             => ['type' => 'bin',  'default' => 0],
		'items_description_model_text'        => ['type' => 'text', 'default' => '{DESCRIPTION}'],
		'items_recent'                        => ['type' => 'bin',  'default' => 1],
		'items_recent_days'                   => ['type' => 'int',  'default' => 7],
		'items_resize'                        => ['type' => 'bin',  'default' => 0],
		'items_resize_height'                 => ['type' => 'int',  'default' => 1200],
		'items_resize_quality'                => ['type' => 'int',  'default' => 90],
		'items_resize_type'                   => ['type' => 'text', 'default' => ''],
		'items_resize_width'                  => ['type' => 'int',  'default' => 1200],
		'items_sql_order_by'                  => ['type' => 'text', 'default'
			=> 'item_pubdt DESC'],

		// Langues.
		'lang_default'                        => ['type' => 'text', 'default' => 'en'],
		'lang_detect'                         => ['type' => 'bin',  'default' => 1],
		'lang_params'                         => ['type' => 'text', 'default'
			=> ['filemtime' => 0, 'langs' => ['en' => 'English', 'fr' => 'Français']]],
		'lang_switch'                         => ['type' => 'bin',  'default' => 0],

		// Liens externes.
		'links'                               => ['type' => 'bin',  'default' => 1],
		'links_params'                        => ['type' => 'text', 'default' => []],

		// Courriel : paramètres.
		'mail_auto_bcc'                       => ['type' => 'bin',  'default' => 1],
		'mail_auto_primary_recipient_address' => ['type' => 'text', 'default' => ''],
		'mail_auto_sender_address'            => ['type' => 'text', 'default' => ''],
		'mail_auto_sender_name'               => ['type' => 'text', 'default' => ''],
		'mail_auto_signature'                 => ['type' => 'bin',  'default' => 0],
		'mail_auto_signature_text'            => ['type' => 'text', 'default' => ''],

		// Courriel : notifications.
		'mail_notify_comment_subject'         => ['type' => 'text', 'default' => ''],
		'mail_notify_comment_message'         => ['type' => 'text', 'default' => ''],
		'mail_notify_comment_follow_subject'  => ['type' => 'text', 'default' => ''],
		'mail_notify_comment_follow_message'  => ['type' => 'text', 'default' => ''],
		'mail_notify_comment_pending_subject' => ['type' => 'text', 'default' => ''],
		'mail_notify_comment_pending_message' => ['type' => 'text', 'default' => ''],
		'mail_notify_items_subject'           => ['type' => 'text', 'default' => ''],
		'mail_notify_items_message'           => ['type' => 'text', 'default' => ''],
		'mail_notify_items_http_subject'      => ['type' => 'text', 'default' => ''],
		'mail_notify_items_http_message'      => ['type' => 'text', 'default' => ''],
		'mail_notify_items_pending_subject'   => ['type' => 'text', 'default' => ''],
		'mail_notify_items_pending_message'   => ['type' => 'text', 'default' => ''],
		'mail_notify_registration_subject'    => ['type' => 'text', 'default' => ''],
		'mail_notify_registration_message'    => ['type' => 'text', 'default' => ''],
		'mail_notify_registration_pending_subject'
											  => ['type' => 'text', 'default' => ''],
		'mail_notify_registration_pending_message'
											  => ['type' => 'text', 'default' => ''],

		// Nouvelle version.
		'new_version'                         => ['type' => 'text', 'default' => ''],
		'new_version_check'                   => ['type' => 'bin',  'default' => 0],
		'new_version_check_date'              => ['type' => 'text', 'default' => ''],

		// Pages.
		'pages_order'                         => ['type' => 'text', 'default'
			=> self::PAGES_ORDER],
		'pages_params'                        => ['type' => 'text', 'default'
			=> self::PAGES_PARAMS],

		// Fichier au hasard.
		'random_item'                         => ['type' => 'bin',  'default' => 0],

		// RSS.
		'rss'                                 => ['type' => 'bin',  'default' => 0],
		'rss_max_items'                       => ['type' => 'int',  'default' => 20],

		// Moteur de recherche.
		'search'                              => ['type' => 'bin',  'default' => 0],
		'search_advanced'                     => ['type' => 'bin',  'default' => 0],
		'search_suggestion'                   => ['type' => 'bin',  'default' => 0],

		// Mode sélection.
		'selection'                           => ['type' => 'bin',  'default' => 0],

		// Statistiques.
		'stats_short_numbers'                 => ['type' => 'bin',  'default' => 1],

		// Tags.
		'tags'                                => ['type' => 'bin',  'default' => 0],
		'tags_max'                            => ['type' => 'int',  'default' => 15],

		// Thème de la galerie.
		'theme_params'                        => ['type' => 'text', 'default' => ''],
		'theme_template'                      => ['type' => 'text', 'default' => 'default'],

		// Vignettes.
		'thumbs_cat_nb_per_page'              => ['type' => 'int',  'default' => 12],
		'thumbs_cat_info_albums'              => ['type' => 'bin',  'default' => 1],
		'thumbs_cat_info_comments'            => ['type' => 'bin',  'default' => 1],
		'thumbs_cat_info_description'         => ['type' => 'bin',  'default' => 0],
		'thumbs_cat_info_description_limit'   => ['type' => 'int',  'default' => 500],
		'thumbs_cat_info_favorites'           => ['type' => 'bin',  'default' => 1],
		'thumbs_cat_info_filesize'            => ['type' => 'bin',  'default' => 0],
		'thumbs_cat_info_items'               => ['type' => 'bin',  'default' => 1],
		'thumbs_cat_info_rating'              => ['type' => 'bin',  'default' => 1],
		'thumbs_cat_info_title'               => ['type' => 'bin',  'default' => 1],
		'thumbs_cat_info_views'               => ['type' => 'bin',  'default' => 1],
		'thumbs_cat_info_votes'               => ['type' => 'bin',  'default' => 1],
		'thumbs_item_nb_per_page'             => ['type' => 'int',  'default' => 24],
		'thumbs_item_info_comments'           => ['type' => 'bin',  'default' => 1],
		'thumbs_item_info_date'               => ['type' => 'bin',  'default' => 0],
		'thumbs_item_info_description'        => ['type' => 'bin',  'default' => 0],
		'thumbs_item_info_description_limit'  => ['type' => 'int',  'default' => 500],
		'thumbs_item_info_favorites'          => ['type' => 'bin',  'default' => 1],
		'thumbs_item_info_filesize'           => ['type' => 'bin',  'default' => 0],
		'thumbs_item_info_rating'             => ['type' => 'bin',  'default' => 0],
		'thumbs_item_info_size'               => ['type' => 'bin',  'default' => 0],
		'thumbs_item_info_title'              => ['type' => 'bin',  'default' => 1],
		'thumbs_item_info_views'              => ['type' => 'bin',  'default' => 1],
		'thumbs_item_info_votes'              => ['type' => 'bin',  'default' => 1],
		'thumbs_quality'                      => ['type' => 'int',  'default' => 90],
		'thumbs_type'                         => ['type' => 'text', 'default' => ''],

		// Fuseau horaire.
		'tz_default'                          => ['type' => 'text', 'default' => 'Europe/Paris'],

		// Envoi de fichiers.
		'upload_maxfilesize'                  => ['type' => 'int',  'default' => 100],
		'upload_maxtotalfiles'                => ['type' => 'int',  'default' => 100],
		'upload_maxwidth'                     => ['type' => 'int',  'default' => 8000],
		'upload_maxheight'                    => ['type' => 'int',  'default' => 8000],
		'upload_resize'                       => ['type' => 'bin',  'default' => 0],
		'upload_resize_maxheight'             => ['type' => 'int',  'default' => 768],
		'upload_resize_maxwidth'              => ['type' => 'int',  'default' => 1024],
		'upload_resize_quality'               => ['type' => 'int',  'default' => 95],

		// Utilisateurs.
		'users'                               => ['type' => 'bin',  'default' => 0],
		'users_description_maxlength'         => ['type' => 'int',  'default' => 500],
		'users_items_resize'                  => ['type' => 'bin',  'default' => 1],
		'users_items_resize_height'           => ['type' => 'int',  'default' => 768],
		'users_items_resize_width'            => ['type' => 'int',  'default' => 1024],
		'users_items_resize_quality'          => ['type' => 'int',  'default' => 90],
		'users_items_resize_type'             => ['type' => 'text', 'default' => ''],
		'users_log_activity'                  => ['type' => 'bin',  'default' => 1],
		'users_log_activity_delete'           => ['type' => 'bin',  'default' => 1],
		'users_log_activity_delete_days'      => ['type' => 'int',  'default' => 10],
		'users_log_activity_no_admin'         => ['type' => 'bin',  'default' => 0],
		'users_log_activity_rejected_only'    => ['type' => 'bin',  'default' => 1],
		'users_online'                        => ['type' => 'bin',  'default' => 0],
		'users_online_duration'               => ['type' => 'int',  'default' => 300],
		'users_only_members'                  => ['type' => 'bin',  'default' => 0],
		'users_only_members_contact'          => ['type' => 'bin',  'default' => 0],
		'users_password_minlength'            => ['type' => 'int',  'default' => 6],
		'users_profile_params'                => ['type' => 'text', 'default'
			=> self::USERS_PROFILE_PARAMS],
		'users_registration'                  => ['type' => 'bin',  'default' => 1],
		'users_registration_password'         => ['type' => 'text', 'default' => ''],
		'users_registration_password_text'    => ['type' => 'text', 'default' => ''],
		'users_registration_valid_admin'      => ['type' => 'bin',  'default' => 0],
		'users_registration_valid_email'      => ['type' => 'bin',  'default' => 1],
		'users_registration_valid_password'   => ['type' => 'bin',  'default' => 0],

		// Vidéos.
		'video_captures'                      => ['type' => 'bin',  'default' => 0],
		'video_loop'                          => ['type' => 'bin',  'default' => 0],
		'video_muted'                         => ['type' => 'bin',  'default' => 0],

		// Vues.
		'views_admin'                         => ['type' => 'bin',  'default' => 0],
		'views_ip'                            => ['type' => 'bin',  'default' => 0],
		'views_ip_list'                       => ['type' => 'text', 'default' => ''],
		'views_useragent'                     => ['type' => 'bin',  'default' => 1],
		'views_useragent_list'                => ['type' => 'text', 'default'
			=> "*addthis*\n*admantx*\n*ads*\n*ahrefs*\n*alexa*\n*archive*\n*ask*\n*baidu*\n"
			. "*bing*\n*bot*\n*b-o-t*\n*bubing*\n*crawl*\n*dataprovider*\n*daum*\n*envolk*\n"
			. "*evaliant*\n*exalead*\n*explorer*\n*facebook*\n*fetcher*\n*genieo*\n*gigablast*\n"
			. "*google*\n*ichiro*\n*jobboerse*\n*mail.ru*\n*megaindex*\n*netcraft*\n*newspaper*\n"
			. "*owlin*\n*panscient*\n*pinterest*\n*qwant*\n*riddler*\n*search*\n*seo*\n"
			. "*sistrix*\n*slurp*\n*sogou*\n*scoutjet*\n*spider*\n*squider*\n*thetradedesk*\n"
			. "*vagabondo*\n*yahoo*\n*yandex*\n*yeti*\n*zgrab*"],

		// Votes.
		'votes'                               => ['type' => 'bin',  'default' => 0],

		// Message de bienvenue.
		'welcome'                             => ['type' => 'bin',  'default' => 1],

		// Informations XMP.
		'xmp'                                 => ['type' => 'bin',  'default' => 0],
		'xmp_get_data'                        => ['type' => 'bin',  'default' => 1],
		'xmp_order'                           => ['type' => 'text', 'default'
			=> self::XMP_ORDER],
		'xmp_params'                          => ['type' => 'text', 'default'
			=> self::XMP_PARAMS],
		'xmp_priority'                        => ['type' => 'bin',  'default' => 1]
	];

	/**
	 * Ordre d'affichage des statistiques des catégories.
	 *
	 * @var array
	 */
	const CATEGORIES_STATS_ORDER =
	[
		'items', 'images', 'videos', 'albums', 'filesize',
		'recent_items', 'recent_images', 'recent_videos', 'views',
		'comments', 'rating', 'votes', 'favorites'
	];

	/**
	 * Paramètres des statistiques des catégories.
	 *
	 * @var array
	 */
	const CATEGORIES_STATS_PARAMS =
	[
		'albums'		=> ['status' => 1],
		'comments'		=> ['status' => 1],
		'favorites'		=> ['status' => 1],
		'filesize'		=> ['status' => 0],
		'images'		=> ['status' => 1],
		'items'			=> ['status' => 0],
		'rating'	    => ['status' => 0],
		'recent_images'	=> ['status' => 1],
		'recent_items'	=> ['status' => 0],
		'recent_videos'	=> ['status' => 0],
		'videos'		=> ['status' => 0],
		'views'			=> ['status' => 1],
		'votes'			=> ['status' => 1]
	];

	/**
	 * Ordre d'affichage des informations EXIF.
	 *
	 * @var array
	 */
	const EXIF_ORDER =
	[
		'Make',
		'Model',
		'Lens',
		'DateTimeOriginal',
		'DateTimeDigitized',
		'DateTime',
		'GPSCoordinates',
		'GPSAltitude',
		'LightSource',
		'Flash',
		'FNumber',
		'MaxApertureValue',
		'FocalLength',
		'FocalLengthIn35mmFilm',
		'DigitalZoomRatio',
		'ISOSpeedRatings',
		'ExposureBiasValue',
		'ExposureMode',
		'ExposureProgram',
		'ExposureTime',
		'SceneType',
		'SceneCaptureType',
		'CustomRendered',
		'MeteringMode',
		'Orientation',
		'WhiteBalance',
		'SensingMethod',
		'SubjectDistanceRange',
		'SubjectDistance',
		'XResolution',
		'YResolution',
		'ResolutionUnit',
		'ColorSpace',
		'GainControl',
		'Contrast',
		'Saturation',
		'Sharpness',
		'Software',
		'Artist',
		'Copyright',
		'ExifVersion',
		'FlashPixVersion'
	];

	/**
	 * Paramètres EXIF.
	 *
	 * @var array
	 */
	const EXIF_PARAMS =
	[
		'Artist'                => ['status' => 0],
		'ColorSpace'            => ['status' => 0],
		'Contrast'              => ['status' => 0],
		'Copyright'             => ['status' => 0],
		'CustomRendered'        => ['status' => 0],
		'DateTime'              => ['status' => 0],
		'DateTimeDigitized'     => ['status' => 0],
		'DateTimeOriginal'      => ['status' => 1],
		'DigitalZoomRatio'      => ['status' => 0, 'format' => '%2.1Fx'],
		'ExifVersion'           => ['status' => 0],
		'ExposureBiasValue'     => ['status' => 0, 'format' => '%+2.2F Ev'],
		'ExposureMode'          => ['status' => 0],
		'ExposureProgram'       => ['status' => 0],
		'ExposureTime'          => ['status' => 1],
		'Flash'                 => ['status' => 1],
		'FlashPixVersion'       => ['status' => 0],
		'FNumber'               => ['status' => 1, 'format' => 'f/%2.1F'],
		'FocalLength'           => ['status' => 1, 'format' => '%2.2F mm'],
		'FocalLengthIn35mmFilm' => ['status' => 0, 'format' => '%2.2F mm'],
		'GainControl'           => ['status' => 0],
		'GPSAltitude'           => ['status' => 0, 'format' => '%.2F m'],
		'GPSCoordinates'        => ['status' => 0],
		'ISOSpeedRatings'       => ['status' => 1],
		'Lens'                  => ['status' => 1],
		'LightSource'           => ['status' => 0],
		'Make'                  => ['status' => 1],
		'MaxApertureValue'      => ['status' => 0, 'format' => '%2.2F mm'],
		'MeteringMode'          => ['status' => 0],
		'Model'                 => ['status' => 1],
		'Orientation'           => ['status' => 0],
		'ResolutionUnit'        => ['status' => 0],
		'Saturation'            => ['status' => 0],
		'SceneCaptureType'      => ['status' => 0],
		'SceneType'             => ['status' => 0],
		'SensingMethod'         => ['status' => 0],
		'Sharpness'             => ['status' => 0],
		'Software'              => ['status' => 0],
		'SubjectDistance'       => ['status' => 0, 'format' => '%2.2F m'],
		'SubjectDistanceRange'  => ['status' => 0],
		'WhiteBalance'          => ['status' => 0],
		'XResolution'           => ['status' => 0, 'format' => '%d'],
		'YResolution'           => ['status' => 0, 'format' => '%d']
	];

	/**
	 * Liste des fonctionnalités désactivables par le thème.
	 *
	 * @var array
	 */
	const FEATURES =
	[
		'albums_download', 'browse', 'browse_ajax', 'categories_stats',
		'comments', 'diaporama', 'exif', 'geolocation', 'iptc', 'items_recent',
		'links', 'random_item', 'rss', 'search', 'search_advanced',
		'search_suggestion', 'selection', 'tags', 'users', 'votes', 'xmp'
	];

	/**
	 * Emplacement du fichier de configuration.
	 *
	 * @var string
	 */
	const FILE_PATH = GALLERY_ROOT . '/config/conf.php';

	/**
	 * Paramètres du fichier de configuration.
	 *
	 * @var array
	 */
	const FILE_PARAMS =
	[
		'CONF_ACCESS_KEY'        => ['type' => 'text', 'regexp' => '[a-z\d]{40,80}'],
		'CONF_ALBUMS_PATH'       => ['type' => 'text', 'regexp' => '.{1,256}'],
		'CONF_AUTH_ADMIN_IP'     => ['type' => 'text', 'regexp' => '.{0,512}'],
		'CONF_DB_USER'           => ['type' => 'text', 'regexp' => '.{0,128}'],
		'CONF_DB_PASS'           => ['type' => 'text', 'regexp' => '.{0,128}'],
		'CONF_DB_HOST'           => ['type' => 'text', 'regexp' => '.{0,128}'],
		'CONF_DB_PORT'           => ['type' => 'text', 'regexp' => '\d{0,5}'],
		'CONF_DB_NAME'           => ['type' => 'text', 'regexp' => '.{0,128}'],
		'CONF_DB_TYPE'           => ['type' => 'text', 'regexp' => '(?:mysql|pgsql|sqlite)'],
		'CONF_DB_PREF'           => ['type' => 'text', 'regexp' => '[a-z\d_]{0,32}'],
		'CONF_DB_DATE'           => ['type' => 'text', 'regexp' => '(?:php|sql)'],
		'CONF_DB_TRAN'           => ['type' => 'int',  'regexp' => 'bin'],
		'CONF_GALLERY_PATH'      => ['type' => 'text', 'regexp' => '.{1,256}'],
		'CONF_GD_TRANSPARENCY'   => ['type' => 'int',  'regexp' => 'bin'],
		'CONF_HTTP_CSP_FRAME_ANCESTORS'
								 => ['type' => 'text', 'regexp' => '.{0,512}'],
		'CONF_HTTP_CSP_HOSTS'
								 => ['type' => 'text', 'regexp' => '.{0,512}'],
		'CONF_INTEGRATED'        => ['type' => 'int',  'regexp' => 'bin'],
		'CONF_KEY'               => ['type' => 'text', 'regexp' => '[a-z\d]{40,80}'],
		'CONF_PASSWORD_PEPPER'   => ['type' => 'text', 'regexp' => '[a-z\d]{40,80}'],
		'CONF_SMTP_MAIL'         => ['type' => 'int',  'regexp' => 'bin'],
		'CONF_SMTP_HOST'         => ['type' => 'text', 'regexp' => '.{0,128}'],
		'CONF_SMTP_PORT'         => ['type' => 'int',  'regexp' => '\d{0,5}'],
		'CONF_SMTP_AUTH'         => ['type' => 'int',  'regexp' => 'bin'],
		'CONF_SMTP_USER'         => ['type' => 'text', 'regexp' => '.{0,128}'],
		'CONF_SMTP_PASS'         => ['type' => 'text', 'regexp' => '.{0,128}'],
		'CONF_SMTP_TIME'         => ['type' => 'int',  'regexp' => '\d{1,2}'],
		'CONF_SQLITE_BACKUP'     => ['type' => 'int',  'regexp' => 'bin'],
		'CONF_SQLITE_BACKUP_MAX' => ['type' => 'int',  'regexp' => '\d{1,5}'],
		'CONF_URL_REWRITE'       => ['type' => 'int',  'regexp' => 'bin']
	];

	/**
	 * Ordre d'affichage des informations IPTC.
	 *
	 * @var array
	 */
	const IPTC_ORDER =
	[
		'ObjectName',
		'Headline',
		'Description',
		'DescriptionWriter',
		'Keywords',
		'Copyright',
		'Source',
		'Contact',
		'Creator',
		'CreatorTitle',
		'Credit',
		'Instructions',
		'Country',
		'CountryCode',
		'ProvinceState',
		'City',
		'SubLocation',
		'DateCreated',
		'TimeCreated',
		'DigitalCreationDate',
		'DigitalCreationTime',
		'Orientation',
		'Software',
		'SoftwareVersion'
	];

	/**
	 * Paramètres IPTC.
	 *
	 * @var array
	 */
	const IPTC_PARAMS =
	[
		'City'                => ['status' => 1],
		'Contact'             => ['status' => 1],
		'Copyright'           => ['status' => 1],
		'Country'             => ['status' => 0],
		'CountryCode'         => ['status' => 0],
		'Creator'             => ['status' => 1],
		'CreatorTitle'        => ['status' => 0],
		'Credit'              => ['status' => 1],
		'DateCreated'         => ['status' => 1],
		'Description'         => ['status' => 1],
		'DescriptionWriter'   => ['status' => 0],
		'DigitalCreationDate' => ['status' => 1],
		'DigitalCreationTime' => ['status' => 0],
		'Headline'            => ['status' => 0],
		'Instructions'        => ['status' => 0],
		'Keywords'            => ['status' => 1],
		'ObjectName'          => ['status' => 1],
		'Orientation'         => ['status' => 0],
		'ProvinceState'       => ['status' => 0],
		'Software'            => ['status' => 0],
		'SoftwareVersion'     => ['status' => 0],
		'Source'              => ['status' => 1],
		'SubLocation'         => ['status' => 0],
		'TimeCreated'         => ['status' => 0]
	];

	/**
	 * Ordre d'affichage des pages.
	 *
	 * @var array
	 */
	const PAGES_ORDER =
	[
		'comments', 'tags', 'history', 'cameras', 'worldmap', 'members', 'contact'
	];

	/**
	 * Paramètres des pages.
	 *
	 * @var array
	 */
	const PAGES_PARAMS = 
	[
		'cameras'  => ['status' => 0],
		'comments' => ['status' => 1, 'nb_per_page' => 20],
		'contact'  => ['status' => 0, 'email' => '', 'message' => ''],
		'history'  => ['status' => 0],
		'members'  => ['status' => 1, 'nb_per_page' => 20, 'order_by' => 'user_crtdt DESC',
			'show_crtdt' => 1, 'show_lastvstdt' => 0, 'show_title' => 1],
		'tags'     => ['status' => 1],
		'worldmap' => ['status' => 1, 'center_lat' => 46.5, 'center_long' => 3, 'zoom' => 4]
	];

	/**
	 * Permissions d'accès aux fonctionnalités de la galerie.
	 *
	 * @var array
	 */
	const USERS_GROUP_PERMS_DEFAULT =
	[
		'albums_download' => 1,
		'comments_add' => 1,
		'comments_add_mode' => 1,
		'comments_read' => 1,
		'create_albums' => 0,
		'create_albums_categories' => 0,
		'create_albums_gallery_root' => 0,
		'create_albums_owner' => 0,
		'image_original' => 1,
		'members_profile' => 1,
		'perm_list' => 'black',
		'selection' => 0,
		'upload' => 0,
		'upload_mode' => 1,
		'upload_owner' => 0,
		'upload_type' => 'all',
		'votes' => 1
	];

	/**
	 * Paramètres de profil pour les utilisateurs.
	 *
	 * @var array
	 */
	const USERS_PROFILE_PARAMS =
	[
		'birthdate'   => ['activated' => 0, 'required' => 0],
		'description' => ['activated' => 1, 'required' => 0],
		'email'       => ['activated' => 1, 'required' => 0],
		'firstname'   => ['activated' => 0, 'required' => 0],
		'gender'      => ['activated' => 0, 'required' => 0],
		'group_id'    => ['activated' => 1, 'required' => 1],
		'lang'        => ['activated' => 1, 'required' => 0],
		'location'    => ['activated' => 0, 'required' => 0],
		'login'       => ['activated' => 1, 'required' => 1],
		'name'        => ['activated' => 0, 'required' => 0],
		'nickname'    => ['activated' => 0, 'required' => 0],
		'password'    => ['activated' => 1, 'required' => 0],
		'custom_1'    => ['activated' => 0, 'required' => 0, 'name' => ''],
		'custom_2'    => ['activated' => 0, 'required' => 0, 'name' => ''],
		'custom_3'    => ['activated' => 0, 'required' => 0, 'name' => ''],
		'custom_4'    => ['activated' => 0, 'required' => 0, 'name' => ''],
		'custom_5'    => ['activated' => 0, 'required' => 0, 'name' => ''],
		'status'      => ['activated' => 1, 'required' => 1],
		'tz'          => ['activated' => 1, 'required' => 0],
		'website'     => ['activated' => 1, 'required' => 0]
	];

	/**
	 * Ordre d'affichage des informations XMP.
	 *
	 * @var array
	 */
	const XMP_ORDER =
	[
		'Contributor', 'Coverage', 'Creator', 'Date', 'Description',
		'Format', 'Identifier', 'Language', 'Publisher', 'Relation',
		'Rights', 'Source', 'Subject', 'Title', 'Type'
	];

	/**
	 * Paramètres XMP.
	 *
	 * @var array
	 */
	const XMP_PARAMS =
	[
		'Contributor' => ['status' => 0],
		'Coverage'    => ['status' => 0],
		'Creator'     => ['status' => 1],
		'Date'        => ['status' => 1],
		'Description' => ['status' => 1],
		'Format'      => ['status' => 0],
		'Identifier'  => ['status' => 0],
		'Language'    => ['status' => 0],
		'Publisher'   => ['status' => 0],
		'Relation'    => ['status' => 0],
		'Rights'      => ['status' => 1],
		'Source'      => ['status' => 0],
		'Subject'     => ['status' => 0],
		'Title'       => ['status' => 1],
		'Type'        => ['status' => 0]
	];



	/**
	 * Valeurs de la configuration en base de données.
	 *
	 * @var array
	 */
	public static $params = [];



	/**
	 * Ajoute des paramètres de configuration en base de données.
	 *
	 * @param array $params
	 *    $params = [
	 *       ['param_1', 'value_1'],
	 *       ['param_2', 'value_2']
	 *       ...
     *    ];
	 *
	 * @return int
	 *   Retourne le nombre de paramètres ajoutés,
	 *   ou -1 en cas d'erreur.
	 */
	public static function addDBParams(array $params): int
	{
		$sql = 'INSERT IGNORE INTO {config} (conf_name, conf_value) VALUES (?, ?)';
		if (!DB::execute($sql, $params))
		{
			return -1;
		}

		return DB::rowCount();
	}

	/**
	 * Ajoute des paramètres au fichier de configuration.
	 *
	 * @param array $params
	 * @param string $comment
	 *
	 * @return bool
	 *   TRUE si le fichier a été modifié avec succès,
	 *   FALSE si une erreur est survenue.
	 */
	public static function addFileParams(array $params, string $comment): bool
	{
		// On récupère le contenu du fichier.
		if (($file_content = file(self::FILE_PATH)) === FALSE
		|| substr($file_content[0], 0, 5) != '<?php')
		{
			return FALSE;
		}

		array_shift($file_content);

		// Ajout des paramètres.
		$add_content = [];
		foreach ($params as $name => &$value)
		{
			// Vérification du format.
			if (!isset(self::FILE_PARAMS[$name]))
			{
				continue;
			}
			switch (self::FILE_PARAMS[$name]['regexp'])
			{
				// Valeur binaire.
				case 'bin' :
					break;

				// Vérification par regexp.
				default :
					if (!preg_match('`^' . self::FILE_PARAMS[$name]['regexp'] . '$`i',
					(string) $value))
					{
						continue 2;
					}
					break;
			}

			// Type de valeur.
			$value = self::_formatFileValue($name, $value);

			// Cette ligne ne sert qu'à gérer correctement les antislashes.
			if (is_string($value))
			{
				$value = preg_replace('`^.*$`', $value, $value);
			}

			// Ajout du paramètre.
			$add_content[] = "define('$name', $value);\n";
		}

		$file_content = array_merge($add_content, $file_content);
		array_unshift($file_content, "<?php\n", "\n", '// ' . $comment . "\n");

		// On enregistre les modifications dans le fichier de configuration.
		return (bool) File::putContents(self::FILE_PATH, $file_content);
	}

	/**
	 * Modifications de paramètres de configuration de base de données.
	 *
	 * @param array $params
	 *
	 * @return int
	 *   Retourne le nombre de paramètres modifiés,
	 *   ou -1 en cas d'erreur.
	 */
	public static function changeDBParams(array $params): int
	{
		foreach ($params as $p => &$value)
		{
			if (!array_key_exists($p, self::DB_PARAMS))
			{
				continue;
			}

			switch (self::DB_PARAMS[$p]['type'])
			{
				case 'bin' :
					if ($value && !self::$params[$p])
					{
						$update_params[] = ['1', $p];
					}
					else if (!$value && self::$params[$p])
					{
						$update_params[] = ['0', $p];
					}
					break;

				case 'int' :
					$value = (string) $value;

					if (preg_match('`^\d+$`', $value)
					&& $value != self::$params[$p])
					{
						$update_params[] = [(int) $value, $p];
					}
					break;

				case 'text' :
					if ($value != self::$params[$p])
					{
						if (is_array($value))
						{
							$value = Utility::jsonEncode($value);
						}
						$update_params[] = [(string) $value, $p];
					}
					break;
			}
		}

		if (empty($update_params))
		{
			return 0;
		}

		$sql = 'UPDATE {config} SET conf_value = ? WHERE conf_name = ?';
		if (!DB::execute($sql, $update_params))
		{
			return -1;
		}
		$count = DB::rowCount();

		self::getDBParams(FALSE);

		return $count;
	}

	/**
	 * Modifie les valeurs de paramètres du fichier de configuration.
	 *
	 * @param array $params
	 *   Tableau associatif avec pour clé le nom de la constante, et pour valeur
	 *   la clé du tableau $_POST contenant la nouvelle valeur de la constante.
	 *
	 * @return bool
	 *   TRUE si le fichier a été modifié avec succès,
	 *   FALSE si une erreur est survenue.
	 */
	public static function changeFileParams(array &$params): bool
	{
		// On récupère le contenu du fichier.
		if (($file_content = file(self::FILE_PATH)) === FALSE)
		{
			return FALSE;
		}

		// On parcours chaque ligne du fichier.
		foreach ($file_content as &$line)
		{
			// Si la ligne ne contient pas de constante qui se trouve dans
			// le tableau des paramètres à modifier, on passe à la suivante.
			$p = trim(preg_replace('`^\s*define\s*\(\s*\'([^\']+).*$`i', '$1', $line));
			if (!isset($params[$p]))
			{
				continue;
			}

			// Vérification du format de chaque valeur.
			if (!isset(self::FILE_PARAMS[$p]))
			{
				continue;
			}
			switch (self::FILE_PARAMS[$p]['regexp'])
			{
				// Valeur binaire pour cases à cocher.
				case 'bin' :
					$value = (int) (bool) $params[$p];
					break;

				// Vérification par regexp.
				default :
					$value = (string) $params[$p];
					if (!preg_match('`^' . self::FILE_PARAMS[$p]['regexp'] . '$`i', $value))
					{
						continue 2;
					}
					break;
			}

			// Remplacement de la valeur de la constante.
			$val = self::_formatFileValue($p, $value);

			$line = preg_replace(
				'`^\s*define\s*\(\s*\'([^\']+)\'\s*,.+\)\s*;(\s*(?:(?:#|//|/\*).*)?)$`i',
				'define(\'$1\', ' . $val . ');$2',
				$line
			);
			if ($line === NULL)
			{
				return FALSE;
			}
		}

		// On enregistre les modifications dans le fichier de configuration.
		return (bool) File::putContents(self::FILE_PATH, $file_content);
	}

	/**
	 * Récupération de tous les paramètres de configuration.
	 *
	 * @param bool $load_config
	 *   Charger les paramètres de configuration du thème ?
	 *
	 * @return bool
	 */
	public static function getDBParams(bool $load_config = TRUE): bool
	{
		if (DB::execute('SELECT * FROM {config}'))
		{
			if (count(self::$params = DB::fetchAll('conf_name', 'conf_value')) < 1)
			{
				trigger_error(__('Configuration manquante.'), E_USER_WARNING);
				return FALSE;
			}
			foreach (self::$params as &$value)
			{
				if (is_string($value) && in_array(substr($value, 0, 1), ['{', '[']))
				{
					$value = Utility::jsonDecode($value);
				}
			}

			// Paramètres du thème.
			if ($load_config)
			{
				require_once(GALLERY_ROOT . '/template/'
					. self::$params['theme_template'] . '/_config.php');
				foreach (self::FEATURES as &$v)
				{
					if (!in_array($v, THEME_FEATURES))
					{
						self::$params[$v] = 0;
					}
				}
				foreach (self::PAGES_PARAMS as $k => &$v)
				{
					if (!in_array($k, THEME_PAGES))
					{
						self::$params['pages_params'][$k]['status'] = 0;
					}
				}
				if (!in_array('custom', THEME_PAGES))
				{
					foreach (self::$params['pages_params'] as $k => &$v)
					{
						if (substr($k, 0, 6) == 'custom')
						{
							$v['status'] = 0;
						}
					}
				}
			}

			if (!self::$params['users'])
			{
				self::$params['users_only_members'] = 0;
			}

			return TRUE;
		}

		return FALSE;
	}

	/**
	 * Récupération de la valeur par défaut d'un paramètre de configuration.
	 *
	 * @param string $param
	 *   Nom du paramètre à retourner.
	 *
	 * @return mixed
	 *   Retourne une chaîne ou un tableau pour les données
	 *   correspondant au paramètre, FALSE en cas d'erreur,
	 *   ou NULL si le paramètre n'existe pas.
	 */
	public static function getDBParamDefault(string $param = '')
	{
		if (!$param)
		{
			foreach (self::DB_PARAMS as $name => &$i)
			{
				$params[$name] = $i['default'];
			}
			return $params;
		}

		if (isset(self::DB_PARAMS[$param]))
		{
			return self::DB_PARAMS[$param]['default'];
		}
	}



	/**
	 * Formate une valeur pour le fichier de configuration.
	 *
	 * @param string $name
	 * @param mixed $value
	 *
	 * @return mixed
	 */
	private static function _formatFileValue(string $name, $value)
	{
		if (self::FILE_PARAMS[$name]['type'] !== 'text')
		{
			return $value;
		}

		foreach (['\\', '\\\''] as $char)
		{
			$value = addcslashes($value, $char);
		}

		return "'$value'";
	}
}
?>