<?php
/**
* @version	$Id: relationship_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 RelationshipEventHandler extends kDBEventHandler
	{
		/**
		 * Allows to override standart permission mapping
		 *
		 */
		function mapPermissions()
		{
			parent::mapPermissions();
			$permissions = Array(
									'OnProcessSelected'		=>	Array('subitem' => 'add|edit'),
							);
			$this->permMapping = array_merge($this->permMapping, $permissions);
		}

		/**
		 * Initializes new relation
		 *
		 * @param kEvent $event
		 */
		function OnNew(&$event)
		{
			parent::OnNew($event);

			$object =& $event->getObject();
			$table_info = $object->getLinkedInfo();

			$object->SetDBField('SourceId', $table_info['ParentId']);
			$source_itemtype = $this->Application->getUnitOption($table_info['ParentPrefix'], 'ItemType');
			$object->SetDBField('SourceType', $source_itemtype);

			$object->SetDBField('TargetId', $this->Application->GetVar('target_id'));
			$object->SetDBField('TargetType', $this->Application->GetVar('target_type'));

			$this->OnAfterItemLoad($event);
		}

		/**
		 * Add new relation
		 *
		 * @param kEvent $event
		 */
		function OnProcessSelected(&$event)
		{
			$dst_field = $this->Application->RecallVar('dst_field');
			if ($dst_field == 'TargetId') {
				// prepare target_id & target_type
				$object =& $event->getObject( Array('skip_autoload' => true) );

				$selected_ids = $this->Application->GetVar('selected_ids');
				$target_prefix = false;
				foreach ($selected_ids as $selected_prefix => $target_id) {
					if ($target_id > 0) {
						$target_prefix = $selected_prefix;
						break;
					}
				}

				if (!$target_prefix) {
					$this->finalizePopup($event);
					return;
				}

				$sql = 'SELECT ResourceId
						FROM '.$this->Application->getUnitOption($target_prefix, 'TableName').'
						WHERE '.$this->Application->getUnitOption($target_prefix, 'IDField').' IN ('.$target_id.')';
				$target_id = $this->Conn->GetOne($sql);
				$target_type = $this->Application->getUnitOption($target_prefix, 'ItemType');

				// don't add same relation twice
				$table_info = $object->getLinkedInfo();
				$sql = 'SELECT TargetId
						FROM '.$object->TableName.'
						WHERE (SourceId = '.$table_info['ParentId'].') AND (TargetId = '.$target_id.')';
				$duplicate_relation = $this->Conn->GetOne($sql) == $target_id;

				$this->finalizePopup($event);

				if (!$duplicate_relation) {
					// place correct template in opener stack
					$source_prefix = $this->Application->getUnitOption($event->Prefix, 'ParentPrefix');
					$template = $this->Application->getUnitOption($source_prefix, 'AdminTemplatePath').'/relations_edit';

					$redirect_params = Array($event->Prefix.'_event' => 'OnNew', 'target_id' => $target_id, 'm_opener' => 's', 'target_type' => $target_type);
					$this->Application->EventManager->openerStackPush($template, $redirect_params, 'all,'.$event->Prefix);
				}
			}
			else {
				$this->finalizePopup($event);
			}
		}

		/**
		 * Set ItemName & ItemType virtual fields based on loaded item data
		 *
		 * @param kEvent $event
		 */
		function OnAfterItemLoad(&$event)
		{
			$object =& $event->getObject();

			$sql = 'SELECT Prefix
					FROM '.TABLE_PREFIX.'ItemTypes
					WHERE ItemType = '.$object->GetDBField('TargetType');
			$target_prefix = $this->Conn->GetOne($sql);

			$title_field = $this->getTitleField($target_prefix);
			$title_phrase = $this->Application->getUnitOption($target_prefix, 'TitlePhrase');

			$sql = 'SELECT '.$title_field.'
					FROM '.$this->Application->getUnitOption($target_prefix, 'TableName').'
					WHERE ResourceId = '.$object->GetDBField('TargetId');

			$object->SetDBField('ItemName', $this->Conn->GetOne($sql));
			$object->SetDBField('ItemType', $this->Application->Phrase($title_phrase));
		}

		/**
		 * Creates needed sql query to load list,
		 * if no query is defined in config for
		 * special requested, then use default
		 * query
		 *
		 * @param kEvent $event
		 * @access protected
		 */
		function ListPrepareQuery(&$event)
		{
			return $this->BaseQuery($event, 'ListSQLs');
		}

		/**
		 * Creates needed sql query to load item,
		 * if no query is defined in config for
		 * special requested, then use default
		 * query
		 *
		 * @param kEvent $event
		 * @access protected
		 */
		function ItemPrepareQuery(&$event)
		{
			return $this->BaseQuery($event, 'ItemSQLs');
		}


		/**
		 * Get item name & type based on relation type & modules installed
		 *
		 * @param kEvent $event
		 * @param string $sql_field
		 */
		function BaseQuery(&$event, $sql_field)
		{
			$sqls = $this->Application->getUnitOption($event->Prefix,$sql_field);
			$sql = isset($sqls[$event->Special]) ? $sqls[$event->Special] : $sqls[''];

			$configs = $this->extractModulesInfo();

			// 2. build sql based on information queried
			$sql_templates['ItemName'] = 'IFNULL(%s.%s,\' \')';
			$sql_templates['TableJoin'] = 'LEFT JOIN %1$s ON %1$s.ResourceId = rel.TargetId';
			$sql_templates['TargetName'] = 'IF(rel.TargetType = %s, \'%s\', %s)';

			$sql_parts = Array();
			$sql_parts['TargetName'] = "''";
			foreach ($configs as $prefix => $config_data) {
				$title_field = $this->getTitleField($prefix);

				$sql_parts['ItemName'][] = sprintf($sql_templates['ItemName'], $config_data['TableName'], $title_field);
				$sql_parts['TableJoin'][] = sprintf($sql_templates['TableJoin'], $config_data['TableName']);

				$sql_parts['TargetName'] = sprintf(	$sql_templates['TargetName'],
					$config_data['ItemType'],
					'!'.$config_data['TitlePhrase'].'!',
					$sql_parts['TargetName']);
				$sql_parts['TargetName'] = str_replace('rel','%1$s',$sql_parts['TargetName']);
			}

			$object =& $event->getObject();

			$vars = Array('#ITEM_NAMES#', '#ITEM_TYPES#');
			$replacements = Array( implode(', ',$sql_parts['ItemName']), $sql_parts['TargetName'] );

			$calculated_fields =& $object->getProperty('CalculatedFields');
			foreach ($calculated_fields as $field_name => $field_expression) {
				$calculated_fields[$field_name] = str_replace($vars, $replacements, $field_expression);
			}

			$object->setProperty('CalculatedFields', $calculated_fields);

			$sql = str_replace('#ITEM_JOIN#', implode(' ',$sql_parts['TableJoin']), $sql);
			$sql = str_replace('rel.','%1$s.',$sql);

			return $sql;
		}

		/**
		 * Convert TitleField field of kMultiLanguage formatter used for it
		 *
		 * @param string $prefix
		 * @return string
		 */
		function getTitleField($prefix)
		{
			$lang_prefix = 'l'.$this->Application->GetVar('m_lang').'_';

			$title_field = $this->Application->getUnitOption($prefix, 'TitleField');
			$field_options = $this->Application->getUnitOption($prefix.'.'.$title_field, 'Fields');

			$formatter_class = isset($field_options['formatter']) ? $field_options['formatter'] : '';
			if ($formatter_class == 'kMultiLanguage' && !isset($field_options['master_field'])) {
				$title_field = $lang_prefix.$title_field;
			}
			return $title_field;
		}

		/**
		 * Get configs from modules installed
		 *
		 * @return Array
		 * @access private
		 */
		function extractModulesInfo()
		{
			// get installed modules & their config info
			// maybe we should leave only prefixes, that have "view" permission
			$configs = Array();
			foreach ($this->Application->ModuleInfo as $module_name => $module_data) {
				$prefix = $module_data['Var'];
				if ($prefix == 'm') {
					$prefix = 'c';
				}
				if (!$this->Application->prefixRegistred($prefix)) continue;

				$configs[$prefix] = $this->Application->getUnitOptions($prefix);
				if($configs[$prefix] === false) unset($configs[$prefix]);
				if(!isset($configs[$prefix]['CatalogItem']) || !$configs[$prefix]['CatalogItem']) unset($configs[$prefix]);
			}
			return $configs;
		}

		/**
		 * Deletes relations to hooked item from other items
		 *
		 * @param kEvent $event
		 */
		function OnDeleteForeignRelations(&$event)
		{
			$main_object =& $event->MasterEvent->getObject();
			$resource_id = $main_object->GetDBField('ResourceId');

			$table = $this->Application->getUnitOption($event->Prefix,'TableName');
			$sql = 'DELETE FROM '.$table.' WHERE TargetId = '.$resource_id;
			$this->Conn->Query($sql);
		}

	}