<?php

/**
 * THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
 * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 *
 * @package clearFusionCMS\module\search
 * @copyright Copyright (c) 2012 - 2017 clearFusionCMS. All rights reserved.
 * @link http://clearfusioncms.com
 */

/**
 * searchSettings Class
 *
 * Class to implement settings for clearFusionCMS full search.
 *
 * @package clearFusionCMS\module\search
 */
class searchSettings implements cfModuleSettingsInterface {

	/**
	 * Get a list of settings groups.
	 *
	 * @return array Array of setting groups, name => func name
	 */
	function getSettingsGroups() {
		if(!clearFusionCMS::getUser()->hasPermission('cfSearch.settings'))
			return array();

		return array(
			__('Search Settings', 'searchBackend') => 'general',
			__('Search Fields', 'searchBackend') => 'fields',
			__('Tag Fields', 'searchBackend') => 'tag'
		);
	}

	/**
	 * Implement editing the password reset email.
	 *
	 * @param flForm $form The form object to use.
	 * @param flDb $db The database object.
	 * @return bool true if the settings were updated, false if failed to update or null if no change.
	 */
	function generalSetting($form, $db) {
		if(!clearFusionCMS::getUser()->hasPermission('cfSearch.settings'))
			return null;

		$mgr = new flSearchManager($db, 'cf_search_' . clearFusionCMS::getSite());
		$cfg = $mgr->getConfig(array('minWordLen', 'maxWordLen', 'stopWords'));
		$cfg['stopWords'] = array_flip(unserialize($cfg['stopWords']));

		$minLen = new flFormElementText($form, 'minlen', $cfg['minWordLen']);
		$minLen->setLabel(__('The Minimum Word Length Indexed', 'searchBackend'))
			->setRequired()
			->addValidator(new flFormValidatorRequired())
			->addValidator(new flFormValidatorInteger());

		$maxLen = new flFormElementText($form, 'maxlen', $cfg['maxWordLen']);
		$maxLen->setLabel(__('The Maximum Word Length Indexed', 'searchBackend'))
			->setRequired()
			->addValidator(new flFormValidatorRequired())
			->addValidator(new flFormValidatorInteger());

		$stopwords = new flFormElementTextArea($form, 'stopwords', join(', ', $cfg['stopWords']));
		$stopwords->setLabel(__('Stop Words', 'searchBackend'))
			->setDescription(clearFusionCMS::getController()->alertMessage('Info', __('1. Each stop word must be separated by a single comma.<br />2. Changes on this page will only affect new content or all content once reindexed.', 'searchBackend')))
			->setRequired()
			->setRows(20)
			->addValidator(new flFormValidatorRequired())
			->addValidator(new flFormValidatorMaxLength(2097152));

		$submit = new flFormElementSubmit($form, 'update');
		$submit->setCaption(__('Update Settings', 'searchBackend'))->setCSS('primary');

		$form->focusElement($minLen);

		$form->groupElements('submit', array($submit), new flFormDecoratorList(new flFormDecoratorDl()));

		$r = null;
		if($form->isSubmitted() && $form->isValid()) {
			cfSettingsAudit::update(
				__('Search', 'searchBackend'),
				__('Search Settings', 'searchBackend'),
				$cfg
			);

			$cfg['minWordLen'] = $minLen->getValue();
			$cfg['maxWordLen'] = $maxLen->getValue();

			$words = explode(',', $stopwords->getValue());
			$cfg['stopWords'] = array();
			foreach($words as $word) {
				$word = trim($word);
				if(!empty($word))
					$cfg['stopWords'][] = $word;
			}

			$cfg['stopWords'] = serialize(array_flip($cfg['stopWords']));
			$mgr->setConfig($cfg);

			$r = true;
		}

		return $r;
	}

