<?php
/**
* @version	$Id: mod_rewrite_helper.php 16513 2017-01-20 14:10:53Z 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 CategoryItemRewrite extends kHelper {

		/**
		 * Builds/parses category item part of url
		 *
		 * @param int $rewrite_mode Mode in what rewrite listener was called. Possbile two modes: REWRITE_MODE_BUILD, REWRITE_MODE_PARSE.
		 * @param string $prefix Prefix, that listener uses for system integration
		 * @param Array $params Params, that are used for url building or created during url parsing.
		 * @param Array $url_parts Url parts to parse (only for parsing).
		 * @param bool $keep_events Keep event names in resulting url (only for building).
		 * @return bool Return true to continue to next listener; return false (when building) not to rewrite given prefix; return false (when parsing) to stop processing at this listener.
		 * @access public
		 */
		public function RewriteListener($rewrite_mode = REWRITE_MODE_BUILD, $prefix, &$params, &$url_parts, $keep_events = false)
		{
			if ($rewrite_mode == REWRITE_MODE_BUILD) {
				return $this->_buildCategoryItemUrl($prefix, $params, $keep_events);
			}

			$module_prefix = $this->_parseCategoryItemUrl($url_parts, $params, $prefix);

			if ($module_prefix !== false) {
				/** @var kRewriteUrlProcessor $rewrite_processor */
				$rewrite_processor = $this->Application->recallObject('kRewriteUrlProcessor');

				$params['pass'][] = $module_prefix;
				$rewrite_processor->setModulePrefix($module_prefix);
			}

			return true;
		}

		/**
		 * Build category item part of url
		 *
		 * @param string $prefix_special
		 * @param Array $params
		 * @param bool $keep_events
		 * @return string
		 * @access protected
		 */
		protected function _buildCategoryItemUrl($prefix_special, &$params, $keep_events)
		{
			static $default_per_page = Array ();

			/** @var kRewriteUrlProcessor $rewrite_processor */
			$rewrite_processor = $this->Application->recallObject('kRewriteUrlProcessor');

			$ret = '';
			list ($prefix) = explode('.', $prefix_special);
			$processed_params = $rewrite_processor->getProcessedParams($prefix_special, $params, $keep_events);

			if ($processed_params === false) {
				return '';
			}

			if ( isset($params[$prefix_special . '_event']) && $params[$prefix_special . '_event'] ) {
				$params['events[' . $prefix_special . ']'] = $params[$prefix_special . '_event'];
				unset($params[$prefix_special . '_event']);
			}

			if (!array_key_exists($prefix, $default_per_page)) {
				/** @var ListHelper $list_helper */
				$list_helper = $this->Application->recallObject('ListHelper');

				$default_per_page[$prefix] = $list_helper->getDefaultPerPage($prefix);
			}

			if ($processed_params[$prefix_special . '_id']) {
				$category_id = array_key_exists('m_cat_id', $params) ? $params['m_cat_id'] : $this->Application->GetVar('m_cat_id');

				// if template is also item template of category, then remove template
				$template = array_key_exists('t', $params) ? $params['t'] : false;
				$item_template = $rewrite_processor->GetItemTemplate($category_id, $prefix);

				if ($template == $item_template || strtolower($template) == '__default__') {
					// given template is also default template for this category item or '__default__' given
					$params['pass_template'] = false;
				}

				// get item's filename
				if ($prefix == 'bb') {
					$ret .= 'bb_' . $processed_params[$prefix_special . '_id'] . '/';
				}
				else {
					$filename = $this->getFilename($prefix, $processed_params[$prefix_special . '_id'], $category_id);
					if ($filename !== false) {
						$ret .= $filename . '/';
					}
				}
			} else {
				if ($processed_params[$prefix_special . '_Page'] == 1) {
					// when printing category items and we are on the 1st page -> there is no information about
					// category item prefix and $params['pass_category'] will not be added automatically
					$params['pass_category'] = true;
				}
				elseif ($processed_params[$prefix_special . '_Page'] > 1) {
					// $ret .= $processed_params[$prefix_special . '_Page'] . '/';
					$params['page'] = $processed_params[$prefix_special . '_Page'];
				}

				$per_page = $processed_params[$prefix_special . '_PerPage'];

				if ($per_page && ($per_page != $default_per_page[$prefix])) {
					$params['per_page'] = $processed_params[$prefix_special . '_PerPage'];
				}
			}

			return mb_strtolower( rtrim($ret, '/') );
		}

		/**
		 * Builds/parses review part of url
		 *
		 * @param int $rewrite_mode Mode in what rewrite listener was called. Possbile two modes: REWRITE_MODE_BUILD, REWRITE_MODE_PARSE.
		 * @param string $prefix_special Prefix, that listener uses for system integration
		 * @param Array $params Params, that are used for url building or created during url parsing.
		 * @param Array $url_parts Url parts to parse (only for parsing).
		 * @param bool $keep_events Keep event names in resulting url (only for building).
		 * @return bool Return true to continue to next listener; return false (when building) not to rewrite given prefix; return false (when parsing) to stop processing at this listener.
		 * @access public
		 */
		public function ReviewRewriteListener($rewrite_mode = REWRITE_MODE_BUILD, $prefix_special, &$params, &$url_parts, $keep_events = false)
		{
			static $default_per_page = Array ();

			if ( $rewrite_mode != REWRITE_MODE_BUILD ) {
				// don't parse anything
				return true;
			}

			/** @var kRewriteUrlProcessor $rewrite_processor */
			$rewrite_processor = $this->Application->recallObject('kRewriteUrlProcessor');

			$ret = '';
			list ($prefix) = explode('.', $prefix_special);
			$processed_params = $rewrite_processor->getProcessedParams($prefix_special, $params, $keep_events);

			if ($processed_params === false) {
				return '';
			}

			if (!array_key_exists($prefix, $default_per_page)) {
				/** @var ListHelper $list_helper */
				$list_helper = $this->Application->recallObject('ListHelper');

				$default_per_page[$prefix] = $list_helper->getDefaultPerPage($prefix);
			}

			if ($processed_params[$prefix_special . '_id']) {
				return false;
			}
			else {
				if ($processed_params[$prefix_special . '_Page'] == 1) {
					// when printing category items and we are on the 1st page -> there is no information about
					// category item prefix and $params['pass_category'] will not be added automatically
					$params['pass_category'] = true;
				}
				elseif ($processed_params[$prefix_special . '_Page'] > 1) {
					// $ret .= $processed_params[$prefix_special . '_Page'] . '/';
					$params['page'] = $processed_params[$prefix_special . '_Page'];
				}

				$per_page = $processed_params[$prefix_special . '_PerPage'];

				if ($per_page && ($per_page != $default_per_page[$prefix])) {
					$params['per_page'] = $processed_params[$prefix_special . '_PerPage'];
				}
			}

			return mb_strtolower( rtrim($ret, '/') );
		}

		/**
		 * Returns item's filename that corresponds id passed. If possible, then get it from cache
		 *
		 * @param string $prefix
		 * @param int $id
		 * @param int $category_id
		 * @return string
		 * @access protected
		 */
		protected function getFilename($prefix, $id, $category_id = null)
		{
			if ($prefix == 'c') {
				throw new Exception('Method "<strong>' . __FUNCTION__ . '</strong>" no longer work with "<strong>c</strong>" prefix. Please use "<strong>getCategoryCache</strong>" method instead');

				return false;
			}

			$category_id = isset($category_id) ? $category_id : $this->Application->GetVar('m_cat_id');

			$cache_key = 'filenames[%' . $this->Application->incrementCacheSerial($prefix, $id, false) . '%]:' . (int)$category_id;
			$filename = $this->Application->getCache($cache_key);

			if ($filename === false) {
				$this->Conn->nextQueryCachable = true;
				$sql = 'SELECT ResourceId
						FROM ' . $this->Application->getUnitOption($prefix, 'TableName') . '
						WHERE ' . $this->Application->getUnitOption($prefix, 'IDField') . ' = ' . $this->Conn->qstr($id);
				$resource_id = $this->Conn->GetOne($sql);

				$this->Conn->nextQueryCachable = true;
				$sql = 'SELECT Filename
						FROM ' . TABLE_PREFIX . 'CategoryItems
						WHERE (ItemResourceId = ' . $resource_id . ') AND (CategoryId = ' . (int)$category_id . ')';
				$filename = $this->Conn->GetOne($sql);

				if ($filename !== false) {
					$this->Application->setCache($cache_key, $filename);
				}
			}

			return $filename;
		}

		/**
		 * Sets template and id, corresponding to category item given in url
		 *
		 * @param Array $url_parts
		 * @param Array $vars
		 * @param string $prefix Prefix, that listener uses for system integration
		 *
		 * @return boolean|string
		 * @access protected
		 */
		protected function _parseCategoryItemUrl(&$url_parts, &$vars, $prefix)
		{
			if ( !$url_parts ) {
				return false;
			}

			$item_filename = end($url_parts);
			if ( is_numeric($item_filename) ) {
				// this page, don't process here
				return false;
			}

			/** @var kRewriteUrlProcessor $rewrite_processor */
			$rewrite_processor = $this->Application->recallObject('kRewriteUrlProcessor');

			if ( $prefix == 'bb' && preg_match('/^bb_([\d]+)/', $item_filename, $regs) ) {
				// process topics separately, because they don't use item filenames
				array_pop($url_parts);
				$rewrite_processor->partParsed($item_filename, 'rtl');

				return $this->_parseTopicUrl($regs[1], $vars);
			}

			$cat_item = $this->findCategoryItem((int)$vars['m_cat_id'], $item_filename, $prefix);

			if ( $cat_item !== false ) {
				// item found
				$module_prefix = $cat_item['ItemPrefix'];
				$item_template = $rewrite_processor->GetItemTemplate($cat_item, $module_prefix, $vars['m_theme']);

				// converting ResourceId to corresponding Item id
				$module_config = $this->Application->getUnitOptions($module_prefix);

				$sql = 'SELECT ' . $module_config['IDField'] . '
						FROM ' . $module_config['TableName'] . '
					 	WHERE ResourceId = ' . $cat_item['ItemResourceId'];
				$item_id = $this->Conn->GetOne($sql);

				if ( $item_id ) {
					array_pop($url_parts);
					$rewrite_processor->partParsed($item_filename, 'rtl');

					if ( $item_template ) {
						// when template is found in category -> set it
						$vars['t'] = $item_template;
					}

					// we have category item id
					$vars[$module_prefix . '_id'] = $item_id;

					return $module_prefix;
				}
			}

			return false;
		}

		/**
		 * Locating the item in CategoryItems by filename to detect its ItemPrefix and its category ParentPath.
		 *
		 * @param integer $category_id Category.
		 * @param string  $filename    Filename.
		 * @param string  $prefix      Prefix, that listener uses for system integration
		 *
		 * @return string
		 */
		protected function findCategoryItem($category_id, $filename, $prefix)
		{
			static $cache = array();

			$cache_key = $category_id . ':' . $filename;

			if ( !isset($cache[$cache_key]) ) {
				$sql = 'SELECT ci.ItemResourceId, ci.ItemPrefix, c.ParentPath, ci.CategoryId
						FROM ' . TABLE_PREFIX . 'CategoryItems AS ci
						LEFT JOIN ' . TABLE_PREFIX . 'Categories AS c ON c.CategoryId = ci.CategoryId
						WHERE (ci.CategoryId = ' . $category_id . ') AND (ci.Filename = ' . $this->Conn->qstr($filename) . ')';
				$cache[$cache_key] = $this->Conn->GetRow($sql);
			}

			$category_item = $cache[$cache_key];

			return $category_item && $category_item['ItemPrefix'] == $prefix ? $category_item : false;
		}

		/**
		 * Set's template and topic id corresponding to topic given in url
		 *
		 * @param int $topic_id
		 * @param Array $vars
		 * @return string
		 * @access protected
		 */
		protected function _parseTopicUrl($topic_id, &$vars)
		{
			/** @var kRewriteUrlProcessor $rewrite_processor */
			$rewrite_processor = $this->Application->recallObject('kRewriteUrlProcessor');

			$sql = 'SELECT c.ParentPath, c.CategoryId
					FROM ' . TABLE_PREFIX . 'Categories AS c
					WHERE c.CategoryId = ' . (int)$vars['m_cat_id'];
			$cat_item = $this->Conn->GetRow($sql);

			$item_template = $rewrite_processor->GetItemTemplate($cat_item, 'bb', $vars['m_theme']);

			if ($item_template) {
				$vars['t'] = $item_template;
			}

			$vars['bb_id'] = $topic_id;

			return 'bb';
		}
	}
