<?php
/**
* @version	$Id: languages_event_handler.php 13590 2010-05-19 17:51:42Z 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'),

				'OnItemBuild' => Array('self' => true),
			);

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

		/**
		 * [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->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->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
			}
		}


		/**
		 * 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)
		{
			if ($event->Special == 'enabled') {
				$object =& $event->getObject();
				/* @var $object kDBList */

				$object->addFilter('enabled_filter', '%1$s.Enabled = 1');
			}
		}

		/**
		 * Copy labels from another language
		 *
		 * @param kEvent $event
		 */
		function OnCopyLabels(&$event)
		{
			$object =& $event->getObject();
			$from_lang_id = $object->GetDBField('CopyFromLanguage');

			if( ($event->MasterEvent->status == erSUCCESS) && $object->GetDBField('CopyLabels') == 1 && ($from_lang_id > 0) )
			{
				$lang_id = $object->GetID();

				// 1. phrases import
				$phrases_live = $this->Application->getUnitOption('phrases','TableName');
				$phrases_temp = $this->Application->GetTempName($phrases_live, 'prefix:phrases');
				$sql = 'INSERT INTO ' . $phrases_temp . '
							SELECT Phrase, PhraseKey, Translation, PhraseType, 0-PhraseId, '.$lang_id.', '.adodb_mktime().', "", Module
						FROM '.$phrases_live.'
							WHERE LanguageId = '.$from_lang_id;
				$this->Conn->Query($sql);

				// 2. events import
				$em_table_live = $this->Application->getUnitOption('emailmessages','TableName');
				$em_table_temp = $this->Application->GetTempName($em_table_live, 'prefix:emailmessages');

				$sql = 'SELECT * FROM '.$em_table_live.' WHERE LanguageId = '.$from_lang_id;
				$email_messages = $this->Conn->Query($sql);
				if($email_messages)
				{
					$id = $this->Conn->GetOne('SELECT MIN(EmailMessageId) FROM '.$em_table_live);
					if($id > 0) $id = 0;
					$id--;

					$sqls = Array();
					foreach($email_messages as $email_message)
					{
						$sqls[] = $id.','.$this->Conn->qstr($email_message['Template']).','.$this->Conn->qstr($email_message['MessageType']).','.$lang_id.','.$email_message['EventId'];
						$id--;
					}
					$sql = 'INSERT INTO '.$em_table_temp.'(EmailMessageId,Template,MessageType,LanguageId,EventId) VALUES ('.implode('),(',$sqls).')';
					$this->Conn->Query($sql);
				}

				$object->SetDBField('CopyLabels', 0);
			}
		}

		/**
		 * 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') == -1) {
					$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', 'phrases', Array('skip_autoload' => true) );
				$object->SetFieldsFromHash($field_values);

				$lang_ids = explode(',', $this->Application->RecallVar('export_language_ids') );

				if( !getArrayValue($field_values,'LangFile') )
				{
					$object->SetError('LangFile', 'required');
					$event->redirect = false;
					return false;
				}
				if( !is_writable(EXPORT_PATH) )
				{
					$object->SetError('LangFile', 'write_error', 'la_ExportFolderNotWritable');
					$event->redirect = false;
					return false;
				}
				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->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;
			}
		}

		/**
		 * 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;
					}

					$this->_addMissingPhrase($source_id, $target_id);
				}
			}
		}

		/**
		 * Copy missing phrases from $from_lang to $to_lang
		 *
		 * @param int $from_lang
		 * @param int $to_lang
		 */
		function _addMissingPhrase($from_lang, $to_lang)
		{
			$tmp_name = TABLE_PREFIX . 'PhraseCopy_' . $this->Application->GetSID();
			$q = 'CREATE TABLE ' . $tmp_name . '
						SELECT
							source.Phrase,
							source.PhraseKey,
							source.Translation,
							source.PhraseType,
							NULL As PhraseId,
							' . $to_lang . ' AS LanguageId,
							source.LastChanged,
							source.LastChangeIP,
							source.Module
						FROM ' . TABLE_PREFIX . 'Phrase source
						WHERE source.LanguageId = ' . $from_lang . '
							AND source.Phrase NOT IN (SELECT Phrase FROM ' . TABLE_PREFIX . 'Phrase target WHERE target.LanguageId = ' . $to_lang . ')';
			$this->Conn->Query($q);

			$this->Conn->Query('INSERT INTO ' . TABLE_PREFIX . 'Phrase SELECT * FROM ' . $tmp_name);
			$this->Conn->Query('DROP TABLE ' . $tmp_name);
		}

	}