	/**
	 * Implement mapping data to search fields.
	 *
	 * @param flForm $form The form object to use.
	 * @param flDb $db The database object.
	 * @return bool true if the settings were updated, false if failed to update or null if no change.
	 */
	function fieldsSetting($form, $db) {
		if(!clearFusionCMS::getUser()->hasPermission('cfSearch.settings'))
			return null;

		$fldMgr = new cfCustomFields($db);
		$mgr = new flSearchManager($db, 'cf_search_' . clearFusionCMS::getSite());
		$cfg = $mgr->getConfig(array('cfFieldDesc', 'cfFieldData'));

		// Get custom fields
		$custFields = array();
		$cf = $fldMgr->getFields();
		foreach($cf as $p => $d)
			$custFields[$p] = "&#91;&#91;+$p&#93;&#93; $d";

		// Get per search fields exported by modules
		$mm = new flModuleMgr($db);
		foreach($mm->getInstalled() as $name => $ver) {
			$info = $mm->getInfo($name);
			if(isset($info->searchfields) && is_array($info->searchfields)) {
				foreach($info->searchfields as $field) {
					list($fn, $fd) = explode(',', $field);
					$fn = trim($fn);
					$fd = trim($fd);
					$custFields[$fn] = "&#91;&#91;+$fn&#93;&#93; " . __($fd, $name . 'Backend');
				}
			}
		}

		$fieldDesc = unserialize($cfg['cfFieldDesc']);
		$fieldData = unserialize($cfg['cfFieldData']);

		// For existing fields
		$formFields = array();
		foreach($fieldData as $field => $data) {

			$fdesc = new flFormElementText($form, 'fdesc_' . $field, $fieldDesc[$field]);
			$fdesc->setLabel('Description for Search Field')
				->setRequired()
				->addValidator(new flFormValidatorRequired())
				->addValidator(new flFormValidatorMaxLength(64));

			$type = $db->fetchOne('SELECT fldtype FROM cf_search_' . clearFusionCMS::getSite() . '_fields WHERE fldname=?', $field);
			$ftype = new flFormElementSelect($form, 'fldtype_' . $field, $type, array(
				'text' => __('Text', 'searchBackend'),
				'int' => __('Integer', 'searchBackend'),
				'number' => __('Number', 'searchBackend')
			));
			$ftype->setLabel(__('Field Type', 'searchBackend'))
				->setReadonly()
				->setDisabled();

			$fdata = new flFormElementChecklist($form, 'fdata_' . $field, $data, array(
				'title' => '&#91;&#91;+title&#93;&#93; ' . __('Document Title', 'searchBackend'),
				'subtitle' => '&#91;&#91;+subtitle&#93;&#93; ' . __('Document Subtitle', 'searchBackend'),
				'content' => '&#91;&#91;+content&#93;&#93; ' . __('Document Content', 'searchBackend'),
				'summary' => '&#91;&#91;+summary&#93;&#93; ' . __('Document Summary', 'searchBackend'),
				'meta_title' => '&#91;&#91;+meta_title&#93;&#93; ' . __('Document Meta Title', 'searchBackend'),
				'meta_description' => '&#91;&#91;+meta_description&#93;&#93; ' . __('Document Meta Description', 'searchBackend'),
				'meta_keywords' => '&#91;&#91;+meta_keywords&#93;&#93; ' . __('Document Meta Keywords', 'searchBackend')
			) + $custFields);
			$fdata->setLabel(__('Content Fields to Use in Search Field', 'searchBackend'));

			$fdel = new flFormElementCheckbox($form, 'fdel_' . $field);
			$fdel->setLabel(__('Delete This Field', 'searchBackend'));

			$form->groupElements('g_' . $field, array($fdesc, $ftype, $fdata, $fdel))
				->addTab(sprintf(__("Search Field '%s'", 'searchBackend'), $field), 'g_' . $field);

			$formFields[$field] = array('desc' => $fdesc, 'data' => $fdata, 'del' => $fdel);
		}

		// Fields for new search field
		$newName = new flFormElementText($form, 'fldname');
		$newName->setLabel(__('Field Name', 'searchBackend'))
			->setRequired()
			->addValidator(new flFormValidatorRegex('/^[a-z0-9_.-]+$/', __('The field name can only contain the characters a-z, 0-9, _, - and . all other characters are not allowed.', 'searchBackend')))
			->addValidator(new flFormValidatorMaxLength(64));

		$newDesc = new flFormElementText($form, 'flddesc');
		$newDesc->setLabel(__('Field Description', 'searchBackend'))
			->setRequired()
			->addValidator(new flFormValidatorMaxLength(64));

		$newType = new flFormElementSelect($form, 'fldtype', '', array(
			'text' => __('Text', 'searchBackend'),
			'int' => __('Integer', 'searchBackend'),
			'number' => __('Number', 'searchBackend')
		));
		$newType->setLabel(__('Field Type', 'searchBackend'));

		$newData = new flFormElementChecklist($form, 'flddata', array(), array(
			'title' => '&#91;&#91;+title&#93;&#93; ' . __('Document Title', 'searchBackend'),
			'subtitle' => '&#91;&#91;+subtitle&#93;&#93; ' . __('Document Subtitle', 'searchBackend'),
			'content' => '&#91;&#91;+content&#93;&#93; ' . __('Document Content', 'searchBackend'),
			'summary' => '&#91;&#91;+summary&#93;&#93; ' . __('Document Summary', 'searchBackend'),
			'meta_title' => '&#91;&#91;+meta_title&#93;&#93; ' . __('Document Meta Title', 'searchBackend'),
			'meta_description' => '&#91;&#91;+meta_description&#93;&#93; ' . __('Document Meta Description', 'searchBackend'),
			'meta_keywords' => '&#91;&#91;+meta_keywords&#93;&#93; ' . __('Document Meta Keywords', 'searchBackend')
		) + $custFields);
		$newData->setLabel(__('Content Fields to Use in Search Field', 'searchBackend'));

		$submit = new flFormElementSubmit($form, 'update');
		$submit->setCaption(__('Update Search Fields', 'searchBackend'))->setCSS('primary');

		$pane = new flFormElementPane($form, 'info', clearFusionCMS::getController()->alertMessage('Info', __('1. Changes on this page will only affect new content or all content once reindexed.<br />
2. Checking a \'Delete This Field\' box will delete the field and all data when \'Update Search Fields\' is clicked.', 'searchBackend')));

		$form->groupElements('newfld', array($newName, $newDesc, $newType, $newData))
			->AddTab(__('Add a Search Field', 'searchBackend'), 'newfld')
			->groupElements('info', array($pane))
			->groupElements('submit', array($submit), new flFormDecoratorList(new flFormDecoratorDl()));

		$r = null;
		if($form->isSubmitted() && $form->isValid()) {
			cfSettingsAudit::update(
				__('Search', 'searchBackend'),
				__('Search Fields', 'searchBackend'),
				[
					'descriptions' => $fieldDesc,
					'data' => $fieldData
				]
			);

			// Delete dead fields and get data
			$fieldDesc = array();
			$fieldData = array();
			foreach($formFields as $field => $d) {
				if($d['del']->getValue())
					$mgr->deleteField($field);
				else {
					$fieldDesc[$field] = $d['desc']->getValue();
					$fieldData[$field] = $d['data']->getValue();
				}
			}

			// Add new field if given
			$name = $newName->getValue();
			$desc = $newDesc->getValue();
			if(!empty($name) && !empty($desc)) {
				$fieldDesc[$name] = $desc;
				$fieldData[$name] = $newData->getValue();
				$mgr->addField($name, $newType->getValue());
			}

			// save config
			$mgr->setConfig(array(
				'cfFieldDesc' => serialize($fieldDesc),
				'cfFieldData' => serialize($fieldData)
			));

			clearFusionCMS::getResponse()->redirectTo(clearFusionCMS::getRequest()->getSelf());

			$r = true;
		}

		return $r;
	}

