<?php
/**
* @version	$Id: priority_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 kPriorityHelper extends kHelper {


		/**
		 * Prepares options for priority dropdown
		 *
		 * @param kEvent $event
		 * @param bool $is_new for newly created items add new priority to the end
		 * @param string $constrain constrain for priority selection (if any)
		 *
		 */
		function preparePriorities(&$event, $is_new = false, $constrain = '')
		{
			$object =& $event->getObject();

			$field_options = $object->GetFieldOptions('Priority');
			$table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');

			$sql = 'SELECT COUNT(*)
					FROM '.$table_name;
			if ($constrain) {
				$sql .= ' WHERE '.$constrain;
			}

			if (!isset($object->Fields['OldPriority'])) {
				$object->VirtualFields['OldPriority'] = Array('type' => 'int', 'default' => 0);
			}

			$items_count = $this->Conn->GetOne($sql);

			// instanceof is not used, because PHP4 doesn't support it
			$current_priority = is_a($object, 'kDBList') ? 0 : $object->GetDBField('Priority');

			if ($is_new || $current_priority == -($items_count+1)) {
				$items_count++;
			}

			if ($is_new) {
				// add new item to the end of list
				$object->SetDBField('Priority', -$items_count);
				$object->SetDBField('OldPriority', -$items_count);
			}
			else {
				$object->SetDBField('OldPriority', $current_priority);
			}

			for ($i = 1; $i <= $items_count; $i++) {
				$field_options['options'][-$i] = $i;
			}

			$object->SetFieldOptions('Priority', $field_options);
			// storing prioriry right after load for comparing when updating
		}

		/**
		 * Updates priorities for changed items
		 *
		 * @param kEvent $event
		 * @param Array $changes = Array (ID => Array ('parent' => ..., 'new' => ..., 'old' => ...), ...)
		 * @param Array $new_ids = Array (temp_id => live_id)
		 * @param string $constrain
		 */
		function updatePriorities(&$event, $changes, $new_ids, $constrain = '')
		{
			if (!$changes) {
				// no changes to process
				return Array ();
			}
			list ($id, $pair) = each($changes);

			if (!$id && !array_key_exists('parent', $pair)) {
				// adding new item without constrain -> priority stays the same
				return Array ($id);
			}

			$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
			$table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');

			$ids = array();
			$not_processed = array_keys($changes);

			foreach ($changes as $id => $pair) {
				array_push($ids, $id);
				$constrain = isset($pair['parent']) ? 'ParentId = '.$pair['parent'].' AND ' : '';

				if ($pair['old'] == 'new') {
					// replace 0 with newly created item id (from $new_ids mapping)
					$not_processed[ array_search($id, $not_processed) ] = $new_ids[$id];
					$id = $new_ids[$id];

					$sql = 'SELECT MIN(Priority)
							FROM '.$table_name.'
							WHERE '.$constrain.' '.$id_field.' NOT IN ('.implode(',', $not_processed).')';
					$min_priority = (int)$this->Conn->GetOne($sql) - 1;

					if ($pair['new'] < $min_priority) {
						$pair['new'] = $min_priority;
					}
					$pair['old'] = $min_priority;
				}

				if ($pair['new'] < $pair['old']) {
					$set = '	SET Priority = Priority + 1';
					$where =' WHERE '.$constrain.'
								Priority >= '.$pair['new'].'
								AND
								Priority < '.$pair['old'].'
								AND
								'.$id_field.' NOT IN ('.implode(',', $not_processed).')';
				}
				elseif ($pair['new'] > $pair['old']) {
					$set = '	SET Priority = Priority - 1';
					$where ='	WHERE '.$constrain.'
								Priority > '.$pair['old'].'
								AND
								Priority <= '.$pair['new'].'
								AND
								'.$id_field.' NOT IN ('.implode(',', $not_processed).')';
				}
				else {
					$set = 'SET Priority = '.$pair['new'];
					$where = ' WHERE '.$id_field.' = '.$id;
				}
				$ids = array_merge($ids, $this->Conn->GetCol('SELECT '.$id_field.' FROM '.$table_name.$where));
				$q = 'UPDATE '.$table_name.' '.$set.$where;
				$this->Conn->Query($q);

				unset( $not_processed[array_search($id, $not_processed)] );
			}
			return $ids;
		}

		/**
		 * Recalculates priorities
		 *
		 * @param kEvent $event
		 * @param string $constrain
		 */
		function recalculatePriorities(&$event, $constrain = '')
		{
			$id_field = $this->Application->getUnitOption($event->Prefix, 'IDField');
			$table_name = $this->Application->getUnitOption($event->Prefix, 'TableName');

			$sql = 'SELECT '.$id_field.'
					FROM '.$table_name.
					($constrain ? ' WHERE '.$constrain : '').'
					ORDER BY Priority DESC';

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

			foreach ($items as $item_number => $item_id) {
				$sql = 'UPDATE '.$table_name.'
						SET Priority = '.-($item_number + 1).'
						WHERE '.$id_field.' = '.$item_id;
				$this->Conn->Query($sql);
			}
			return $items;
		}
	}