<?php namespace HashOver;

// Copyright (C) 2018-2019 Jacob Barkdull
// This file is part of HashOver.
//
// HashOver is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// HashOver is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with HashOver.  If not, see <http://www.gnu.org/licenses/>.


// Generates an array of various settings information
function ui_array (Setup $setup, Locale $locale)
{
	// Theme names
	$themes = array ();

	// Themes directory
	$themes_directory = $setup->getAbsolutePath ('themes');

	// Get each theme directory name
	foreach (glob ($themes_directory . '/*', GLOB_ONLYDIR) as $directory) {
		$theme = basename ($directory);
		$themes[$theme] = $theme;
	}

	// Form fields options
	$field_options = array (
		'on'		=> $locale->text['enabled'],
		'required'	=> $locale->text['required'],
		'off'		=> $locale->text['disabled'],
	);

	// Return array of settings allowed to be changed
	return array (
		'general' => array (
			'language' => array (
				'type' => 'select',
				'value' => $setup->language,

				'options' => array (
					'en-us' => 'English',
					'pt-br' => 'Brazilian Portuguese',
					'da-dk' => 'Danish',
					'nl-nl' => 'Dutch',
					'eo-eo' => 'Esperanto',
					'fr-fr' => 'French',
					'de-de' => 'German',
					'el-el' => 'Greek',
					'ja-jp' => 'Japanese',
					'ko-kr' => 'Korean',
					'lt-lt' => 'Lithuanian',
					'fa-ir' => 'Persian',
					'pl-pl' => 'Polish',
					'ro-ro' => 'Romanian',
					'ru-ru' => 'Russian',
					'zh-cn' => 'Simplified Chinese',
					'es-es' => 'Spanish',
					'tr-tr' => 'Turkish',
					'ar-sy' => 'Arabic'
				)
			),

			'theme' => array (
				'type' => 'select',
				'value' => $setup->theme,
				'options' => $themes
			),

			'default-sorting' => array (
				'type' => 'select',
				'value' => $setup->defaultSorting,

				'options' => array (
					'ascending'	=> $locale->text['sort-ascending'],
					'descending'	=> $locale->text['sort-descending'],
					'by-date'	=> $locale->text['sort-by-date'],
					'by-likes'	=> $locale->text['sort-by-likes'],
					'by-replies'	=> $locale->text['sort-by-replies'],
					'by-name'	=> $locale->text['sort-by-name'],

					'sort-threads' => array (
						'threaded-descending'	=> $locale->text['sort-descending'],
						'threaded-by-date'	=> $locale->text['sort-by-date'],
						'threaded-by-likes'	=> $locale->text['sort-by-likes'],
						'by-popularity'		=> $locale->text['sort-by-popularity'],
						'by-discussion'		=> $locale->text['sort-by-discussion'],
						'threaded-by-name'	=> $locale->text['sort-by-name']
					)
				)
			),

			'uses-markdown' => array (
				'type' => 'checkbox',
				'value' => $setup->usesMarkdown
			),

			'uses-ajax' => array (
				'type' => 'checkbox',
				'value' => $setup->usesAjax
			),

			'shows-reply-count' => array (
				'type' => 'checkbox',
				'value' => $setup->showsReplyCount
			),

			'allows-images' => array (
				'type' => 'checkbox',
				'value' => $setup->allowsImages
			),

			'allows-likes' => array (
				'type' => 'checkbox',
				'value' => $setup->allowsLikes
			),

			'allows-dislikes' => array (
				'type' => 'checkbox',
				'value' => $setup->allowsDislikes
			)
		),

		'moderation' => array (
			'uses-moderation' => array (
				'type' => 'checkbox',
				'value' => $setup->usesModeration
			),

			'pends-user-edits' => array (
				'type' => 'checkbox',
				'value' => $setup->pendsUserEdits
			)
		),

		'e-mail' => array (
			'mail-type' => array (
				'type' => 'select',
				'value' => $setup->mailType,

				'options' => array (
					'text' => 'Text',
					'html' => 'HTML'
				)
			),

			'mailer' => array (
				'type' => 'select',
				'value' => $setup->mailer,

				'options' => array (
					'sendmail' => 'Sendmail',
					'smtp' => 'SMTP'
				)
			),

			'subscribes-user' => array (
				'type' => 'checkbox',
				'value' => $setup->subscribesUser
			),

			'allows-user-replies' => array (
				'type' => 'checkbox',
				'value' => $setup->allowsUserReplies
			)
		),

		'cookies' => array (
			'sets-cookies' => array (
				'type' => 'checkbox',
				'value' => $setup->setsCookies
			),

			'cookie-expiration' => array (
				'type' => 'text',
				'documentation'=> 'https://www.php.net/manual/en/datetime.formats.relative.php',
				'value' => $setup->cookieExpiration
			),

			'secure-cookies' => array (
				'type' => 'checkbox',
				'value' => $setup->secureCookies
			)
		),

		'comment-collapsing' => array (
			'collapses-interface' => array (
				'type' => 'checkbox',
				'value' => $setup->collapsesInterface
			),

			'collapses-comments' => array (
				'type' => 'checkbox',
				'value' => $setup->collapsesComments
			),

			'collapse-limit' => array (
				'type' => 'number',
				'value' => $setup->collapseLimit
			)
		),

		'popular-comments' => array (
			'popularity-threshold' => array (
				'type' => 'number',
				'value' => $setup->popularityThreshold
			),

			'popularity-limit' => array (
				'type' => 'number',
				'value' => $setup->popularityLimit
			)
		),

		'spam-protection' => array (
			'spam-database' => array (
				'type' => 'select',
				'value' => $setup->spamDatabase,

				'options' => array (
					'remote' => 'StopForumSpam.com',
					'local' => 'Local CSV file'
				)
			),

			'spam-check-modes' => array (
				'type' => 'select',
				'value' => $setup->spamCheckModes,

				'options' => array (
					'both' => 'Both',
					'json' => 'JavaScript',
					'php' => 'PHP'
				)
			)
		),

		'avatars' => array (
			'icon-mode' => array (
				'type' => 'select',
				'value' => $setup->iconMode,

				'options' => array (
					'image' => 'Image',
					'count' => 'Count',
					'none' => 'None'
				)
			),

			'icon-size' => array (
				'type' => 'number',
				'value' => $setup->iconSize
			),

			'gravatar-default' => array (
				'type' => 'select',
				'value' => $setup->gravatarDefault,

				'options' => array (
					'custom' => 'Custom',
					'identicon' => 'Identicon',
					'monsterid' => 'Monsterid',
					'wavatar' => 'Wavatar',
					'retro' => 'Retro'
				)
			),

			'gravatar-force' => array (
				'type' => 'checkbox',
				'value' => $setup->gravatarForce
			)
		),

		'form-fields' => array (
			'form-position' => array (
				'type' => 'select',
				'value' => $setup->formPosition,

				'options' => array (
					'top' => 'Top',
					'bottom' => 'Bottom'
				)
			),

			'name-field' => array (
				'type' => 'select',
				'value' => $setup->nameField,
				'options' => $field_options
			),

			'password-field' => array (
				'type' => 'select',
				'value' => $setup->passwordField,
				'options' => $field_options
			),

			'email-field' => array (
				'type' => 'select',
				'value' => $setup->emailField,
				'options' => $field_options
			),

			'website-field' => array (
				'type' => 'select',
				'value' => $setup->websiteField,
				'options' => $field_options
			),

			'displays-title' => array (
				'type' => 'checkbox',
				'value' => $setup->displaysTitle
			),

			'uses-cancel-buttons' => array (
				'type' => 'checkbox',
				'value' => $setup->usesCancelButtons
			),

			'uses-labels' => array (
				'type' => 'checkbox',
				'value' => $setup->usesLabels
			)
		),

		'date-time' => array (
			'date-pattern' => array (
				'documentation' => 'http://userguide.icu-project.org/formatparse/datetime',
				'type' => 'text',
				'value' => $setup->datePattern
			),

			'time-pattern' => array (
				'type' => 'text',
				'value' => $setup->timePattern
			),

			'server-timezone' => array (
				'documentation' => 'https://php.net/manual/en/timezones.php',
				'type' => 'text',
				'value' => $setup->serverTimezone
			),

			'uses-user-timezone' => array (
				'type' => 'checkbox',
				'value' => $setup->usesUserTimezone
			),

			'uses-short-dates' => array (
				'type' => 'checkbox',
				'value' => $setup->usesShortDates
			)
		),

		'login' => array (
			'login-method' => array (
				'type' => 'select',
				'value' => $setup->loginMethod,

				'options' => array (
					'DefaultLogin' => 'Cookies Login',
					'SessionLogin' => 'Session Login'
				)
			),

			'allows-login' => array (
				'type' => 'checkbox',
				'value' => $setup->allowsLogin
			),

			'uses-auto-login' => array (
				'type' => 'checkbox',
				'value' => $setup->usesAutoLogin
			)
		),

		'technical' => array (
			'data-format' => array (
				'type' => 'select',
				'value' => $setup->dataFormat,

				'options' => array (
					'xml' => 'XML',
					'json' => 'JSON',
					'sql' => 'SQL'
				)
			),

			'default-name' => array (
				'type' => 'text',
				'value' => $setup->defaultName
			),

			'reply-mode' => array (
				'type' => 'select',
				'value' => $setup->replyMode,

				'options' => array (
					'thread' => 'Threaded',
					'stream' => 'Stream'
				)
			),

			'stream-depth' => array (
				'type' => 'number',
				'value' => $setup->streamDepth
			),

			'image-format' => array (
				'type' => 'select',
				'value' => $setup->imageFormat,

				'options' => array (
					'png' => 'PNG',
					'svg' => 'SVG'
				)
			),

			'appends-css' => array (
				'type' => 'checkbox',
				'value' => $setup->appendsCss
			),

			'appends-rss' => array (
				'type' => 'checkbox',
				'value' => $setup->appendsRss
			),

			'counts-deletions' => array (
				'type' => 'checkbox',
				'value' => $setup->countsDeletions
			),

			'local-metadata' => array (
				'type' => 'checkbox',
				'value' => $setup->localMetadata
			),

			'stores-ip-address' => array (
				'type' => 'checkbox',
				'value' => $setup->storesIpAddress
			)
		),

		'JavaScript' => array (
			'minifies-javascript' => array (
				'type' => 'checkbox',
				'value' => $setup->minifiesJavascript
			),

			'minify-level' => array (
				'type' => 'select',
				'cast' => 'number',
				'value' => $setup->minifyLevel,

				'options' => array (
					1 => 'Basic (removes code comments)',
					2 => 'Low (removes whitespace + Basic)',
					3 => 'Medium (removes newlines + Low)',
					4 => 'High (removes extra bits + Medium)'
				)
			)
		)
	);
}