	/**
	 * Implement selection of the field to use for tagging.
	 *
	 * @param flForm $form The form object to use.
	 * @param flDb $db The database object.
	 * @return bool true if the settings were updated, false if failed to update or null if no change.
	 */
	function tagSetting($form, $db) {
		if(!clearFusionCMS::getUser()->hasPermission('cfSearch.settings'))
			return null;

		$fldMgr = new cfCustomFields($db);
		$mgr = new flSearchManager($db, 'cf_search_' . clearFusionCMS::getSite());
		$cfg = $mgr->getConfig(array('cfTagField'));
		$cfg['cfTagField'] = unserialize($cfg['cfTagField']);

		// Get custom fields
		$custFields = array();
		$cf = $fldMgr->getFields();
		foreach($cf as $p => $d)
			$custFields[$p] = "&#91;&#91;+$p&#93;&#93; $d";

		// Get per search fields exported by modules
		$mm = new flModuleMgr($db);
		foreach($mm->getInstalled() as $name => $ver) {
			$info = $mm->getInfo($name);
			if(isset($info->searchfields) && is_array($info->searchfields)) {
				foreach($info->searchfields as $field) {
					list($fn, $fd) = explode(',', $field);
					$fn = trim($fn);
					$fd = trim($fd);
					$custFields[$fn] = "&#91;&#91;+$fn&#93;&#93; " . __($fd, $name . 'Backend');
				}
			}
		}

		$tagField = new flFormElementChecklist($form, 'tagfield', $cfg['cfTagField'], array(
			'title' => '&#91;&#91;+title&#93;&#93; ' . __('Document Title', 'searchBackend'),
			'content' => '&#91;&#91;+content&#93;&#93; ' . __('Document Content', 'searchBackend'),
			'summary' => '&#91;&#91;+summary&#93;&#93; ' . __('Document Summary', 'searchBackend'),
			'meta_description' => '&#91;&#91;+meta_description&#93;&#93; ' . __('Document Meta Description', 'searchBackend'),
			'meta_keywords' => '&#91;&#91;+meta_keywords&#93;&#93; ' . __('Document Meta Keywords', 'searchBackend')
		) + $custFields);
		$tagField->setLabel(__('Fields To Generate Tags From', 'searchBackend'))
			->setDescription(clearFusionCMS::getController()->alertMessage('Info', __('Changes on this page will only affect new content or all content once reindexed.', 'searchBackend')));

		$submit = new flFormElementSubmit($form, 'update');
		$submit->setCaption(__('Update Tag Fields', 'searchBackend'))->setCSS('primary');

		$form->focusElement($tagField);

		$form->groupElements('submit', array($submit), new flFormDecoratorList(new flFormDecoratorDl()));

		$r = null;
		if($form->isSubmitted() && $form->isValid()) {
			cfSettingsAudit::update(
				__('Search', 'searchBackend'),
				__('Tag Fields', 'searchBackend'),
				$cfg
			);

			$mgr->setConfig(array(
				'cfTagField' => serialize($tagField->getValue())
			));
			$r = true;
		}

		return $r;
	}
}
