<?php
/**
* @version	$Id: list_helper.php 16513 2017-01-20 14:10:53Z alex $
* @package	In-Portal
* @copyright	Copyright (C) 1997 - 2011 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 ListHelper extends kHelper {

		/**
		 * Detects, that current sorting of the list is not default
		 *
		 * @param kDBList $list
		 * @return bool
		 */
		function hasUserSorting(&$list)
		{
			static $cache = Array ();

			if (array_key_exists($list->getPrefixSpecial(), $cache)) {
				return $cache[ $list->getPrefixSpecial() ];
			}

			$user_sorting_start = $this->getUserSortIndex($list);

			$sorting_configs = $this->Application->getUnitOption($list->Prefix, 'ConfigMapping', Array ());
			$list_sortings = $this->Application->getUnitOption($list->Prefix, 'ListSortings', Array ());
			$sorting_prefix = getArrayValue($list_sortings, $list->Special) ? $list->Special : '';

			if (array_key_exists('DefaultSorting1Field', $sorting_configs)) {
				$list_sortings[$sorting_prefix]['Sorting'] = Array (
					$this->Application->ConfigValue($sorting_configs['DefaultSorting1Field']) => $this->Application->ConfigValue($sorting_configs['DefaultSorting1Dir']),
					$this->Application->ConfigValue($sorting_configs['DefaultSorting2Field']) => $this->Application->ConfigValue($sorting_configs['DefaultSorting2Dir']),
				);
			}

			$sorting = getArrayValue($list_sortings, $sorting_prefix, 'Sorting');
			$sort_fields = is_array($sorting) ? array_keys($sorting) : Array ();

			for ($order_number = 0; $order_number < 2; $order_number++) {
				// current sorting in list
				$sorting_pos = $user_sorting_start + $order_number;
				$current_order_field = $list->GetOrderField($sorting_pos, true);
				$current_order_direction = $list->GetOrderDirection($sorting_pos, true);

				if (!$current_order_field || !$current_order_direction) {
					// no sorting defined for this sorting position
					continue;
				}

				// remove language prefix from field
				$field_options = $list->GetFieldOptions($current_order_field);
				if (array_key_exists('formatter', $field_options) && $field_options['formatter'] == 'kMultiLanguage') {
					// remove language prefix
					$current_order_field = preg_replace('/^l[\d]+_(.*)/', '\\1', $current_order_field);
				}

				// user sorting found
				if (array_key_exists($order_number, $sort_fields)) {
					// default sorting found
					$default_order_field = $sort_fields[$order_number];
					$default_order_direction = $sorting[$default_order_field]; // because people can write

					if ($current_order_field != $default_order_field || strcasecmp($current_order_direction, $default_order_direction) != 0) {
						// #1. user sorting differs from default sorting -> changed
						$cache[ $list->getPrefixSpecial() ] = true;
						return true;
					}
				}
				else {
					// #2. user sorting + no default sorting -> changed
					$cache[ $list->getPrefixSpecial() ] = true;
					return true;
				}
			}

			// #3. user sorting match default or not defined -> not changed
			$cache[ $list->getPrefixSpecial() ] = false;
			return false;
		}

		/**
		 * Returns default per-page value for given prefix
		 *
		 * @param string $prefix
		 * @param int $default
		 * @return int
		 */
		function getDefaultPerPage($prefix, $default = 10)
		{
			$ret = false;
			$config_mapping = $this->Application->getUnitOption($prefix, 'ConfigMapping');

			if ($config_mapping) {
				if (!array_key_exists('PerPage', $config_mapping)) {
					trigger_error('Incorrect mapping of <span class="debug_error">PerPage</span> key in config for prefix <strong>' . $prefix . '</strong>', E_USER_WARNING);
				}

				$per_page = $this->Application->ConfigValue($config_mapping['PerPage']);

				if ($per_page) {
					return $per_page;
				}
			}

			// none of checked above per-page locations are useful, then try default value
			return $default;
		}

		/**
		 * Returns index where 1st changable sorting field begins
		 *
		 * @param kDBList $list
		 * @return int
		 * @todo 	This is copy of kDBTagProcessor::getUserSortIndex method.
		 * 			Can't call helper there, because it will slow down grid output
		 * 			when we have a lot of columns
		 */
		function getUserSortIndex(&$list)
		{
			$list_sortings = $this->Application->getUnitOption($list->Prefix, 'ListSortings', Array ());
			$sorting_prefix = getArrayValue($list_sortings, $list->Special) ? $list->Special : '';

			$user_sorting_start = 0;
			$forced_sorting = getArrayValue($list_sortings, $sorting_prefix, 'ForcedSorting');

			if ( $forced_sorting ) {
				$user_sorting_start = count($forced_sorting);
			}

			return $user_sorting_start;
		}

		/**
		 * Returns ID of previous/next record related to current record
		 *
		 * @param kDBItem $object
		 * @param string $list_prefix
		 * @param bool $next
		 * @param string $select_fields
		 * @return int
		 */
		function getNavigationResource(&$object, $list_prefix, $next = true, $select_fields = null)
		{
			/** @var kDBList $list */
			$list = $this->Application->recallObject($list_prefix);

			if ( !isset($select_fields) ) {
				$select_fields = '%1$s.' . $object->IDField;
			}

			if ( is_array($select_fields) ) {
				$select_fields = implode(', ', $select_fields);
			}

			$list->SetSelectSQL( str_replace(Array ('%1$s.*', '%2$s'), Array ($select_fields, ''), $list->GetPlainSelectSQL()) );

			$operators = Array (
				'asc' => $next ? '>' : '<',
				'desc' => $next ? '<' : '>',
			);

			$where_clause = Array ();
			$lang = $this->Application->GetVar('m_lang');
			$order_fields = $order_fields_backup = $list->getOrderFields();

			foreach ($order_fields as $index => $order) {
				$where_clause[$index] = Array ();

				if ( !$next ) {
					$list->changeOrderDirection($index, $order_fields_backup[$index][1] == 'asc' ? 'desc' : 'asc');
				}

				for ($i = 0; $i <= $index; $i++) {
					$order_field = $order_fields_backup[$i][0];
					$is_expression = $order_fields_backup[$i][2];

					if ( preg_match('/^IF\(COALESCE\(.*?\.(l' . $lang . '_.*?), ""\),/', $order_field, $regs) ) {
						// undo result of kDBList::getMLSortField method
						$order_field = $regs[1];
						$is_expression = false;
					}

					$order_direction = $order_fields_backup[$i][1];

					$field_prefix = $list->isVirtualField($order_field) || $is_expression ? '' : '%1$s.';

					$actual_operator = $i == $index ? $operators[$order_direction] : '=';
					$where_clause[$index][] = $field_prefix . $order_field . ' ' . $actual_operator . ' ' . $this->Conn->qstr($object->GetDBField($order_field));
				}

				$where_clause[$index] = '(' . implode(') AND (', $where_clause[$index]) . ')';
			}

			$where_clause = '(%1$s.' . $object->IDField . ' != ' . $object->GetID() . ') AND ((' . implode(') OR (', $where_clause) . '))';
			$list->addFilter('navigation_filter', $where_clause);

			// do extractCalculatedFields (transforms having into where), since we don't select fields from JOINed tables
			$sql = $list->extractCalculatedFields($list->GetSelectSQL(), 1, true);

			$list->removeFilter('navigation_filter');
			$list->setOrderFields($order_fields_backup);

			if ( $this->Application->isDebugMode() ) {
				$this->Application->Debugger->appendHTML('Quering <strong>' . ($next ? 'next' : 'previous') . '</strong> item for "<strong>' . $list_prefix . '</strong>" list:');
			}

			return $this->Conn->GetOne($sql);
		}
	}