// Creates a select element with setting options
function create_select ($hashover, $name, array $setting)
{
	// Create wrapper element for dropdown menu
	$element = new HTMLTag ('span', array (
		'class' => 'select-wrapper'
	));

	// Create dropdown menu
	$select = new HTMLTag ('select', array (
		'id' => $name,
		'name' => $name,
		'size' => 1
	));

	// Run through setting options
	foreach ($setting['options'] as $value => $data) {
		// Check if the current option is an array
		if (is_array ($data)) {
			// If so, add an option group spacer to menu
			$select->appendChild (new HTMLTag ('optgroup', array (
				'label' => '&nbsp;'
			)));

			// Create an option group with localized label
			$optgroup = new HTMLTag ('optgroup', array (
				'label' => $hashover->locale->text[$value]
			));

			// Run through each optgroup option
			foreach ($data as $opt_value => $opt_text) {
				// Create setting option
				$option = new HTMLTag ('option', array (
					'value' => $opt_value,
					'innerHTML' => $opt_text
				), false);

				// Select proper option
				if ($opt_value === $setting['value']) {
					$option->createAttribute ('selected', 'true');
				}

				// Append option to optgroup
				$optgroup->appendChild ($option);
			}

			// And append optgroup to menu
			$select->appendChild ($optgroup);
		} else {
			// If not, create setting option
			$option = new HTMLTag ('option', array (
				'value' => $value,
				'innerHTML' => $data
			), false);

			// Select proper option
			if ($value === $setting['value']) {
				$option->createAttribute ('selected', 'true');
			}

			// Append option to menu
			$select->appendChild ($option);
		}
	}

	// Append dropdown menu to wrapper element
	$element->appendChild ($select);

	return $element;
}

