<?php
/**
* @version	$Id: phrases_event_handler.php 16513 2017-01-20 14:10:53Z alex $
* @package	In-Portal
* @copyright	Copyright (C) 1997 - 2009 Intechnic. All rights reserved.
* @license      GNU/GPL
* In-Portal is Open Source software.
* This means that this software may have been modified pursuant
* the GNU General Public License, and as distributed it includes
* or is derivative of works licensed under the GNU General Public License
* or other free or open source software licenses.
* See http://www.in-portal.org/license for copyright notices and details.
*/

	defined('FULL_PATH') or die('restricted access!');

	class PhrasesEventHandler extends kDBEventHandler
	{
		/**
		 * Allows to override standard permission mapping
		 *
		 * @return void
		 * @access protected
		 * @see kEventHandler::$permMapping
		 */
		protected function mapPermissions()
		{
			parent::mapPermissions();

			$permissions = Array (
				'OnItemBuild' => Array ('self' => true, 'subitem' => true),
				'OnPreparePhrase' => Array ('self' => true, 'subitem' => true),
				'OnExportPhrases' => Array ('self' => 'view'),
			);

			$this->permMapping = array_merge($this->permMapping, $permissions);
		}

		/**
		 * Hides phrases from disabled modules
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function SetCustomQuery(kEvent $event)
		{
			parent::SetCustomQuery($event);

			/** @var kDBList $object */
			$object = $event->getObject();

			$object->addFilter('module_filter', '%1$s.Module IN (SELECT Name FROM ' . TABLE_PREFIX . 'Modules WHERE Loaded = 1)');
		}

		/**
		 * Apply some special processing to object being
		 * recalled before using it in other events that
		 * call prepareObject
		 *
		 * @param kDBItem|kDBList $object
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function prepareObject(&$object, kEvent $event)
		{
			// don't call parent
			if ( $event->Special == 'import' || $event->Special == 'export' ) {
				$this->RemoveRequiredFields($object);
				$object->setRequired(Array ('ExportDataTypes', 'LangFile', 'PhraseType', 'Module'));

				// allow multiple phrase types to be selected during import/export
				$object->SetFieldOption('PhraseType', 'type', 'string');
			}
		}

		/**
		 * Allow to create phrases from front end in debug mode with DBG_PHRASES constant set
		 *
		 * @param kEvent $event
		 * @return bool
		 * @access public
		 */
		public function CheckPermission(kEvent $event)
		{
			if ( !$this->Application->isAdmin && $this->Application->isDebugMode(false) && kUtil::constOn('DBG_PHRASES') ) {
				$allow_events = Array ('OnCreate', 'OnCreateAjax', 'OnUpdate', 'OnUpdateAjax');

				if ( in_array($event->Name, $allow_events) ) {
					return true;
				}
			}

			return parent::CheckPermission($event);
		}

		/**
		 * Prepares phrase for translation
		 *
		 * @param kEvent $event
		 */
		function OnPreparePhrase($event)
		{
			$label = $this->Application->GetVar($event->getPrefixSpecial() . '_label');

			if (!$label) {
				return ;
			}

			// we got label, try to get it's ID then if any
			$phrase_id = $this->_getPhraseId($label);

			if ($phrase_id) {
				$event->SetRedirectParam($event->getPrefixSpecial(true) . '_id', $phrase_id);
				$event->SetRedirectParam('pass', 'm,' . $event->getPrefixSpecial());

				$next_template = $this->Application->GetVar('next_template');

				if ($next_template) {
					$event->SetRedirectParam('next_template', $next_template);
				}
			}
			else {
				$event->CallSubEvent('OnNew');
			}

			if ($this->Application->GetVar('simple_mode')) {
				$event->SetRedirectParam('simple_mode', 1);
			}
		}

		function _getPhraseId($phrase)
		{
			$sql = 'SELECT ' . $this->Application->getUnitOption($this->Prefix, 'IDField') . '
					FROM ' . $this->Application->getUnitOption($this->Prefix, 'TableName') . '
					WHERE PhraseKey = ' . $this->Conn->qstr( mb_strtoupper($phrase) );

			return $this->Conn->GetOne($sql);
		}

		/**
		 * Sets phrase type based on place where it's created (to display on form only)
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnPreCreate(kEvent $event)
		{
			parent::OnPreCreate($event);

			/** @var kDBItem $object */
			$object = $event->getObject();

			$this->_setPhraseModule($object);
		}

		/**
		 * Forces new label in case if issued from get link
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnNew(kEvent $event)
		{
			parent::OnNew($event);

			/** @var kDBItem $object */
			$object = $event->getObject();

			$label = $this->Application->GetVar($event->getPrefixSpecial() . '_label');

			if ( $label ) {
				// phrase is created in language, used to display phrases
				$object->SetDBField('Phrase', $label);
				$object->SetDBField('PhraseType', $this->_getPhraseType($label)); // to show on form
				$object->SetDBField('PrimaryTranslation', $this->_getPrimaryTranslation($label));
			}

			$this->_setPhraseModule($object);

			if ( $event->Special == 'export' || $event->Special == 'import' ) {
				$object->SetDBField('PhraseType', '|0|1|2|');
				$object->SetDBField('Module', '|' . implode('|', array_keys($this->Application->ModuleInfo)) . '|');

				$export_mode = $this->Application->GetVar('export_mode');

				if ( $export_mode != 'lang' ) {
					$object->SetDBField('ExportDataTypes', '|' . $export_mode . '|');
				}
			}
		}

		/**
		 * Returns given phrase translation on primary language
		 *
		 * @param string $phrase
		 * @return string
		 * @access protected
		 */
		protected function _getPrimaryTranslation($phrase)
		{
			$sql = 'SELECT l' . $this->Application->GetDefaultLanguageId() . '_Translation
					FROM ' . $this->Application->getUnitOption($this->Prefix, 'TableName') . '
					WHERE PhraseKey = ' . $this->Conn->qstr( mb_strtoupper($phrase) );

			return $this->Conn->GetOne($sql);
		}

		/**
		 * Sets new phrase module
		 *
		 * @param kDBItem $object
		 * @return void
		 * @access protected
		 */
		protected function _setPhraseModule(&$object)
		{
			$last_module = $this->Application->GetVar('last_module');

			if ( $last_module ) {
				$object->SetDBField('Module', $last_module);
			}
		}

		/**
		 * Forces create to use live table
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnCreate(kEvent $event)
		{
			if ( $this->Application->GetVar($event->Prefix . '_label') ) {
				/** @var kDBItem $object */
				$object = $event->getObject(Array ('skip_autoload' => true));

				if ( $this->Application->GetVar('m_lang') != $this->Application->GetVar('lang_id') ) {
					$object->SwitchToLive();
				}

				$this->returnToOriginalTemplate($event);
			}

			parent::OnCreate($event);
		}

		/**
		 * Processes items create from ajax request
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnCreateAjax(kEvent $event)
		{
			/** @var AjaxFormHelper $ajax_form_helper */
			$ajax_form_helper = $this->Application->recallObject('AjaxFormHelper');

			$ajax_form_helper->transitEvent($event, 'OnCreate');
		}

		/**
		 * Redirects to original template after phrase is being update
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnUpdate(kEvent $event)
		{
			if ( $this->Application->GetVar($event->Prefix . '_label') ) {
				$this->returnToOriginalTemplate($event);
			}

			parent::OnUpdate($event);
		}

		/**
		 * Processes items update from ajax request
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnUpdateAjax(kEvent $event)
		{
			/** @var AjaxFormHelper $ajax_form_helper */
			$ajax_form_helper = $this->Application->recallObject('AjaxFormHelper');

			$ajax_form_helper->transitEvent($event, 'OnUpdate');
		}

		/**
		 * Returns to original template after phrase adding/editing
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function returnToOriginalTemplate(kEvent $event)
		{
			$next_template = $this->Application->GetVar('next_template');

			if ( $next_template ) {
				$event->redirect = $next_template;
				$event->SetRedirectParam('opener', 's');
			}
		}

		/**
		 * Set last change info, when phrase is created
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnBeforeItemCreate(kEvent $event)
		{
			parent::OnBeforeItemCreate($event);

			/** @var kDBItem $object */
			$object = $event->getObject();

			$primary_language_id = $this->Application->GetDefaultLanguageId();

			if ( !$object->GetDBField('l' . $primary_language_id . '_Translation') ) {
				// no translation on primary language -> try to copy from other language
				$src_languages = Array ('lang_id', 'm_lang'); // editable language, theme language

				foreach ($src_languages as $src_language) {
					$src_language = $this->Application->GetVar($src_language);
					$src_value = $src_language ? $object->GetDBField('l' . $src_language . '_Translation') : false;

					if ( $src_value ) {
						$object->SetDBField('l' . $primary_language_id . '_Translation', $src_value);
						break;
					}
				}
			}

			$this->_phraseChanged($event);
		}

		/**
		 * Update last change info, when phrase is updated
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnBeforeItemUpdate(kEvent $event)
		{
			parent::OnBeforeItemUpdate($event);

			$this->_phraseChanged($event);
		}

		/**
		 * Set's phrase key and last change info, used for phrase updating and loading
		 *
		 * @param kEvent $event
		 */
		function _phraseChanged($event)
		{
			/** @var kDBItem $object */
			$object = $event->getObject();

			$label = $object->GetDBField('Phrase');
			$object->SetDBField('PhraseKey', mb_strtoupper($label));
			$object->SetDBField('PhraseType', $this->_getPhraseType($label));

			if ( $this->translationChanged($object) ) {
				$object->SetDBField('LastChanged_date', adodb_mktime() );
				$object->SetDBField('LastChanged_time', adodb_mktime() );
				$object->SetDBField('LastChangeIP', $this->Application->getClientIp());
			}

			$this->Application->Session->SetCookie('last_module', $object->GetDBField('Module'));
		}

		/**
		 * Returns phrase type, that corresponds given phrase label
		 *
		 * @param string $label
		 * @return int
		 * @access protected
		 */
		protected function _getPhraseType($label)
		{
			$phrase_type_map = Array (
				'LU' => Language::PHRASE_TYPE_FRONT,
				'LA' => Language::PHRASE_TYPE_ADMIN,
				'LC' => Language::PHRASE_TYPE_COMMON
			);

			$label = mb_strtoupper($label);
			$label_prefix = substr($label, 0, 2);

			return isset($phrase_type_map[$label_prefix]) ? $phrase_type_map[$label_prefix] : Language::PHRASE_TYPE_COMMON;
		}

		/**
		 * Checks, that at least one of phrase's translations was changed
		 *
		 * @param kDBItem $object
		 * @return bool
		 */
		function translationChanged(&$object)
		{
			$changed_fields = array_keys( $object->GetChangedFields() );
			$translation_fields = Array ('Translation', 'HintTranslation', 'ColumnTranslation');

			foreach ($changed_fields as $changed_field) {
				$changed_field = preg_replace('/^l[\d]+_/', '', $changed_field);

				if ( in_array($changed_field, $translation_fields) ) {
					return true;
				}
			}

			return false;
		}

		/**
		 * Changes default module to custom (when available)
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnAfterConfigRead(kEvent $event)
		{
			parent::OnAfterConfigRead($event);

			if ($this->Application->findModule('Name', 'Custom')) {
				$fields = $this->Application->getUnitOption($event->Prefix, 'Fields');
				$fields['Module']['default'] = 'Custom';
				$this->Application->setUnitOption($event->Prefix, 'Fields', $fields);
			}

			// make sure, that PrimaryTranslation column always refrers to primary language column
			$language_id = $this->Application->GetVar('lang_id');

			if (!$language_id) {
				$language_id = $this->Application->GetVar('m_lang');
			}

			$primary_language_id = $this->Application->GetDefaultLanguageId();
			$calculated_fields = $this->Application->getUnitOption($event->Prefix, 'CalculatedFields');

			foreach ($calculated_fields[''] as $field_name => $field_expression) {
				$field_expression = str_replace('%5$s', $language_id, $field_expression);
				$field_expression = str_replace('%4$s', $primary_language_id, $field_expression);

				$calculated_fields[''][$field_name] = $field_expression;
			}

			$this->Application->setUnitOption($event->Prefix, 'CalculatedFields', $calculated_fields);

			if ($this->Application->GetVar('regional')) {
				$this->Application->setUnitOption($event->Prefix, 'PopulateMlFields', true);
			}
		}

		/**
		 * Saves changes & changes language
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnPreSaveAndChangeLanguage(kEvent $event)
		{
			$label = $this->Application->GetVar($event->getPrefixSpecial() . '_label');

			if ( $label && !$this->UseTempTables($event) ) {
				$phrase_id = $this->_getPhraseId($label);

				if ( $phrase_id ) {
					$event->CallSubEvent('OnUpdate');
					$event->SetRedirectParam('opener', 's');
				}
				else {
					$event->CallSubEvent('OnCreate');
					$event->SetRedirectParam('opener', 's');
				}

				if ( $event->status != kEvent::erSUCCESS ) {
					return;
				}

				$event->SetRedirectParam($event->getPrefixSpecial() . '_event', 'OnPreparePhrase');
				$event->SetRedirectParam('pass_events', true);
			}

			if ( $this->Application->GetVar('simple_mode') ) {
				$event->SetRedirectParam('simple_mode', 1);
			}

			parent::OnPreSaveAndChangeLanguage($event);
		}

		/**
		 * Prepare temp tables and populate it
		 * with items selected in the grid
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnEdit(kEvent $event)
		{
			parent::OnEdit($event);

			// use language from grid, instead of primary language used by default
			$event->SetRedirectParam('m_lang', $this->Application->GetVar('m_lang'));
		}

		/**
		 * Stores ids of selected phrases and redirects to export language step 1
		 *
		 * @param kEvent $event
		 * @return void
		 * @access protected
		 */
		protected function OnExportPhrases(kEvent $event)
		{
			if ( $this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1) ) {
				$event->status = kEvent::erFAIL;
				return;
			}

			$this->Application->setUnitOption('phrases', 'AutoLoad', false);

			$this->StoreSelectedIDs($event);
			$this->Application->StoreVar('export_language_ids', $this->Application->GetVar('m_lang'));

			$event->setRedirectParams(
				Array (
					'phrases.export_event' => 'OnNew',
					'pass' => 'all,phrases.export',
					'export_mode' => $event->Prefix,
				)
			);
		}
	}
