<?php
/**
* @version	$Id: edit_picker_helper.php 12734 2009-10-20 19:28:11Z 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 EditPickerHelper extends kHelper {


		function getTable($prefix, $temp=false)
		{
			$table_name = $this->Application->getUnitOption($prefix, 'TableName');
			return $temp ? $this->Application->GetTempName($table_name, 'prefix:'.$prefix) : $table_name;
		}

		/**
		 * Applies filter for multiple lists in inp_edit_picker control.
		 * Called from SetCustomQuery of prefix, that contains all available items.
		 *
		 * @param kEvent $event
		 * @param string $storage_field main item's field name, where values are located
		 */
		function applyFilter(&$event, $storage_field)
		{
			if ($event->Special != 'selected' && $event->Special != 'available') {
				return ;
			}

			if ($storage_field != $event->getEventParam('link_to_field')) {
				return ;
			}

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

			$main_object =& $this->Application->recallObject($event->getEventParam('link_to_prefix'));
			/* @var $main_object kDBItem */

			$selected_items = $main_object->GetDBField($storage_field);
			if ($selected_items) {
				$filter_type = $event->Special == 'selected' ? 'IN' : 'NOT IN';
				$selected_items = explode('|', substr($selected_items, 1, -1));
				$filter_clause = '%1$s.' . $object->IDField.' '.$filter_type.' ('.implode(',', $selected_items).')';
			}
			else {
				$filter_clause = ($event->Special == 'selected') ? 'FALSE' : 'TRUE';
			}

			$constrain = $this->_getConstrain($main_object, $storage_field, 'filter');
			if ($constrain) {
				$filter_clause .= ' AND (' . $constrain . ')';
			}

			$object->addFilter('edit_picker_filter', $filter_clause);
		}

		/**
		 * Loads selected values from sub_prefix to main item virtual field.
		 * Called from OnAfterItemLoad of main prefix.
		 *
		 * @param kEvent $event
		 * @param string $store_field main item's field name, to store values into
		 * @param string $source_field prefix and it's field used to store info about selected items (format: prefix.field)
		 */
		function LoadValues(&$event, $store_field, $source_field)
		{
			$object =& $event->getObject();
			/* @var $object kDBItem */

			list ($sub_prefix, $sub_prefix_field) = explode('.', $source_field);
			$foreign_key = $this->Application->getUnitOption($sub_prefix, 'ForeignKey');

			$sql = 'SELECT '.$sub_prefix_field.'
					FROM '.$this->getTable($sub_prefix, $object->IsTempTable()).'
					WHERE '.$foreign_key.' = '.$object->GetID();

			$constrain = $this->_getConstrain($object, $store_field, 'load');
			if ($constrain) {
				$sql .= ' AND (' . $sub_prefix_field . ' IN (' . $constrain . '))';
			}

			$selected_items = array_unique($this->Conn->GetCol($sql));

			$object->SetDBField($store_field, $selected_items ? '|'.implode('|', $selected_items).'|' : '');
		}

		/**
		 * Saves value to subitem's table
		 *
		 * @param kEvent $sub_event
		 * @param string $store_field main item's field name, to get values from
		 * @param string $sub_prefix_field check already existing records by this field
		 */
		function SaveValues(&$sub_event, $store_field, $sub_prefix_field)
		{
			$main_object =& $sub_event->MasterEvent->getObject();
			/* @var $main_object kDBItem */

			$affected_field = $main_object->GetDBField($store_field);

			$object =& $this->Application->recallObject($sub_event->getPrefixSpecial(), null, Array('skip_autoload' => true));
			/* @var $object kDBItem */

			$sub_table = $object->TableName;
			$foreign_key = $this->Application->getUnitOption($sub_event->Prefix, 'ForeignKey');

			// 1. get previous values from db
			$sql = 'SELECT ' . $sub_prefix_field . '
					FROM ' . $sub_table . '
					WHERE '.$foreign_key.' = '.$main_object->GetID();

			$constrain = $this->_getConstrain($main_object, $store_field, 'save');
			if ($constrain) {
				$sql .= ' AND (' . $sub_prefix_field . ' IN (' . $constrain . '))';
			}

			$old_values = $this->Conn->GetCol($sql);

			// 2. get new values from form
			$new_values = $affected_field ? explode('|', substr($affected_field, 1, -1)) : Array ();

			$records_to_add = array_diff($new_values, $old_values);
			$records_to_delete = array_diff($old_values, $new_values);

			if ($records_to_delete && $main_object->Loaded) {
				$where_clause = Array (
					$foreign_key . ' = ' . $main_object->GetID(),
					$sub_prefix_field . ' IN (' . implode(',', $records_to_delete) . ')',
				);
				$sql = 'SELECT ' . $object->IDField . '
						FROM ' . $sub_table . '
						WHERE (' . implode(') AND (', $where_clause) . ')';
				$delete_ids = $this->Conn->GetCol($sql);

				foreach ($delete_ids as $delete_id) {
					$object->Delete($delete_id);
				}
			}

			if ($records_to_add) {
				$main_id = $main_object->GetID();
				foreach ($records_to_add as $add_id) {
					$object->Clear();
					$object->SetDBField($foreign_key, $main_id);
					$object->SetDBField($sub_prefix_field, $add_id);
					$object->Create();

					if ($object->IsTempTable()) {
						$object->setTempID();
					}
				}
			}
		}

		function _getConstrain(&$object, $store_field, $mode = 'filter')
		{
			$field_options = $object->GetFieldOptions($store_field);
			$constrain = array_key_exists('option_constrain', $field_options) ? $field_options['option_constrain'] : false;

			if ($mode == 'filter') {
				// filter on edit form
				return $constrain;
			}
			elseif ($constrain) {
				// load or save
				return sprintf($field_options['options_sql'], $field_options['option_key_field']);
			}

			return false;
		}
	}