<?php
/**
 * @version	$Id: navigation_bar.php 15424 2012-07-03 08:11:37Z alex $
 * @package	In-Portal
 * @copyright	Copyright (C) 1997 - 2012 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 kNavigationBar extends kBase {

	/**
	 * Parameters to indicate how exactly navigation bar should look like
	 *
	 * @var Array
	 * @access protected
	 */
	protected $_params = Array ();

	/**
	 * Prints category path using given blocks. Also supports used defined path elements at the end.
	 *
	 * @param Array $params
	 * @return string
	 */
	public function build($params)
	{
		// elements:
		// - current_render_as - currently selected element (automatic detection)
		// - render_as - link to a regular template
		// - category_render_as - link to category path element
		// - custom_render_as - link to custom element (that have "__" in front of them)
		// - root_cat_render_as - link to Home page

		$this->_params = $params;
		$this->_params['is_first'] = 1;

		$home_element = $this->_getHomeElement();

		if ( !getArrayValue($this->_params, 'titles') && !getArrayValue($this->_params, 'templates') ) {
			// no static templates given, show only category path
			return $home_element . $this->getCategoryPath();
		}

		$ret = '';
		$block_params = $this->_getBaseParams();
		$current_template = $this->_getCurrentTemplate();
		$navigation_parts = $this->getNavigationParts();

		foreach ($navigation_parts as $template => $title) {
			$block_params['template'] = $template;

			if ( $title == '__categorypath__' ) {
				$ret .= $this->getCategoryPath();
			}
			else {
				$is_current = $template == $current_template;
				$block_params['current'] = $is_current;

				if ( substr($title, 0, 2) == '__' ) {
					$block_params['title'] = $title;
					$block_params['name'] = $this->SelectParam($this->_params, 'custom_render_as,render_as');
				}
				else {
					$block_params['title'] = $this->Application->Phrase($title);
					$block_params['name'] = $this->_params[$is_current ? 'current_render_as' : 'render_as'];
				}

				$ret .= $this->Application->ParseBlock($block_params);
			}
		}

		return $home_element . $ret;
	}

	/**
	 * Returns base params for rendering each navigation bar element
	 *
	 * @return Array
	 * @access protected
	 */
	protected function _getBaseParams()
	{
		$block_params = Array (
			'no_editing' => 1,
			'category' => 0,
			'separator' => $this->_params['separator'],
			'current' => 0,
		);

		return $block_params;
	}

	/**
	 * Returns the name of current physical template
	 *
	 * @return string
	 * @access protected
	 */
	protected function _getCurrentTemplate()
	{
		return $this->Application->getPhysicalTemplate($this->Application->GetVar('t'));
	}

	/**
	 * Returns element for "Home" category
	 *
	 * @return string
	 * @access protected
	 */
	protected function _getHomeElement()
	{
		if ( isset($this->_params['shift']) && $this->_params['shift'] ) {
			$home_element = '';
			$this->_params['shift']--;
		}
		else {
			$home_element = $this->_getHomeCategoryPath();
			unset($this->_params['is_first']);
		}

		return $home_element;
	}

	/**
	 * Renders path to top catalog category
	 *
	 * @return string
	 * @access protected
	 */
	protected function _getHomeCategoryPath()
	{
		$block_params = $this->_getBaseParams();
		$block_params['cat_id'] = $this->Application->getBaseCategory();
		$block_params['current'] = $this->_getCurrentCategoryId() == $block_params['cat_id'] ? 1 : 0;
		$block_params['is_first'] = $this->_params['is_first'];
		$block_params['template'] = ''; // to prevent warning when category element is rendered using general "render_as" block

		$category_name = $this->Application->Phrase(($this->Application->isAdmin ? 'la_' : 'lu_') . 'rootcategory_name');
		$block_params['cat_name'] = $block_params['title'] = $category_name;

		$block_params['name'] = $this->SelectParam($this->_params, 'root_cat_render_as,category_render_as,render_as');

		if ( $block_params['current'] ) {
			$block_params['name'] = $this->SelectParam($this->_params, 'current_render_as,render_as');
		}

		return $this->Application->ParseBlock($block_params);
	}

	/**
	 * Returns currently selected category
	 *
	 * @return mixed
	 */
	protected function _getCurrentCategoryId()
	{
		return isset($this->_params['cat_id']) ? $this->_params['cat_id'] : $this->Application->GetVar('m_cat_id');
	}

	/**
	 * Get navigation parts
	 *
	 * @return Array
	 * @access protected
	 */
	protected function getNavigationParts()
	{
		$titles = explode(',', $this->_params['titles']);
		$templates = explode(',', $this->_params['templates']);

		if ( getArrayValue($this->_params, 'show_category') && !in_array('__categorypath__', $titles) ) {
			// insert before __item__ or first element, when __item__ isn't specified
			$item_index = (int)array_search('__item__', $titles);
			array_splice($titles, $item_index, 0, '__categorypath__');
			array_splice($templates, $item_index, 0, '__categorypath__');
		}

		return array_combine($templates, $titles);
	}

	/**
	 * Renders path to given category using given blocks.
	 *
	 * @return string
	 * @access protected
	 */
	protected function getCategoryPath()
	{
		$category_path = $this->getCategoryParentPath();

		if ( !$category_path ) {
			// in "Home" category
			return '';
		}

		$main_category_id = $this->_getCurrentCategoryId();

		if ( isset($this->_params['shift']) && $this->_params['shift'] ) {
			array_splice($category_path, 0, $this->_params['shift']);
		}

		$category_helper = $this->Application->recallObject('CategoryHelper');
		/* @var $category_helper CategoryHelper */

		$module_info = $category_helper->getCategoryModule($this->_params, array_keys($category_path));
		$module_item_id = $this->Application->GetVar($module_info['Var'] . '_id');

		$ret = '';
		$block_params = $this->_getBaseParams();
		$block_params['category'] = 1;
		$block_params['template'] = ''; // to prevent warning when category element is rendered using general "render_as" block

		if ( isset($this->_params['is_first']) ) {
			$block_params['is_first'] = $this->_params['is_first'];
		}

		$block_params['separator'] = $this->_params['separator'];
		$no_current = isset($this->_params['no_current']) && $this->_params['no_current'];
		$backup_category_id = $this->Application->GetVar('c_id');

		foreach ($category_path as $category_id => $category_name) {
			$block_params['cat_id'] = $category_id;
			$block_params['cat_name'] = $block_params['title'] = $category_name;

			if ( $no_current ) {
				$block_params['current'] = 0;
			}
			else {
				$block_params['current'] = ($main_category_id == $category_id) && !$module_item_id ? 1 : 0;
			}

			$block_params['name'] = $this->SelectParam($this->_params, 'category_render_as,render_as');

			if ( $block_params['current'] ) {
				$block_params['name'] = $this->SelectParam($this->_params, 'current_render_as,render_as');
			}

			$this->Application->SetVar('c_id', $category_id);
			$ret .= $this->Application->ParseBlock($block_params);

			if ( array_key_exists('is_first', $block_params) ) {
				unset($block_params['is_first']);
			}
		}

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

		return $ret;
	}

	/**
	 * Returns given category's parent path as array of id=>name elements
	 *
	 * @return Array
	 * @access protected
	 */
	protected function getCategoryParentPath()
	{
		$main_category_id = $this->_getCurrentCategoryId();

		if ( $main_category_id == 0 ) {
			// don't query path for "Home" category
			return Array ();
		}

		$category_title = isset($this->_params['category_title']) ? $this->_params['category_title'] : 'Name';
		$cache_key = 'parent_paths_named[%CIDSerial:' . $main_category_id . '%]:' . $category_title;
		$cached_path = $this->Application->getCache($cache_key);

		if ( $cached_path === false ) {
			$parent_path = explode('|', substr($this->getParentPath($main_category_id), 1, -1));

			$ml_formatter = $this->Application->recallObject('kMultiLanguage');
			/* @var $ml_formatter kMultiLanguage */

			$navbar_field = $ml_formatter->LangFieldName($category_title);

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

			$this->Conn->nextQueryCachable = true;
			$sql = 'SELECT ' . $navbar_field . ', ' . $id_field . '
					FROM ' . $table_name . '
					WHERE ' . $id_field . ' IN (' . implode(',', $parent_path) . ')';
			$category_names = $this->Conn->GetCol($sql, $id_field);

			$cached_path = Array ();
			$skip_category = $this->Application->getBaseCategory();

			if ( $category_names ) {
				foreach ($parent_path as $category_id) {
					if ( $category_id == $skip_category ) {
						continue;
					}

					$cached_path[$category_id] = $category_names[$category_id];
				}
			}

			$this->Application->setCache($cache_key, $cached_path);
		}

		return $cached_path;
	}

	/**
	 * Returns parent path from a given category
	 *
	 * @param int $category_id
	 * @return string
	 * @access public
	 */
	public function getParentPath($category_id)
	{
		$cache_key = 'parent_paths[%CIDSerial:' . $category_id . '%]';
		$parent_path = $this->Application->getCache($cache_key);

		if ( $parent_path !== false ) {
			return $parent_path;
		}

		$this->Conn->nextQueryCachable = true;
		$sql = 'SELECT ParentPath
				FROM ' . $this->Application->getUnitOption('c', 'TableName') . '
				WHERE ' . $this->Application->getUnitOption('c', 'IDField') . ' = ' . $category_id;
		$parent_path = $this->Conn->GetOne($sql);

		$this->Application->setCache($cache_key, $parent_path);

		return $parent_path;
	}

	/**
	 * Not tag. Method for parameter selection from list in this TagProcessor
	 *
	 * @param Array $params
	 * @param Array $possible_names
	 *
	 * @return string
	 * @access protected
	 */
	protected function SelectParam($params, $possible_names)
	{
		if ( !is_array($params) ) {
			return '';
		}
		if ( !is_array($possible_names) ) {
			$possible_names = explode(',', $possible_names);
		}

		foreach ($possible_names as $name) {
			if ( isset($params[$name]) ) {
				return $params[$name];
			}
		}

		return '';
	}
}