<?php
/**
* @version	$Id: opener_stack.php 14937 2011-12-28 20:23:27Z 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 kOpenerStack extends kBase {

	/**
	 * Reference to last opener stack element
	 */
	const LAST_ELEMENT = -1;

	/**
	 * Window ID of opener stack
	 *
	 * @var int
	 * @access protected
	 */
	protected $windowID = null;

	/**
	 * Opener stack data
	 *
	 * @var Array
	 * @access protected
	 */
	protected $data = Array ();

	/**
	 * Creates instance of opener stack manager
	 *
	 * @param int $window_id
	 */
	public function __construct($window_id = null)
	{
		parent::__construct();

		$this->windowID = isset($window_id) ? $window_id : $this->Application->GetVar('m_wid');
		$this->load();
	}

	/**
	 * Returns window id, that was finally used by opener stack
	 *
	 * @return int
	 * @access public
	 */
	public function getWindowID()
	{
		return $this->windowID;
	}

	/**
	 * Returns session variable name, used to store opener stack
	 *
	 * @return string
	 * @access protected
	 */
	protected function getVariableName()
	{
		return rtrim('opener_stack_' . $this->windowID, '_');
	}

	/**
	 * Loads opener stack data from session
	 *
	 * @return void
	 * @access protected
	 */
	protected function load()
	{
		$stack_name = $this->getVariableName();
		$opener_stack = $this->Application->RecallVar($stack_name);

		$this->data = $opener_stack ? unserialize($opener_stack) : Array ();
	}

	/**
	 * Stores updated opener stack to session
	 *
	 * @param bool $remove_on_empty
	 * @return void
	 */
	public function save($remove_on_empty = false)
	{
		if ( $remove_on_empty ) {
			if ( $this->data ) {
				$this->Application->StoreVar($this->getVariableName(), serialize($this->data));
			}
			else {
				$this->Application->RemoveVar($this->getVariableName());
			}
		}
		else {
			$this->Application->StoreVar($this->getVariableName(), serialize($this->data), !$this->data);
		}
	}

	/**
	 * Returns opener stack element at given position
	 *
	 * @param int $index Position of element in opener stack. Negative number will retrieve element from the end.
	 * @param bool $raw
	 * @return Array|string {$template, $params, $index_file}
	 * @see kRequestManager::openerStackChange()
	 * @access public
	 */
	public function get($index, $raw = false)
	{
		if ( $index < 0 ) {
			$index += count($this->data);
		}

		if ( !$this->data || !isset($this->data[$index]) ) {
			return Array ('', Array (), null);
		}

		if ( $raw ) {
			return $this->data[$index];
		}

		list ($index_file, $original_env) = explode('|', $this->data[$index], 2);
		$fixed_env = str_replace(Array ('&amp;', '%5C'), Array ('&', '\\'), $original_env);

		$params = $this->Application->processQueryString($fixed_env, 'pass');

		// opener stack is used from JavaScript / redirecting, so any "&amp;" could break it
		$params['__URLENCODE__'] = 1;

		$template = kUtil::popParam('t', $params, '');

		return Array ($template, $params, $index_file);
	}

	/**
	 * Parses last opener stack element and returns it
	 *
	 * @param bool $raw
	 * @return Array {$template, $params, $index_file}
	 * @access public
	 */
	public function pop($raw = false)
	{
		$ret = $this->get(self::LAST_ELEMENT, $raw);
		array_pop($this->data);

		return $ret;
	}

	/**
	 * Adds new opener stack element
	 *
	 * @param string $template
	 * @param Array $params
	 * @param string $index_file
	 * @return void
	 * @access public
	 */
	public function push($template = '', $params = Array (), $index_file = null)
	{
		$pass_events = kUtil::popParam('pass_events', $params, true);

		$new_level = $this->Application->BuildEnv($template, $params, $params['pass'], $pass_events, false);
		$this->data[] = $index_file . '|' . $new_level;
	}

	/**
	 * Adds new opener stack element as raw string
	 *
	 * @param $data
	 * @return void
	 * @access public
	 */
	public function pushRaw($data)
	{
		$this->data[] = $data;
	}

	/**
	 * Resets opener stack content
	 *
	 * @return void
	 * @access public
	 */
	public function reset()
	{
		$this->data = Array ();
	}

	/**
	 * Checks, that opener stack has no records
	 *
	 * @return bool
	 * @access public
	 */
	public function isEmpty()
	{
		return count($this->data) == 0;
	}
}