// Creates a paragraph element for a setting value
function create_paragraph ($hashover, $name, array $setting)
{
	// Create setting description and value paragraph
	$paragraph = new HTMLTag ('p');

	// Setting description locale string
	$text = $hashover->locale->text['setting-' . $name];

	// Create description label
	$label = new HTMLTag ('label', array (
		'for' => $name,
		'innerHTML' => $text
	), false);

	// Get documentation locale string
	$docs = $hashover->locale->text['documentation'];

	// Create documentation link
	$docs_link = new HTMLTag ('a', array (
		'class' => 'docs-link',
		'href' => '../docs/en-us/settings/#' . $name,
		'target' => '_blank',
		'title' => $docs,
		'innerHTML' => '?'
	), false);

	// Handle specific setting types
	switch ($setting['type']) {
		// Create checkbox for enabling/disabling the setting
		case 'checkbox': {
			// Create checkbox type input element
			$element = new HTMLTag ('input', array (
				'id' => $name,
				'type' => 'checkbox',
				'name' => $name
			), false, true);

			// Set check based on current setting
			if ($setting['value'] !== false) {
				$element->createAttribute ('checked', 'true');
			}

			break;
		}

		// Create text/number box for entering the setting value
		case 'number' : case 'text': {
			// Add class to make label a block element
			$label->createAttribute ('class', 'block');

			// And create number or text type input element
			$element = new HTMLTag ('input', array (
				'id' => $name,
				'type' => $setting['type'],
				'name' => $name,
				'value' => $setting['value'],
				'size' => ($setting['type'] === 'text') ? '25' : '10'
			), false, true);

			break;
		}

		// Create dropdown menu for selecting the setting value
		case 'select': {
			// Add class to make label a block element
			$label->createAttribute ('class', 'block');

			// Create select element
			$element = create_select ($hashover, $name, $setting);

			break;
		}
	}

	// Check if setting is a checkbox
	if ($setting['type'] === 'checkbox') {
		// If so, append setting value element to paragraph
		$paragraph->appendChild ($element);

		// Then append label element to paragraph
		$paragraph->appendChild ($label);

		// Append documentation link to description and value paragraph
		$paragraph->appendChild ($docs_link);
	} else {
		// If not, append documentation link to description label
		$label->appendChild ($docs_link);

		// Append label element to paragraph
		$paragraph->appendChild ($label);

		// Then append setting value element to paragraph
		$paragraph->appendChild ($element);
	}

	// And return paragraph element
	return $paragraph;
}

