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

		function DeleteCategory($category_id, $prefix='c')
		{
			$id_field = $this->Application->getUnitOption($prefix, 'IDField');
			$table_name = $this->Application->getUnitOption($prefix, 'TableName');

			$sql = 'SELECT '.$id_field.'
					FROM '.$table_name.'
					WHERE ParentId = '.$category_id;

			$sub_categories = $this->Conn->GetCol($sql);
			if ($sub_categories) {
				foreach ($sub_categories as $sub_category_id) {
					$this->DeleteCategory($sub_category_id);
				}
			}

			$ci_table = $this->Application->getUnitOption('ci', 'TableName');
			// 1. remove category items from this category if it is supplemental (non-primary) category to them
			$sql = 'DELETE FROM '.$ci_table.'
					WHERE ('.$id_field.' = '.$category_id.') AND (PrimaryCat = 0)';
			$this->Conn->Query($sql);

			$temp_handler =& $this->Application->recallObject($prefix.'_TempHandler', 'kTempTablesHandler');

			// 2. delete items this have this category as primary
			$delete_ids = $this->getCategoryItems($category_id, true);

			foreach ($delete_ids as $item_prefix => $resource_ids) {
				if (!$item_prefix) {
					// not ItemPrefix filled -> old categoryitem linking
					continue;
				}
				$item_ids = $this->GetItemIDs($item_prefix, $resource_ids);
				$temp_handler->BuildTables($item_prefix, $item_ids);
				$temp_handler->DeleteItems($item_prefix, '', $item_ids);
			}

			// 3. delete this category
			$temp_handler->BuildTables($prefix, Array($category_id));
			$temp_handler->DeleteItems($prefix, '', Array($category_id));
		}

		/**
		 * Converts resource ids list to id field list for given prefix
		 *
		 * @param string $prefix
		 * @param Array $resource_ids
		 * @return Array
		 */
		function GetItemIDs($prefix, $resource_ids)
		{
			if (!$resource_ids) {
				return Array();
			}

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

			$sql = 'SELECT '.$id_field.'
					FROM '.$table_name.'
					WHERE ResourceId IN ('.implode(',', $resource_ids).')';
			return $this->Conn->GetCol($sql);
		}

		// moves selected categories to destination category
		function MoveCategories($category_ids, $dest_category_id)
		{
			if (!$category_ids) return ;

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

			// do not move categories into their children
			$sql = 'SELECT ParentPath
					FROM '.$table_name.'
					WHERE '.$id_field.' = '.$dest_category_id;
			$dest_parent_path = explode('|', substr($this->Conn->GetOne($sql), 1, -1));

			$child_categories = array_intersect($dest_parent_path, $category_ids); // get categories, then can't be moved
			$category_ids = array_diff($category_ids, $child_categories); // remove them from movable categories list

			if ($category_ids) {
				$sql = 'UPDATE '.$table_name.'
						SET ParentId = '.$dest_category_id.'
						WHERE '.$id_field.' IN ('.implode(',', $category_ids).')';
				$this->Conn->Query($sql);
			}
		}

		/**
		 * Complete cloning or category with subcategories and subitems
		 *
		 * @param int $category_id
		 */
		function PasteCategory($category_id, $prefix = 'c')
		{
			$backup_category_id = $this->Application->GetVar('m_cat_id');

			$src_parent_path = $this->_getParentPath($category_id);
			$dst_parent_path = $this->_getParentPath($backup_category_id);

			if (substr($dst_parent_path, 0, strlen($src_parent_path)) == $src_parent_path) {
				// target path contains source path -> recursion
				return ;
			}

			// 1. clone category
			$temp_handler =& $this->Application->recallObject($prefix.'_TempHandler', 'kTempTablesHandler');
			/* @var $temp_handler kTempTablesHandler*/
			$temp_handler->BuildTables($prefix, Array($category_id));
			$new_category_id = array_pop( $temp_handler->CloneItems($prefix, '', Array($category_id)) );
			$this->Application->SetVar('m_cat_id', $new_category_id);

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

			// 2. assign supplemental items to current category to new category
			$paste_ids = $this->getCategoryItems($category_id, false);

			foreach ($paste_ids as $item_prefix => $resource_ids) {
				if (!$item_prefix) {
					// not ItemPrefix filled -> old categoryitem linking
					continue;
				}

				$item_object =& $this->Application->recallObject($item_prefix.'.-item', null, Array('skip_autoload' => true));
				foreach ($resource_ids as $item_resource_id) {
					$item_object->Load($item_resource_id, 'ResourceId');
					$item_object->assignToCategory($new_category_id, false);
				}
			}

			// 3. clone items that have current category as primary
			$paste_ids = $this->getCategoryItems($category_id, true);

			foreach ($paste_ids as $item_prefix => $resource_ids) {
				if (!$item_prefix) {
					// not ItemPrefix filled -> old categoryitem linking
					continue;
				}

				// 2. clone items from current category (for each prefix separately)
				$item_ids = $this->GetItemIDs($item_prefix, $resource_ids);
				$temp_handler->BuildTables($item_prefix, $item_ids);
				$temp_handler->CloneItems($item_prefix, '', $item_ids);
			}

			// 4. do same stuff for each subcategory
			$sql = 'SELECT '.$id_field.'
					FROM '.$table_name.'
					WHERE ParentId = '.$category_id;

			$sub_categories = $this->Conn->GetCol($sql);
			if ($sub_categories) {
				foreach ($sub_categories as $sub_category_id) {
					$this->PasteCategory($sub_category_id, $prefix);
				}
			}

			$this->Application->SetVar('m_cat_id', $backup_category_id);
		}

		/**
		 * Returns grouped category items
		 *
		 * @param int $category_id
		 * @param bool $item_primary_category
		 * @return Array
		 */
		function getCategoryItems($category_id, $item_primary_category = true)
		{
			$ci_table = $this->Application->getUnitOption('ci', 'TableName');

			$sql = 'SELECT ItemPrefix, ItemResourceId
					FROM '.$ci_table.'
					WHERE (CategoryId = '.$category_id.') AND (PrimaryCat = '.($item_primary_category ? 1 : 0).')';
			$category_items = $this->Conn->GetCol($sql, 'ItemResourceId');

			$item_ids = Array();
			foreach ($category_items as $resource_id => $item_prefix) {
				$item_ids[$item_prefix][] = $resource_id;
			}
			return $item_ids;
		}

		/**
		 * Returns parent path for given category
		 *
		 * @param int $category_id
		 * @return Array
		 */
		function _getParentPath($category_id)
		{
			static $cache = Array ();

			if (!array_key_exists($category_id, $cache)) {
				$sql = 'SELECT ParentPath
						FROM ' . TABLE_PREFIX . 'Category
						WHERE CategoryId = ' . $category_id;
				$cache[$category_id] = $this->Conn->GetOne($sql);
			}

			return $cache[$category_id];
		}
	}