'use strict';

/**
 * Gestion du thème.
 *
 * @license https://www.gnu.org/licenses/gpl-3.0.html
 * @link https://www.igalerie.org/
 */
function Theme()
{
	// Modification de la valeur d'une propriété CSS.
	const _cssProp = (prop, val) => document.documentElement.style.setProperty(prop, val);

	// Raccourcis.
	const _q = App.q, _qAll = App.qAll;



	// Chemin du répertoire des fichiers utilisé pour le fond.
	var _backgroundPath = GALLERY.path + '/images/background/';

	// Chemin du répertoire des fichiers utilisé pour la bannière.
	var _bannersPath = GALLERY.path + '/images/banners/';

	// Sélecteur de couleur.
	var _colorPicker;

	// Indique si les options du thème ont été initialisées.
	var _optionsInit = false;

	// Indique si le panneau des options est ouvert.
	var _optionsOpen = false;

	// Paramètres du thème durant l'édition des options.
	var _themeParams;

	// Chemin du répertoire des textures.
	var _texturesPath = GALLERY.path + '/images/textures/';



	/**
	 * Initialisation.
	 *
	 * @return void
	 */
	(function()
	{
		if (!_q('#theme_template') && !THEME_USER.change)
		{
			return;
		}

		if (typeof THEME_ADMIN == 'object')
		{
			if (!THEME_ADMIN.params.style)
			{
				THEME_ADMIN.params = THEME_USER.params;
			}
			_themeParams = JSON.parse(JSON.stringify(THEME_ADMIN.params));
		}

		// Changement du style par l'utilisateur.
		if (THEME_USER.change && _q('#header_top'))
		{
			_styleButtonChange(THEME_USER.style, true);
		}
		App.click('#user_style_large a', _styleButtonClick);

		// Si les options du thème ne sont pas disponibles, on arrête là.
		if (!_q('#theme_template'))
		{
			return;
		}

		// Insertion du code HTML des options du thème.
		_q('#content').append(_q('#theme_template').content.cloneNode(true));

		// Panneau des options.
		_options();

		// Modification du style.
		_style();

		// Modification de la couleur.
		_color();

		// Gestion des textures.
		_textures();

		// Gestion des fichiers.
		_files();

		// Modification de la bannière.
		_banner();

		// Modification du fond.
		_background();

		// Code CSS personnalisé.
		_customStyle();

		// Options de la galerie.
		_gallery();

		// Options des vignettes.
		_thumbs();

		// Options d'affichage.
		_display();
	})();



	/**
	 * Gestion du fond.
	 *
	 * @return void
	 */
	function _background()
	{
		_backgroundChangeType();

		App.on('#theme_background_type input', 'change', function()
		{
			_themeParams['background'][_themeParams['style']]['type'] = this.value;
			_backgroundChangeType();
		});

		App.on('#theme_background_filename', 'change', function()
		{
			_themeParams['background'][_themeParams['style']]['file']
				= this.selectedOptions[0].value;
			_backgroundChangeFile();
		});

		App.on('#theme_background_fixed', 'change', function()
		{
			_themeParams['background'][_themeParams['style']]['fixed'] = this.checked ? 1 : 0;
			_texturesCSS('background',
				_themeParams['background'][_themeParams['style']]['texture']);
			_cssProp('--background-attachment', this.checked ? 'fixed' : 'scroll');
		});

		App.on('#theme_background_bottom_texture', 'change', function()
		{
			_themeParams['background'][_themeParams['style']]['bottom_texture']
				= this.checked ? 1 : 0;
			App.toggleClass('body', 'bottom_bg', this.checked);
		});

		App.on('#theme_background_internal_hatches', 'change', function()
		{
			_themeParams['background']['dark']['internal_hatches'] = this.checked ? 1 : 0;
			App.toggleClass('body', 'hatches', this.checked);
		});
	}

	/**
	 * Modification du code CSS du fond.
	 *
	 * @return void
	 */
	function _backgroundChangeCSS()
	{
		const style = _themeParams['style'];
		const bg = _themeParams['background'][style];

		_cssProp('--background-color', style == 'dark' ? '#111' : 'none');
		_cssProp('--background-image', 'none');

		App.toggleClass('body', 'bg', bg['type'] != 'none');
		App.toggleClass('body', 'bottom_bg', bg['bottom_texture'] == 1);
		App.toggleClass('body', 'hatches', style == 'dark' ? bg['internal_hatches'] == 1 : false);

		switch (bg['type'])
		{
			case 'file' :
				_backgroundChangeFile();
				break;

			case 'texture' :
				_texturesCSS('background', bg['texture']);
				break;
		}
	}

	/**
	 * Modification du fichier utilisé comme fond.
	 *
	 * @return void
	 */
	function _backgroundChangeFile()
	{
		const background = _themeParams['background'][_themeParams['style']];
		const file = background['file'];

		_cssProp('--background-color', _themeParams['style'] == 'dark' ? '#111' : 'none');
		_cssProp('--background-image', file ? `url(${_backgroundPath}${file})` : 'none');
		_cssProp('--background-attachment', background['fixed'] == 1 ? 'fixed' : 'scroll');

		App.removeAttr('#theme_background_filename option', 'selected');

		let selector = `#theme_background_filename option[value="${file}"]`;
		if (!_q(selector))
		{
			selector = '#theme_background_filename option:first-child';
			if (!_q(selector))
			{
				return;
			}
			_themeParams['background'][_themeParams['style']]['file'] = App.val(selector);
			_cssProp('--background-image', `url(${_backgroundPath}${App.val(selector)})`);
		}

		App.attr(selector, 'selected', '');
		_q(selector).selected = true;
	}

	/**
	 * Modification du type de fond.
	 *
	 * @return void
	 */
	function _backgroundChangeType()
	{
		_backgroundChangeCSS();

		const style = _themeParams['style'];

		_q('#theme_background_type_none').checked = false;
		_q('#theme_background_type_border').checked = false;
		_q('#theme_background_type_texture').checked = false;
		_q('#theme_background_fixed').checked = _themeParams['background'][style]['fixed'] == 1;

		App.hide('#theme_background_file');
		App.hide('#theme_background_texture');
		App.hide(_q('#theme_background_fixed').closest('p'));
		App.hide(_q('#theme_background_bottom_texture').closest('p'));
		_q('#theme_background_internal_hatches').closest('p').style.display
			= style == 'dark' ? 'block' : 'none';

		switch (_themeParams['background'][style]['type'])
		{
			case 'none' :
				_q('#theme_background_type_none').checked = true;
				App.hide(_q('#theme_background_internal_hatches').closest('p'));
				if (_themeParams['gallery']['size'] != 'small')
				{
					_q('#theme_background_bottom_texture').checked
						= _themeParams['background'][style]['bottom_texture'] == 1;
					App.show(_q('#theme_background_bottom_texture').closest('p'));
				}
				break;

			case 'border' :
				_q('#theme_background_type_border').checked = true;
				break;

			case 'file' :
				_q('#theme_background_type_file').checked = true;
				App.show('#theme_background_file');
				App.show(_q('#theme_background_fixed').closest('p'));
				break;

			case 'texture' :
				_q('#theme_background_type_texture').checked = true;
				App.show('#theme_background_texture', 'flex');
				App.show(_q('#theme_background_fixed').closest('p'));
				break;
		}

		if (style == 'dark')
		{
			_q('#theme_background_internal_hatches').checked
				= _themeParams['background'][style]['internal_hatches'] == 1;
		}
	}

	/**
	 * Gestion de la bannière.
	 *
	 * @return void
	 */
	function _banner()
	{
		_bannerChangeType();
		_bannerChangeHeight();

		App.on('#theme_banner_type input', 'change', function()
		{
			_themeParams['banner'][_themeParams['style']]['type'] = this.value;
			_bannerChangeType();
		});

		App.on('#theme_banner_filename', 'change', function()
		{
			_themeParams['banner'][_themeParams['style']]['file'] = this.selectedOptions[0].value;
			_bannerChangeFile();
		});

		App.on('#theme_banner_height', 'input', function()
		{
			_themeParams['banner'][_themeParams['style']]['height'] = this.value + 'px';
			_bannerChangeHeight();
		});
	}

	/**
	 * Modification du code CSS pour la bannière.
	 *
	 * @return void
	 */
	function _bannerChangeCSS()
	{
		const classlist = _q('#header_top').closest('header').classList;
		const banner = _themeParams['banner'][_themeParams['style']];
		const type = banner['type'];

		classlist.toggle('banner', ['file', 'texture'].includes(type));
		classlist.toggle('color', type == 'color');
		classlist.toggle('none', type == 'none');

		switch (type)
		{
			case 'file' :
				_bannerChangeFile();
				break;

			case 'texture' :
				_texturesCSS('banner', banner['texture']);
				break;
		}
	}

	/**
	 * Modification du fichier utilisé comme bannière.
	 *
	 * @return void
	 */
	function _bannerChangeFile()
	{
		const file = _themeParams['banner'][_themeParams['style']]['file'];

		_cssProp('--banner-color', 'transparent');
		_cssProp('--banner-image', file ? `url(${_bannersPath}${file})` : 'none');
		_cssProp('--banner-size', 'cover');
		_cssProp('--banner-position', 'center');
		_cssProp('--banner-repeat', 'no-repeat');

		App.removeAttr('#theme_banner_filename option', 'selected');

		let selector = `#theme_banner_filename option[value="${file}"]`;
		if (!_q(selector))
		{
			selector = '#theme_banner_filename option:first-child';
			if (!_q(selector))
			{
				return;
			}
			_themeParams['banner'][_themeParams['style']]['file'] = App.val(selector);
			_cssProp('--banner-image', `url(${_bannersPath}${App.val(selector)})`);
		}

		App.attr(selector, 'selected', '');
		_q(selector).selected = true;
	}

	/**
	 * Modification de la hauteur de la bannière.
	 *
	 * @return void
	 */
	function _bannerChangeHeight()
	{
		_bannerChangeHeightCSS();

		const val = parseInt(_themeParams['banner'][_themeParams['style']]['height']);

		App.val('#theme_banner_height', val);
		App.text('#theme_banner_height + span', val + ' px');
	}

	/**
	 * Modification du code CSS de la hauteur de la bannière.
	 *
	 * @return void
	 */
	function _bannerChangeHeightCSS()
	{
		_cssProp('--header-height', _themeParams['banner'][_themeParams['style']]['height']);
	}

	/**
	 * Modification de la couleur de fond des textures utilisées pour la bannière.
	 *
	 * @param string color
	 *
	 * @return void
	 */
	function _bannerChangeTexturesColor(color)
	{
		if (_themeParams['style'] == 'clear')
		{
			// Changement de la couleur des textures de la liste des textures.
			App.style('div[data-type="banner"] .theme_textures_images div',
			{
				backgroundColor: color
			});

			// Changement de la couleur de la bannière.
			_cssProp('--banner-color', color);
		}
	}

	/**
	 * Modification du type de bannière.
	 *
	 * @return void
	 */
	function _bannerChangeType()
	{
		_bannerChangeCSS();

		App.each('#theme_banner_type input', elem => elem.checked = false);
		App.hide('#theme_banner_file');
		App.hide('#theme_banner_texture');
		App.hide(_q('#theme_banner_height').closest('p'));

		switch (_themeParams['banner'][_themeParams['style']]['type'])
		{
			case 'color' :
				_q('#theme_banner_type_color').checked = true;
				break;

			case 'file' :
				_q('#theme_banner_type_file').checked = true;
				App.show('#theme_banner_file');
				App.show(_q('#theme_banner_height').closest('p'));
				break;

			case 'none' :
				_q('#theme_banner_type_none').checked = true;
				break;

			case 'texture' :
				_q('#theme_banner_type_texture').checked = true;
				App.show('#theme_banner_texture', 'flex');
				App.show(_q('#theme_banner_height').closest('p'));
				break;
		}
	}

	/**
	 * Gestion de la couleur du thème.
	 *
	 * @return void
	 */
	function _color()
	{
		// Type de couleur : prédéfinie ou personnalisée.
		App.on('input[name="theme_color_type"]', 'change', function()
		{
			if (this.value == 'palette')
			{
				App.show('#theme_palette');
				App.hide('#theme_custom_color');

				_colorChangePalette(_themeParams['color'][_themeParams['style']]);
			}
			else
			{
				App.hide('#theme_palette');
				App.show('#theme_custom_color');
			}
		});

		// Couleurs prédéfinies.
		const palette =
		[
			'575757', '966b3c', '877240', '888040', '7f8840', '61893d', '3d8946',
			'828282', '977857', '877b5a', '9d933f', '8f9d3f', '76a64b', '5fa567',
			'3a8e67', '369291', '328296', '3b7ab5', '3b5eb5', '584eb5', '873d9f',
			'37a575', '2daeb5', '159dc4', '6492d8', '738de0', '7e6eb8', 'b577dd',
			'9d3da6', 'b52262', 'e85392', 'd22828', 'd85c18', 'cd842d', 'c89418',
			'd15cd9', 'd575bb', 'de6cac', 'd54949', 'd55949', 'd47149', 'c47e2c'
		];
		palette.forEach(code =>
		{
			App.append('#theme_palette', `<a href="javascript:;" data-code="#${code}"></a>`);
		});
		App.each('#theme_palette a', elem =>
		{
			const color = App.attr(elem, 'data-code');

			elem.style.background = color;
			App.click(elem, evt => _colorChangePalette(color));
		});

		// Sélecteur de couleur.
		const color_init = _themeParams['color'][_themeParams['style']];
		_colorPicker = new iro.ColorPicker('#theme_color_picker',
		{
			color: color_init,
			width: 300
		});
		function color_picker_change()
		{
			const color = _colorPicker.color.hexString;

			App.val('#theme_color_code', color);
			_cssProp('--color', color);
			_themeParams['color'][_themeParams['style']] = color;
			_bannerChangeTexturesColor(color);
			_customStyleChange();
		}
		_colorPicker.on('color:change', color_picker_change);

		// Code couleur.
		App.val('#theme_color_code', color_init);
		App.on('#theme_color_code', 'input', function()
		{
			if (RegExp('^#[a-f0-9]{6}$', 'i').test(this.value))
			{
				_colorPicker.color.hexString = this.value;
				color_picker_change();
			}
		});

		// Couleur initiale.
		_colorChange(color_init);
	}

	/**
	 * Modification de la couleur du thème.
	 *
	 * @param string color
	 *
	 * @return void
	 */
	function _colorChange(color)
	{
		if (_q(`#theme_palette a[data-code="${color}"]`))
		{
			_q('#theme_color_type_palette').checked = true;
			_q('#theme_color_type_custom').checked = false;
			App.show('#theme_palette');
			App.hide('#theme_custom_color');
			_colorChangePalette(color);
		}
		else
		{
			_q('#theme_color_type_palette').checked = false;
			_q('#theme_color_type_custom').checked = true;
			App.hide('#theme_palette');
			App.show('#theme_custom_color');
			_colorPicker.color.hexString = color;
		}
	}

	/**
	 * Couleur prédéfinie.
	 *
	 * @param string color
	 *
	 * @return void
	 */
	function _colorChangePalette(color)
	{
		_colorPicker.color.hexString = color;
		_cssProp('--color', color);

		App.removeClass('#theme_palette a', 'current');
		App.addClass(`#theme_palette a[data-code="${color}"]`, 'current');

		_bannerChangeTexturesColor(color);
		_themeParams['color'][_themeParams['style']] = color;
		_customStyleChange();
	}

	/**
	 * Gestion du code CSS personnalisé.
	 *
	 * @return void
	 */
	function _customStyle()
	{
		_customStyleChange(true);

		App.on('#theme_css_code', 'input', function()
		{
			_themeParams['css'][_themeParams['style']] = this.value;
			_customStyleChange();
		});
	}

	/**
	 * Modification du code CSS personnalisé.
	 *
	 * @param bool init
	 *
	 * @return void
	 */
	function _customStyleChange(init = false)
	{
		const css = _themeParams['css'][_themeParams['style']];

		if (_q('#theme_css_code'))
		{
			_q('#theme_css_code').value = css;
		}

		if (!init)
		{
			_q('#style_custom').textContent = css.replace(
				/(\{(?:[\s\S](?![{}]))*?)(#color|#gallery_path)((?:[\s\S](?![{]))*?\})/gi,
				m =>
				{
					return m.replace(/#color/gi, _themeParams['color'][_themeParams['style']])
							.replace(/#gallery_path/, GALLERY.path);
				}
			);
		}
	}

	/**
	 * Gestion des options d'affichage.
	 *
	 * @return void
	 */
	function _display()
	{
		for (const name in _themeParams['display'])
		{
			const display = _q('#theme_display_' + name);
			if (display)
			{
				display.checked = _themeParams['display'][name] == '1';
				App.on(display, 'change', function()
				{
					const name = this.id.replace('theme_display_', '');
					_themeParams['display'][name] = this.checked ? '1' : '0';
					App.toggleClass(`*[data-option-display="${name}"]`, 'show', this.checked);
				});
			}
		}
	}

	/**
	 * Gestion des fichiers.
	 *
	 * @return void
	 */
	function _files()
	{
		// Bouton de rechargement de la liste des fichiers.
		App.click('.theme_file_icons a[data-dir]', function()
		{
			if (App.hasClass(this, 'load'))
			{
				return;
			}

			App.removeClass(this, 'rotate');
			App.addClass(this, 'load');

			_filesAjax([App.attr(this, 'data-dir')], () =>
			{
				App.removeClass(this, 'load');
				App.addClass(this, 'rotate');
			});
		});
	}

	function _filesAjax(dir, callback)
	{
		App.ajax(
		{
			section: 'theme-files',
			dir: dir
		},
		{
			success: r =>
			{
				dir.forEach(name =>
				{
					const select = _q(_q(`[data-dir="${name}"]`).closest('p'), 'select');
					App.empty(select);

					for (const file of r.files[name])
					{
						const option = document.createElement('option');
						App.val(option, file);
						App.text(option, file);
						select.append(option);
					}

					if (name == 'background'
					&& _themeParams['background'][_themeParams['style']]['type'] == 'file')
					{
						_backgroundChangeFile();
					}
					if (name == 'banners'
					&& _themeParams['banner'][_themeParams['style']]['type'] == 'file')
					{
						_bannerChangeFile();
					}
				});

				callback?.();
			}
		});
	}

	/**
	 * Gestion des options de la galerie.
	 *
	 * @return void
	 */
	function _gallery()
	{
		// Largeur de la galerie.
		_galleryChangeSize();

		App.on('input[name="theme_gallery_size"]', 'change', function()
		{
			_themeParams['gallery']['size'] = this.value;
			_galleryChangeSize();
			_backgroundChangeType();
		});

		// Taille du texte.
		[100, 105, 110, 115, 120].forEach(size =>
		{
			App.append('#theme_text_size', `<option value="${size}">${size}</option>`);
		});

		_galleryChangeTextSize();

		App.on('#theme_text_size', 'change', function()
		{
			App.removeAttr([this, 'option'], 'selected');
			App.attr(this.selectedOptions[0], 'selected', '');
			_themeParams['text']['size'] = this.selectedOptions[0].value;
			_galleryChangeTextSize();
		});

		// Largeur des descriptions.
		_galleryChangeDescWidthLimit();

		_q('#theme_text_desc_width_limit').checked
			= _themeParams['text']['desc_width_limit'] == 1;

		App.on('#theme_text_desc_width_limit', 'change', function()
		{
			_themeParams['text']['desc_width_limit'] = this.checked ? 1 : 0;
			_galleryChangeDescWidthLimit();
		});

		// Largeur du menu.
		_galleryChangeMenuWidth();

		App.on('#theme_menu_width', 'input', function()
		{
			_themeParams['menu']['width'] = this.value;
			_galleryChangeMenuWidth();
		});
	}

	/**
	 * Modification de la largeur des descriptions.
	 *
	 * @return void
	 */
	function _galleryChangeDescWidthLimit()
	{
		_cssProp('--desc-max-width', _themeParams['text']['desc_width_limit'] == 1
			? 'min(80%, 900px)'
			: 'none');
	}

	/**
	 * Modification de la largeur du menu.
	 *
	 * @return void
	 */
	function _galleryChangeMenuWidth()
	{
		const val = _themeParams['menu']['width'];
		_cssProp('--menu-max-width', val + '%');

		App.val('#theme_menu_width', val);
		App.text('#theme_menu_width + span', val + ' %');
	}

	/**
	 * Modification de la largeur de la galerie.
	 *
	 * @return void
	 */
	function _galleryChangeSize()
	{
		const gallery_size = _themeParams['gallery']['size'];
		_q('#theme_gallery_size_' + gallery_size).checked = true;
		_q('#gallery').className = gallery_size;
	}

	/**
	 * Modification de la taille du texte.
	 *
	 * @return void
	 */
	function _galleryChangeTextSize()
	{
		const val = _themeParams['text']['size'];
		_cssProp('--text-size', val + '%');

		const current = _q(`#theme_text_size option[value="${parseInt(val)}"]`);
		current.selected = true;
		App.attr(current, 'selected', '');
	}

	/**
	 * Gestion du panneau des options.
	 *
	 * @return void
	 */
	function _options()
	{
		// Bouton pour accéder aux options.
		let open_transition = false;
		App.click('#theme_options_icon a', () =>
		{
			if (!open_transition)
			{
				open_transition = true;
				App.show('#theme_options form');
				App.toggleClass('#theme_options', 'open');
			}
		});
		App.on('#theme_options', 'transitionend', function(evt)
		{
			if (evt.target != this)
			{
				return;
			}
			if (_optionsOpen)
			{
				_optionsOpen = false;
				THEME_ADMIN.params = JSON.parse(JSON.stringify(_themeParams));
				if (THEME_USER.change == 1)
				{
					const is_style = typeof THEME_USER.params.style != 'undefined';
					if (is_style)
					{
						_themeParams = JSON.parse(JSON.stringify(THEME_USER.params));
					}
					_styleChange(is_style ? THEME_USER.style : THEME.style);
				}
				_q('#theme_options_icon a').focus();

				// Quand les options sont cachées, on désactive l'affichage du
				// formulaire afin d'éviter que les éléments du formulaire soient
				// atteignables lors d'une navigation au clavier.
				App.hide('#theme_options form');
			}
			else
			{
				_optionsOpen = true;
				_themeParams = JSON.parse(JSON.stringify(THEME_ADMIN.params));
				_styleChange(THEME.style);

				if (!_optionsInit)
				{
					_filesAjax(['background', 'banners']);
					_optionsInit = true;
				}
			}
			open_transition = false;
		});

		// Menu.
		App.click('#theme_options_menu a', function()
		{
			App.hide('#theme_options fieldset');
			App.removeClass('#theme_options_menu a.current', 'current');
			App.show('#' + App.attr(this, 'data-id'));
			App.addClass(this, 'current');
		});

		// Aide contextuelle.
		App.click('#theme_options .infos_icon', function()
		{
			const i = _q('#' + App.attr(this, 'data-id'));
			i.style.display = i.checkVisibility() ? 'none' : 'block';
		});

		// Enregistrement des paramètres.
		const submit = _q('#theme_options input[type="submit"]');
		let hide_report_timeout;
		function theme_report_hide()
		{
			clearTimeout(hide_report_timeout);
			App.remove('[id^="theme_report"]');
			App.removeAttr(submit, 'disabled');
			submit.blur();
		}
		App.on('#theme_options form', 'submit', evt =>
		{
			evt.preventDefault();

			THEME_ADMIN.params = JSON.parse(JSON.stringify(_themeParams));
			if (typeof THEME_USER.params.style != 'undefined')
			{
				THEME_USER.params = JSON.parse(JSON.stringify(_themeParams));
			}
			function message(type, message)
			{
				App.append('#theme_options_buttons',
					`<div id="theme_report_${type}">` +
						`<span class="message_${type}"></span>` +
					`</div>`);
				App.click('[id^="theme_report"]', theme_report_hide);
				App.text(`#theme_report_${type} span`, message);

				App.remove('#theme_loading');

				App.show('#theme_report_' + type, 250, 'flex');
				hide_report_timeout = setTimeout(() =>
				{
					App.hide('#theme_report_' + type, 250, theme_report_hide);
				}, 2000);
			}

			App.attr(submit, 'disabled', '');
			App.append('#theme_options_buttons', '<div id="theme_loading"></div>');

			App.ajax(
			{
				section: 'theme-params',
				template: THEME_ADMIN.dir,
				params: _themeParams
			},
			{
				error: r => message(r.status, r.message),
				info: r => message(r.status, r.message),
				success: r => message(r.status, r.message),
			});
		});

		// Bouton "annuler".
		App.click('#theme_options form input[name="cancel"]',
			() => _q('#theme_options_icon a').click());
	}

	/**
	 * Gestion du style.
	 *
	 * @return void
	 */
	function _style()
	{
		// Style clair ou sombre.
		_q('#theme_style_clear').checked = THEME.style == 'clear';
		_q('#theme_style_dark').checked = THEME.style == 'dark';

		App.on('input[name="theme_style"]', 'change', function()
		{
			THEME.style = this.value;
			_styleChange(THEME.style);
			_styleButtonChange(THEME.style, _q('#user_style_large.active') ? true : false);
		});

		// Autoriser les visiteurs à changer le style.
		_q('#theme_style_change').checked = _themeParams['style_change'] == 1;

		App.on('#theme_style_change', 'change', function()
		{
			_themeParams['style_change'] = THEME_USER.change = this.checked ? 1 : 0;
			_styleButtonChange(_themeParams['style'], this.checked);
		});

		// Boutons de formulaires.
		_styleChangeFormButtons();

		App.on('input[name="theme_form_buttons_style"]', 'change', function()
		{
			_themeParams['buttons'][_themeParams['style']]['style'] = this.value;
			_styleChangeFormButtons();
		});
	}

	/**
	 * Modification du bouton de changement de style.
	 *
	 * @param string style
	 * @param bool active
	 *
	 * @return void
	 */
	function _styleButtonChange(style, active)
	{
		const large = _q('#user_style_large');
		const large_a = _q('#user_style_large a');

		App.removeClass(large, 'active');
		App.remove('#user_style_small');

		if (active)
		{
			const cursor = _optionsOpen ? 'not-allowed' : 'pointer';
			const data_style = style == 'dark' ? 'clear' : 'dark';
			const icon = style == 'dark' ? '&#xe902;' : '&#xe908;';
			const tag = _q('#user_menu') ? 'li' : 'div';

			App.addClass(large, 'active');
			App.attr(large, 'data-style', data_style);
			App.html(large_a, icon);
			large_a.style.cursor = cursor;

			_q(_q('#user_menu') ? '#user_menu' : '#title').insertAdjacentHTML(
				_q('#user_menu') ? 'afterbegin' : 'afterend',
				`<${tag} data-style="${data_style}" id="user_style_small">` +
					`<a href="javascript:;">${icon}</a>` +
				`</${tag}>`
			);

			_q('#user_style_small a').style.cursor = cursor;
			App.click('#user_style_small a', _styleButtonClick);
		}
	}

	/**
	 * Gestion de l'événement "click" sur le bouton de changement de style.
	 *
	 * @return void
	 */
	function _styleButtonClick()
	{
		if (_q('#theme_options') && _optionsOpen)
		{
			return;
		}

		THEME_USER.style = App.attr(this.parentElement, 'data-style');
		if (typeof THEME_USER.params.style != 'undefined')
		{
			_themeParams = JSON.parse(JSON.stringify(THEME_USER.params));
		}
		else
		{
			THEME_USER.params = JSON.parse(JSON.stringify(THEME_ADMIN.params));
		}
		_styleButtonChange(THEME_USER.style, true);
		_styleChange(THEME_USER.style);
		_cssProp('--color', _themeParams['color'][THEME_USER.style]);

		App.ajax(
		{
			section: 'cookie-prefs-write',
			param: 'theme_default_user_style',
			value: THEME_USER.style
		});
	}

	/**
	 * Effectue toutes les modifications liées au changement de style.
	 *
	 * @param string style
	 *
	 * @return void
	 */
	function _styleChange(style)
	{
		if (style != 'dark' && _q('#style_dark'))
		{
			App.remove('#style_dark');
		}
		if (style == 'dark' && !_q('#style_dark') && THEME.path.substring(0, 1) == '/')
		{
			const dark = document.createElement('link');
			App.attr(dark,
			{
				'rel': 'stylesheet',
				'id': 'style_dark',
				'type': 'text/css',
				'media': 'screen',
				'title': 'style',
				'href': THEME.path + '/style/dark.css?' + GALLERY.version_key
			});
			App.after('#style_clear', dark);
		}

		_themeParams['style'] = style;

		_styleButtonChange(style, THEME_USER.change == 1);

		if (_q('#theme_options'))
		{
			_colorChange(_themeParams['color'][style]);

			_texturesList('banner');
			_texturesList('background');

			_bannerChangeType();
			_bannerChangeHeight();
			_backgroundChangeType();
			_styleChangeFormButtons();
		}
		else
		{
			_backgroundChangeCSS();
			_bannerChangeCSS();
			_bannerChangeHeightCSS();
			_styleChangeFormButtonsCSS();
		}

		_customStyleChange();
	}

	/**
	 * Style des boutons de formulaires.
	 *
	 * @return void
	 */
	function _styleChangeFormButtons()
	{
		_styleChangeFormButtonsCSS();

		_q('#theme_form_buttons_style_1').checked = false;
		_q('#theme_form_buttons_style_2').checked = false;
		_q('#theme_form_buttons_style_'
			+ _themeParams['buttons'][_themeParams['style']]['style']).checked = true;
	}

	/**
	 * Modification du code CSS des boutons de formulaires.
	 *
	 * @return void
	 */
	function _styleChangeFormButtonsCSS()
	{
		App.toggleClass('body',
			'btn_2_' + _themeParams['style'],
			_themeParams['buttons'][_themeParams['style']]['style'] == 2
		);
		App.toggleClass('body',
			'btn_2_' + (_themeParams['style'] == 'dark' ? 'clear' : 'dark'),
			false
		);
	}

	/**
	 * Gestion des textures.
	 *
	 * @return void
	 */
	function _textures()
	{
		// Création des listes de textures.
		_texturesList('banner');
		_texturesList('background');

		// Boutons de navigation au sein des textures.
		App.click('.theme_textures_next,.theme_textures_prev', function()
		{
			if (!App.hasClass(this, 'disabled'))
			{
				_texturesList(
					App.attr(this.parentElement, 'data-type'),
					App.hasClass(this, 'theme_textures_next') ? 1 : -1
				);
			}
		});
	}

	/**
	 * Modifie les paramètres CSS des textures.
	 *
	 * @param string name
	 * @param string file
	 *
	 * @return void
	 */
	function _texturesCSS(name, file)
	{
		const style = _themeParams['style'];
		if (_themeParams[name][style]['type'] == 'texture')
		{
			const color = THEME.textures[name][style][file] == ''
				? _themeParams['color'][_themeParams['style']]
				: THEME.textures[name][style][file];
			const attachment = name == 'background' && _themeParams[name][style]['fixed'] == 1
				? 'fixed'
				: 'scroll';

			_cssProp(`--${name}-attachment`, attachment);
			_cssProp(`--${name}-color`, color);
			_cssProp(`--${name}-image`, `url(${_texturesPath}${file})`);
			_cssProp(`--${name}-size`, 'auto');
			_cssProp(`--${name}-position`, '0 0');
			_cssProp(`--${name}-repeat`, 'repeat');
		}
	}

	/**
	 * Fabrication des listes de textures.
	 *
	 * @param string type
	 * @param int next_page
	 *
	 * @return void
	 */
	function _texturesList(type, next_page = 0)
	{
		const list = _q(`#theme_options div[data-type="${type}"]`);
		const style = _themeParams['style'];
		const items_count = Object.keys(THEME.textures[type][style]).length;
		const nb_per_page = 3;
		const pages_count = Math.ceil(items_count / nb_per_page);

		// Image et page courantes.
		let current_page = 1;
		let current_item = 0;
		let i = 1;
		for (const file in THEME.textures[type][style])
		{
			if (file == _themeParams[type][style]['texture'])
			{
				current_item = i;
				current_page = Math.ceil(i / nb_per_page);
				break;
			}
			i++;
		}
		if (next_page)
		{
			current_page = parseInt(App.attr(list, 'data-page')) + next_page;
		}
		App.attr(list, 'data-page', current_page);

		// Création de chaque image.
		const end = current_page * nb_per_page;
		const start = 1 + end - nb_per_page;
		const images = _q(list, '.theme_textures_images');
		App.empty(images);
		i = 1;
		for (const file in THEME.textures[type][style])
		{
			if (i >= start && i <= end)
			{
				const color = THEME.textures[type][style][file] == ''
					? _themeParams['color'][_themeParams['style']]
					: THEME.textures[type][style][file];
				const div = document.createElement('div');
				App.attr(div, 'data-texture', file);
				if (i == current_item)
				{
					App.addClass(div, 'selected');
				}
				div.style.background = `${color} url(${_texturesPath}${file})`;
				images.append(div);
			}
			i++;
		}

		// Boutons de navigation entre les pages de textures.
		App.addClass([list, 'div:has(span)'], 'disabled');
		if (current_page > 1)
		{
			App.removeClass([list, '.theme_textures_prev'], 'disabled');
		}
		if (current_page != pages_count)
		{
			App.removeClass([list, '.theme_textures_next'], 'disabled');
		}

		// Sélection d'une texture.
		App.click([images, 'div'], function()
		{
			const file = App.attr(this, 'data-texture');
			const type = App.attr(this.closest('.theme_textures'), 'data-type');
			const current = _themeParams[type][_themeParams['style']]['texture'];

			if (file != current)
			{
				_texturesCSS(type, file);
				_themeParams[type][_themeParams['style']]['texture'] = file;
				App.removeClass([this.parentElement, 'div'], 'selected');
				App.addClass(this, 'selected');
			}
		});
	}

	/**
	 * Gestion des vignettes.
	 *
	 * @return void
	 */
	function _thumbs()
	{
		_q('#theme_thumbs_cat_size_' + _themeParams['thumbs_cat']['size'].replace(' ', '_'))
			.checked = true;
		_q('#theme_thumbs_cat_type_' + _themeParams['thumbs_cat']['layout']).checked = true;
		_q('#theme_thumbs_items_size_' + _themeParams['thumbs_items']['size']).checked = true;
		_q('#theme_thumbs_items_type_' + _themeParams['thumbs_items']['layout']).checked = true;

		App.on('input[name="theme_thumbs_cat_size"]', 'change', function()
		{
			_themeParams['thumbs_cat']['size'] = this.value;
			_galleryChangeSize();
			_thumbsCatChange();
		});

		App.on('input[name="theme_thumbs_cat_type"]', 'change', function()
		{
			_themeParams['thumbs_cat']['layout'] = this.value;
			_thumbsCatChange();
		});

		App.on('input[name="theme_thumbs_items_size"]', 'change', function()
		{
			_themeParams['thumbs_items']['size'] = this.value;
			_galleryChangeSize();
			_thumbsItemsChange();
		});

		App.on('input[name="theme_thumbs_items_type"]', 'change', function()
		{
			_themeParams['thumbs_items']['layout'] = this.value;
			_thumbsItemsChange();
		});
	}

	/**
	 * Modification des vignettes de catégories.
	 *
	 * @return void
	 */
	function _thumbsCatChange()
	{
		if (!_q('#thumbs_cat'))
		{
			return;
		}

		const cat_id = [];
		const layout = _themeParams['thumbs_cat']['layout'];
		const size = _themeParams['thumbs_cat']['size'];

		App.each('#thumbs_cat dt a', elem => cat_id.push(parseInt(App.attr(elem, 'data-id'))));
		if (!cat_id.length)
		{
			return;
		}

		GALLERY.thumbs_cat_size = (() =>
		{
			switch (layout)
			{
				case 'portrait' :
					return size == 'large' ? '363x544' : '232x348';
				case 'square' :
					return size == 'large' ? '363x363' : '232x232';
				default :
					return size == 'large' ? '363x262' : '232x167';
			}
		})();

		App.ajax(
		{
			section: 'thumbs-cat-source',
			cat_id: cat_id,
			size: GALLERY.thumbs_cat_size
		},
		{
			error: r => alert('error: ' + r.message),
			success: r =>
			{
				App.removeClass('#thumbs_cat', 'small', 'large',
					'landscape', 'portrait', 'square', 'standard');
				App.addClass('#thumbs_cat', layout, size);
				for (const id in r.thumbs_source)
				{
					App.attr(`#thumbs_cat dt a[data-id="${id}"] img`, 'src', r.thumbs_source[id]);
				}
			}
		});
	}

	/**
	 * Modification des vignettes de fichiers.
	 *
	 * @return void
	 */
	function _thumbsItemsChange()
	{
		if (!_qAll('.thumbs_items'))
		{
			return;
		}

		const items_id = [];
		const layout = _themeParams['thumbs_items']['layout'];
		const size = _themeParams['thumbs_items']['size'];

		App.each('.thumbs_items *[data-id]', elem =>
		{
			items_id.push(parseInt(App.attr(elem, 'data-id')));
		});
		if (!items_id.length)
		{
			return;
		}

		GALLERY.thumbs_items_size = (() =>
		{
			switch (layout)
			{
				case 'landscape' :
					return size == 'superlarge'
						? '378x252'
						: (size == 'large' ? '248x165' : '161x107');
				case 'portrait' :
					return size == 'superlarge'
						? '378x566'
						: (size == 'large' ? '248x371' : '161x241');
				case 'square' :
					return size == 'superlarge'
						? '378x378'
						: (size == 'large' ? '248x248' : '161x161');
				default :
					return size == 'superlarge'
						? '368'
						: (size == 'large' ? '238' : '151');
			}
		})();

		App.ajax(
		{
			section: 'thumbs-items-source',
			items_id: items_id,
			size: GALLERY.thumbs_items_size
		},
		{
			error: r => alert('error: ' + r.message),
			success: r =>
			{
				App.removeClass('.thumbs_items', 'small', 'large', 'superlarge',
					'landscape', 'portrait', 'square', 'standard');
				App.addClass('.thumbs_items', layout, size);
				for (const id in r.thumbs_source)
				{
					App.attr(`.thumbs_items *[data-id="${id}"] img`, 'src', r.thumbs_source[id]);
				}
			}
		});
	}
}