<?php
/**
* @version	$Id: languages_event_handler.php 14241 2011-03-16 20:24:35Z 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 LanguagesEventHandler extends kDBEventHandler
	{
		/**
		 * Allows to override standart permission mapping
		 *
		 */
		function mapPermissions()
		{
			parent::mapPermissions();
			$permissions = Array(
				'OnChangeLanguage'	=>	Array('self' => true),
				'OnSetPrimary'		=>	Array('self' => 'advanced:set_primary|add|edit'),
				'OnImportLanguage'	=>	Array('self' => 'advanced:import'),
				'OnExportLanguage'	=>	Array('self' => 'advanced:export'),
				'OnExportProgress'	=>	Array('self' => 'advanced:export'),
				'OnReflectMultiLingualFields' => Array ('self' => 'view'),
				'OnSynchronizeLanguages' => Array ('self' => 'edit'),
			);

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

		/**
		 * Permission check override
		 *
		 * @param kEvent $event
		 */
		function CheckPermission(&$event)
		{
			if ($event->Name == 'OnItemBuild') {
				// check permission without using $event->getSection(),
				// so first cache rebuild won't lead to "ldefault_Name" field being used
				return true;
			}

			return parent::CheckPermission($event);
		}

		/**
		 * [HOOK] Updates table structure on new language adding/removing language
		 *
		 * @param kEvent $event
		 */
		function OnReflectMultiLingualFields(&$event)
		{
			if ($this->Application->GetVar('ajax') == 'yes') {
				$event->status = erSTOP;
			}

			if (is_object($event->MasterEvent)) {
				if ($event->MasterEvent->status != erSUCCESS) {
					// only rebuild when all fields are validated
					return ;
				}

				if (($event->MasterEvent->Name == 'OnSave') && !$this->Application->GetVar('new_language')) {
					// only rebuild during new language adding
					return ;
				}
			}

			$ml_helper =& $this->Application->recallObject('kMultiLanguageHelper');
			/* @var $ml_helper kMultiLanguageHelper */

			$this->Application->UnitConfigReader->ReReadConfigs();
			foreach ($this->Application->UnitConfigReader->configData as $prefix => $config_data) {
				$ml_helper->createFields($prefix);
			}
		}

		/**
		 * Allows to set selected language as primary
		 *
		 * @param kEvent $event
		 */
		function OnSetPrimary(&$event)
		{
			if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
				$event->status = erFAIL;
				return;
			}

			$this->StoreSelectedIDs($event);
			$ids = $this->getSelectedIDs($event);
			if ($ids) {
				$id = array_shift($ids);
				$object =& $event->getObject( Array('skip_autoload' => true) );
				/* @var $object LanguagesItem */

				$object->Load($id);
				$object->copyMissingData( $object->setPrimary() );
			}
		}

		/**
		 * [HOOK] Reset primary status of other languages if we are saving primary language
		 *
		 * @param kEvent $event
		 */
		function OnUpdatePrimary(&$event)
		{
			if ($event->MasterEvent->status != erSUCCESS) {
				return ;
			}

			$object =& $event->getObject( Array('skip_autoload' => true) );
			/* @var $object LanguagesItem */

			$object->SwitchToLive();

			// set primary for each languages, that have this checkbox checked
			$ids = explode(',', $event->MasterEvent->getEventParam('ids'));
			foreach ($ids as $id) {
				$object->Load($id);
				if ($object->GetDBField('PrimaryLang')) {
					$object->copyMissingData( $object->setPrimary(true, false) );
				}

				if ($object->GetDBField('AdminInterfaceLang')) {
					$object->setPrimary(true, true);
				}
			}

			// if no primary language left, then set primary last language (not to load again) from edited list
			$sql = 'SELECT '.$object->IDField.'
					FROM '.$object->TableName.'
					WHERE PrimaryLang = 1';
			$primary_language = $this->Conn->GetOne($sql);

			if (!$primary_language) {
				$object->setPrimary(false, false); // set primary language
			}

			$sql = 'SELECT '.$object->IDField.'
					FROM '.$object->TableName.'
					WHERE AdminInterfaceLang = 1';
			$primary_language = $this->Conn->GetOne($sql);

			if (!$primary_language) {
				$object->setPrimary(false, true); // set admin interface language
			}
		}


		/**
		 * Prefills options with dynamic values
		 *
		 * @param kEvent $event
		 */
		function OnAfterConfigRead(&$event)
		{
			parent::OnAfterConfigRead($event);

			$fields = $this->Application->getUnitOption($event->Prefix, 'Fields');

			// set dynamic hints for options in date format fields
			$options = $fields['InputDateFormat']['options'];
			if ($options) {
				foreach ($options as $i => $v) {
					$options[$i] = $v . ' (' . adodb_date($i) . ')';
				}
				$fields['InputDateFormat']['options'] = $options;
			}

			$options = $fields['InputTimeFormat']['options'];
			if ($options) {
				foreach ($options as $i => $v) {
					$options[$i] = $v . ' (' . adodb_date($i) . ')';
				}
				$fields['InputTimeFormat']['options'] = $options;
			}

			$this->Application->setUnitOption($event->Prefix, 'Fields', $fields);
		}

		/**
		 * Occurse before updating item
		 *
		 * @param kEvent $event
		 * @access public
		 */
		function OnBeforeItemUpdate(&$event)
		{
			$object =& $event->getObject();
			$status_fields = $this->Application->getUnitOption($event->Prefix, 'StatusField');
			$status_field = array_shift($status_fields);

			if ($object->GetDBField('PrimaryLang') == 1 && $object->GetDBField($status_field) == 0) {
				$object->SetDBField($status_field, 1);
			}
		}

		/**
		 * Shows only enabled languages on front
		 *
		 * @param kEvent $event
		 */
		function SetCustomQuery(&$event)
		{
			$object =& $event->getObject();
			/* @var $object kDBList */

			if (in_array($event->Special, Array ('enabled', 'selected', 'available'))) {
				$object->addFilter('enabled_filter', '%1$s.Enabled = ' . STATUS_ACTIVE);
			}

			// site domain language picker
			if ($event->Special == 'selected' || $event->Special == 'available') {
				$edit_picker_helper =& $this->Application->recallObject('EditPickerHelper');
				/* @var $edit_picker_helper EditPickerHelper */

				$edit_picker_helper->applyFilter($event, 'Languages');
			}

			// apply domain-based language filtering
			$languages = $this->Application->siteDomainField('Languages');

			if (strlen($languages)) {
				$languages = explode('|', substr($languages, 1, -1));
				$object->addFilter('domain_filter', '%1$s.LanguageId IN (' . implode(',', $languages) . ')');
			}
		}

		/**
		 * Copy labels from another language
		 *
		 * @param kEvent $event
		 */
		function OnAfterItemCreate(&$event)
		{
			parent::OnAfterItemCreate($event);

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

			$src_language = $object->GetDBField('CopyFromLanguage');

			if ($object->GetDBField('CopyLabels') && $src_language) {
				$dst_language = $object->GetID();

				// 1. schedule data copy after OnSave event is executed
				$var_name = $event->getPrefixSpecial() . '_copy_data' . $this->Application->GetVar('m_wid');
				$pending_actions = $this->Application->RecallVar($var_name, Array ());

				if ($pending_actions) {
					$pending_actions = unserialize($pending_actions);
				}

				$pending_actions[$src_language] = $dst_language;
				$this->Application->StoreVar($var_name, serialize($pending_actions));
				$object->SetDBField('CopyLabels', 0);
			}
		}

		/**
		 * Saves language from temp table to live
		 *
		 * @param kEvent $event
		 */
		function OnSave(&$event)
		{
			parent::OnSave($event);

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

			$var_name = $event->getPrefixSpecial() . '_copy_data' . $this->Application->GetVar('m_wid');
			$pending_actions = $this->Application->RecallVar($var_name, Array ());

			if ($pending_actions) {
				$pending_actions = unserialize($pending_actions);
			}

			// create multilingual columns for phrases & email events table first (actual for 6+ language)
			$ml_helper =& $this->Application->recallObject('kMultiLanguageHelper');
			$ml_helper->createFields('phrases');
			$ml_helper->createFields('emailevents');

			foreach ($pending_actions as $src_language => $dst_language) {
				// phrases import
				$sql = 'UPDATE ' . $this->Application->getUnitOption('phrases', 'TableName') . '
						SET l' . $dst_language . '_Translation = l' . $src_language . '_Translation';
				$this->Conn->Query($sql);

				// events import
				$sql = 'UPDATE ' . $this->Application->getUnitOption('emailevents', 'TableName') . '
						SET
							l' . $dst_language . '_Subject = l' . $src_language . '_Subject,
							l' . $dst_language . '_Body = l' . $src_language . '_Body';
				$this->Conn->Query($sql);
			}

			$this->Application->RemoveVar($var_name);

			$event->CallSubEvent('OnReflectMultiLingualFields');
			$event->CallSubEvent('OnUpdatePrimary');
		}

		/**
		 * Prepare temp tables for creating new item
		 * but does not create it. Actual create is
		 * done in OnPreSaveCreated
		 *
		 * @param kEvent $event
		 */
		function OnPreCreate(&$event)
		{
			parent::OnPreCreate($event);

			$object =& $event->getObject();
			$object->SetDBField('CopyLabels', 1);

			$live_table = $this->Application->getUnitOption($event->Prefix, 'TableName');
			$primary_lang_id = $this->Conn->GetOne('SELECT '.$object->IDField.' FROM '.$live_table.' WHERE PrimaryLang = 1');

			$object->SetDBField('CopyFromLanguage', $primary_lang_id);
		}

		/**
		 * Sets new language mark
		 *
		 * @param kEvent $event
		 */
		function OnBeforeDeleteFromLive(&$event)
		{
			$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
			$table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');

			$sql = 'SELECT ' . $id_field . '
					FROM ' . $table_name . '
					WHERE ' . $id_field . ' = ' . $event->getEventParam('id');
			$id = $this->Conn->GetOne($sql);

			if (!$id) {
				$this->Application->SetVar('new_language', 1);
			}
		}

		function OnChangeLanguage(&$event)
		{
			$language_id = $this->Application->GetVar('language');

			if ($this->Application->isAdmin) {
				// admin data only
				$this->Application->SetVar('m_lang', $language_id);

				// set new language for this session (admin interface only)
				$this->Application->Session->SetField('Language', $language_id);

				// remember last user language in administrative console
				if ($this->Application->RecallVar('user_id') == USER_ROOT) {
					$this->Application->StorePersistentVar('AdminLanguage', $language_id);
				}
				else {
					$object =& $this->Application->recallObject('u.current');
					/* @var $object kDBItem */

					$object->SetDBField('AdminLanguage', $language_id);
					$object->Update();
				}

				// without this language change in admin will cause erase of last remembered tree section
				$this->Application->SetVar('skip_last_template', 1);
			}
			else {
				// changing language on Front-End
				$this->Application->SetVar('m_lang', $language_id);

				if (MOD_REWRITE) {
					$mod_rewrite_helper =& $this->Application->recallObject('ModRewriteHelper');
					/* @var $mod_rewrite_helper kModRewriteHelper */

					$mod_rewrite_helper->removePages();
				}
			}
		}

		/**
		 * Parse language XML file into temp tables and redirect to progress bar screen
		 *
		 * @param kEvent $event
		 */
		function OnImportLanguage(&$event)
		{
			if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
				$event->status = erFAIL;
				return;
			}

			$items_info = $this->Application->GetVar('phrases_import');
			if ($items_info) {
				list ($id, $field_values) = each($items_info);

				$object =& $this->Application->recallObject('phrases.import', 'phrases', Array('skip_autoload' => true));
				/* @var $object kDBItem */

				$object->setID($id);
				$object->SetFieldsFromHash($field_values);

				if (!$object->Validate()) {
					$event->status = erFAIL;
					return ;
				}

				$filename = $object->GetField('LangFile', 'full_path');

				if (!filesize($filename)) {
					$object->SetError('LangFile', 'la_empty_file', 'la_EmptyFile');
					$event->status = erFAIL;
				}

				$language_import_helper =& $this->Application->recallObject('LanguageImportHelper');
				/* @var $language_import_helper LanguageImportHelper */

				$language_import_helper->performImport(
					$filename,
					$object->GetDBField('PhraseType'),
					$object->GetDBField('Module'),
					$object->GetDBField('ImportOverwrite') ? LANG_OVERWRITE_EXISTING : LANG_SKIP_EXISTING
				);

				// delete uploaded language pack after import is finished
				unlink($filename);

				$event->SetRedirectParam('opener', 'u');
			}
		}

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

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

			$this->StoreSelectedIDs($event);
			$this->Application->StoreVar('export_language_ids', implode(',', $this->getSelectedIDs($event)) );

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

		/**
		 * Saves selected languages to xml file passed
		 *
		 * @param kEvent $event
		 */
		function OnExportProgress(&$event)
		{
			$items_info = $this->Application->GetVar('phrases_export');
			if ($items_info) {
				list($id, $field_values) = each($items_info);
				$object =& $this->Application->recallObject('phrases.export', null, Array('skip_autoload' => true));
				/* @var $object kDBItem */

				$object->setID($id);
				$object->SetFieldsFromHash($field_values);

				if (!$object->Validate()) {
					$event->status = erFAIL;
					return ;
				}

				$file_helper =& $this->Application->recallObject('FileHelper');
				/* @var $file_helper FileHelper */

				$file_helper->CheckFolder(EXPORT_PATH);

				if (!is_writable(EXPORT_PATH)) {
					$event->status = erFAIL;
					$object->SetError('LangFile', 'write_error', 'la_ExportFolderNotWritable');

					return ;
				}

				if ( substr($field_values['LangFile'], -5) != '.lang') {
					$field_values['LangFile'] .= '.lang';
				}

				$filename = EXPORT_PATH . '/' . $field_values['LangFile'];

				$language_import_helper =& $this->Application->recallObject('LanguageImportHelper');
				/* @var $language_import_helper LanguageImportHelper */

				if ($object->GetDBField('DoNotEncode')) {
					$language_import_helper->setExportEncoding('plain');
				}

				$language_import_helper->setExportLimits($field_values['ExportPhrases'], $field_values['ExportEmailEvents']);

				$lang_ids = explode(',', $this->Application->RecallVar('export_language_ids') );
				$language_import_helper->performExport($filename, $field_values['PhraseType'], $lang_ids, $field_values['Module']);

			}

			$event->redirect = 'regional/languages_export_step2';
			$event->SetRedirectParam('export_file', $field_values['LangFile']);
		}

		/**
		 * Returns to previous template in opener stack
		 *
		 * @param kEvent $event
		 */
		function OnGoBack(&$event)
		{
			$event->redirect_params['opener'] = 'u';
		}

		function OnScheduleTopFrameReload(&$event)
		{
			$this->Application->StoreVar('RefreshTopFrame',1);
		}

		/**
		 * Do now allow deleting current language
		 *
		 * @param kEvent $event
		 */
		function OnBeforeItemDelete(&$event)
		{
			$del_id = $event->getEventParam('id');
			$object =& $event->getObject(array('skip_autload' => true));
			$object->Load($del_id);

			if ($object->GetDBField('PrimaryLang') || $object->GetDBField('AdminInterfaceLang') || $del_id == $this->Application->GetVar('m_lang')) {
				$event->status = erFAIL;
			}
		}

		/**
		 * Deletes phrases and email events on given language
		 *
		 * @param kEvent $event
		 */
		function OnAfterItemDelete(&$event)
		{
			parent::OnAfterItemDelete($event);

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

			// clean Events table
			$fields_hash = Array (
				'l' . $object->GetID() . '_Subject' => NULL,
				'l' . $object->GetID() . '_Body' => NULL,
			);
			$this->Conn->doUpdate($fields_hash, $this->Application->getUnitOption('emailevents', 'TableName'), 1);

			// clean Phrases table
			$fields_hash = Array (
				'l' . $object->GetID() . '_Translation' => NULL,
			);
			$this->Conn->doUpdate($fields_hash, $this->Application->getUnitOption('phrases', 'TableName'), 1);
		}

		/**
		 * Copy missing phrases across all system languages (starting from primary)
		 *
		 * @param kEvent $event
		 */
		function OnSynchronizeLanguages(&$event)
		{
			if ($this->Application->CheckPermission('SYSTEM_ACCESS.READONLY', 1)) {
				$event->status = erFAIL;
				return;
			}

			// get language list with primary language first
			$sql = 'SELECT LanguageId
					FROM ' . TABLE_PREFIX . 'Language
					ORDER BY PrimaryLang DESC';

			$source_langs = $this->Conn->GetCol($sql);
			$target_langs = $source_langs;

			foreach ($source_langs as $source_id) {
				foreach ($target_langs as $target_id) {
					if ($source_id == $target_id)	{
						continue;
					}

					$sql = 'UPDATE ' . TABLE_PREFIX . 'Phrase
							SET l' . $target_id . '_Translation = l' . $source_id . '_Translation
							WHERE (l' . $target_id . '_Translation IS NULL) OR (l' . $target_id . '_Translation = "")';
					$this->Conn->Query($sql);
				}
			}
		}
	}