try {
	// Do some standard HashOver setup work
	require (realpath ('../../backend/standard-setup.php'));

	// View setup
	require (realpath ('../view-setup.php'));

	// Get array of UI elements to create
	$ui = ui_array ($hashover->setup, $hashover->locale);

	// Check if the form has been submitted
	if (isset ($_POST['save'])) {
		// Settings JSON file path
		$settings_file = $hashover->setup->getAbsolutePath ('config/settings.json');

		// Read JSON settings file
		$json = $data_files->readJSON ($settings_file);

		// Existing JSON settings or an empty array
		$settings = ($json !== false) ? $json : array ();

		// Run through configurable settings
		foreach ($ui as $items) {
			// Run through each settings category
			foreach ($items as $name => $setting) {
				// Use specified type or optional cast
				$type = !empty ($setting['cast']) ? 'cast' : 'type';

				// Handle specific setting types
				switch ($setting[$type]) {
					// Set value to boolean based on POST data
					case 'checkbox': {
						$settings[$name] = isset ($_POST[$name]);
						break;
					}

					// Cast number values to integers
					case 'number': {
						$settings[$name] = (int)($_POST[$name]);
						break;
					}

					// All other values are strings
					default: {
						// Check if setting has a value
						if (!empty ($_POST[$name])) {
							// If so, cast it to string before setting it
							$settings[$name] = (string)($_POST[$name]);
						} else {
							// If not, remove the setting entirely
							unset ($settings[$name]);
						}

						break;
					}
				}
			}
		}

		// Check if the user login is admin
		if ($hashover->login->verifyAdmin () === true) {
			// If so, attempt to save the settings
			$saved = $data_files->saveJSON ($settings_file, $settings);

			// If saved successfully, redirect with success indicator
			if ($saved === true) {
				redirect ('./?status=success');
			}
		}

		// Otherwise, redirect with failure indicator
		redirect ('./?status=failure');
	}

	// Otherwise, create settings div
	$div = new HTMLTag ('div', array (
		'id' => 'settings'
	));

	// Create settings divs
	foreach ($ui as $locale => $settings) {
		// Replace key with locale string if one exists
		if (!empty ($hashover->locale->text[$locale])) {
			$locale = $hashover->locale->text[$locale];
		}

		// Append settings category text to settings div
		$div->appendChild (new HTMLTag ('p', array (
			'class' => 'settings-category',
			'innerHTML' => $locale
		), false));

		// Create settings items element
		$items = new HTMLTag ('div', array (
			'class' => 'settings'
		));

		// Append each settings category items to div
		foreach ($settings as $name => $setting) {
			$items->appendChild (create_paragraph ($hashover, $name, $setting));
		}

		// Append settings items element to div
		$div->appendChild ($items);
	}

	// Template data
	$template = array (
		'title'		=> $hashover->locale->text['settings'],
		'sub-title'	=> $hashover->locale->text['settings-sub'],
		'settings'	=> $div->asHTML ("\t"),
		'save-button'	=> $hashover->locale->text['save']
	);

	// Load and parse HTML template
	echo parse_templates ('admin', 'settings.html', $template, $hashover);

} catch (\Exception $error) {
	echo Misc::displayException ($error);
}