<?php
/**
* @version	$Id: tag_processor.php 14995 2012-01-05 11:19:42Z 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 kTagProcessor extends kBase {

		/**
		 * Returns joined prefix and special if any
		 *
		 * @param bool $from_submit if true, then joins prefix & special by "_", uses  "." otherwise
		 * @return string
		 * @access public
		 */
		public function getPrefixSpecial($from_submit = false)
		{
			if (!$from_submit) {
				return parent::getPrefixSpecial();
			}

			return rtrim($this->Prefix . '_' . $this->Special, '_');
		}

		/**
		 * Processes tag
		 *
		 * @param _BlockTag $tag
		 * @return string
		 * @access public
		 */
		function ProcessTag(&$tag)
		{
			return $this->ProcessParsedTag($tag->Tag, $tag->NP, $tag->getPrefixSpecial());
		}

		/**
		 * Checks, that tag is implemented in this tag processor
		 *
		 * @param string $tag
		 * @param string $prefix
		 *
		 * @return bool
		 * @access public
		 */
		public function CheckTag($tag, $prefix)
		{
			$method = $tag;

			if ( method_exists($this, $method) ) {
				return true;
			}

			if ( $this->Application->hasObject('TagsAggregator') ) {
				$aggregator =& $this->Application->recallObject('TagsAggregator');
				/* @var $aggregator kArray */

				$tmp = $this->Application->processPrefix($prefix);
				$tag_mapping = $aggregator->GetArrayValue($tmp['prefix'], $method);

				if ( $tag_mapping ) {
					return true;
				}
			}

			return false;
		}

		function FormCacheKey($tag, $params, $prefix)
		{
			// link tag to it's template
			$reg_exp = '/^' . preg_quote(FULL_PATH, '/') . '/';
			$template_path = preg_replace($reg_exp, '', $this->Application->Parser->TempalteFullPath, 1);
			$element = 'file=' . $template_path . ':' . $prefix . '_' . $tag . '_' . crc32( serialize($params) );

			return $this->Application->Parser->FormCacheKey($element);
		}

		function ProcessParsedTag($tag, $params, $prefix, $file='unknown', $line=0)
		{
			$Method = $tag;
			if ( method_exists($this, $Method) ) {
				if ( defined('DEBUG_MODE') && defined('DBG_SHOW_TAGS') && DBG_SHOW_TAGS && $this->Application->isDebugMode() ) {
					$this->Application->Debugger->appendHTML('Processing PreParsed Tag ' . $Method . ' in ' . $this->Prefix);
				}

				list ($prefix_only,) = explode('.', $prefix);
				$this->Application->Parser->PrefixesInUse[$prefix_only] = 1;

				$cache_key = '';
				$backup_prefix = $this->Prefix;
				$backup_special = $this->Special;

				if ( $this->Application->Parser->CachingEnabled && array_key_exists('cache_timeout', $params) ) {
					// individual tag caching
					$cache_key = $this->FormCacheKey($tag, $params, $prefix);
					$res = $this->Application->Parser->getCache($cache_key);

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

				$original_params = $params;
				$flag_values = $this->PreparePostProcess($params);

				// pass_params for non ParseBlock tags :)
				if ( $flag_values['pass_params'] ) {
					$params = array_merge($this->Application->Parser->Params, $params);
				}

				$ret = $this->$Method($params);

				$this->Init($backup_prefix, $backup_special);

				$ret = $this->PostProcess($ret, $flag_values);

				if ( $this->Application->Parser->CachingEnabled && $flag_values['cache_timeout'] ) {
					$this->Application->Parser->setCache($cache_key, $ret, (int)$flag_values['cache_timeout']);
				}

				return $ret;
			}
			else {
				list ($ret, $tag_found) = $this->processAggregatedTag($tag, $params, $prefix, $file, $line);

				if ( $tag_found ) {
					return $ret;
				}

				$error_tag = Array ('file' => $file, 'line' => $line);
				throw new ParserException('Undefined tag: <strong>' . $prefix . ':' . $tag . '</strong>', 0, null, $error_tag);

				return false;
			}
		}

		function processAggregatedTag($tag, $params, $prefix, $file = 'unknown', $line = 0)
		{
			if ( $this->Application->hasObject('TagsAggregator') ) {
				$Method = $tag;
				$aggregator =& $this->Application->recallObject('TagsAggregator');
				/* @var $aggregator kArray */

				$tmp = $this->Application->processPrefix($prefix);
				$tag_mapping = $aggregator->GetArrayValue($tmp['prefix'], $Method);

				if ( $tag_mapping ) {
					// aggregated tag defined
					$tmp = $this->Application->processPrefix($tag_mapping[0]);
					$__tag_processor = $tmp['prefix'] . '_TagProcessor';

					$processor =& $this->Application->recallObject($__tag_processor);
					/* @var $processor kTagProcessor */

					$processor->Init($tmp['prefix'], getArrayValue($tag_mapping, 2) ? $tag_mapping[2] : $tmp['special']);

					$params['original_tag'] = $Method; // allows to define same method for different aggregated tags in same tag processor
					$params['PrefixSpecial'] = $this->getPrefixSpecial(); // $prefix;
					$ret = $processor->ProcessParsedTag($tag_mapping[1], $params, $prefix);
					if ( isset($params['result_to_var']) ) {
						$this->Application->Parser->SetParam($params['result_to_var'], $ret);
						$ret = '';
					}
					return Array ($ret, true);
				}
				else {
					// aggregated tag not defined
					$error_tag = Array ('file' => $file, 'line' => $line);
					throw new ParserException('Undefined aggregated tag <strong>' . $prefix . ':' . $Method . '</strong> (in ' . get_class($this) . ' tag processor)', 0, null, $error_tag);
				}
			}

			return Array ('', false);
		}

		function PreparePostProcess(&$params)
		{
			$flags = Array('js_escape', 'equals_to', 'result_to_var', 'pass_params', 'html_escape', 'strip_nl', 'trim', 'cache_timeout');
			$flag_values = Array();

			foreach ($flags as $flag_name) {
				$flag_values[$flag_name] = false;
				if (isset($params[$flag_name])) {
					$flag_values[$flag_name] = $params[$flag_name];
					unset($params[$flag_name]);
				}
			}
			return $flag_values;
		}

		function PostProcess($ret, $flag_values)
		{
			if ($flag_values['html_escape']) {
				$ret = htmlspecialchars($ret);
			}
			if ($flag_values['js_escape']) {
				$ret = addslashes($ret);
				$ret = str_replace(Array("\r", "\n"), Array('\r', '\n'), $ret);
				$ret = str_replace('</script>', "</'+'script>", $ret);
			}
			if ($flag_values['strip_nl']) {
				// 1 - strip \r,\n; 2 - strip tabs too
				$ret = preg_replace($flag_values['strip_nl'] == 2 ? "/[\r\n\t]/" : "/[\r\n]/", '', $ret);
			}
			if ($flag_values['trim']) {
				$ret = trim($ret);
			}
			// TODO: in new parser implement this parameter in compiled code (by Alex)
			if ($flag_values['equals_to'] !== false) {
				$equals_to = explode('|', $flag_values['equals_to']);
				$ret = in_array($ret, $equals_to);
			}

			if ($flag_values['result_to_var']) {
				$this->Application->Parser->SetParam($flag_values['result_to_var'], $ret);
				$ret = '';
			}
			return $ret;
		}


		/**
		 * Not tag, method for parameter
		 * selection from list in this TagProcessor
		 *
		 * @param Array $params
		 * @param string $possible_names
		 * @return string|bool
		 * @access protected
		 */
		protected function SelectParam($params, $possible_names = null)
		{
			if ( !isset($possible_names) ) {
				// select 1st parameter non-empty parameter value
				$possible_names = explode(',', $params['possible_names']);

				foreach ($possible_names as $param_name) {
					$value = $this->Application->Parser->GetParam($param_name);
					$string_value = (string)$value;

					if ( ($string_value != '') && ($string_value != '0') ) {
						return $value;
					}
				}

				return false;
			}

			if ( !is_array($possible_names) ) {
				$possible_names = explode(',', $possible_names);
			}

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

			return false;
		}

	/**
	 * Returns templates path for module, which is gathered from prefix module
	 *
	 * @param Array $params
	 * @return string
	 * @author Alex
	 */
	function ModulePath($params)
	{
		$force_module = getArrayValue($params, 'module');
		if ($force_module) {
			if ($force_module == '#session#') {
				$force_module = preg_replace('/([^:]*):.*/', '\1', $this->Application->RecallVar('module'));
				if (!$force_module) $force_module = 'core';
			}
			else {
				$force_module = mb_strtolower($force_module);
			}

			if ($force_module == 'core') {
				$module_folder = 'core';
			}
			else {
				$module_folder = trim( $this->Application->findModule('Name', $force_module, 'Path'), '/');
			}
		}
		else {
			$module_folder = $this->Application->getUnitOption($this->Prefix, 'ModuleFolder');
		}
		return '../../'.$module_folder.'/admin_templates/';
	}
}

/*class ProcessorsPool {
	var $Processors = Array();
	var $Application;
	var $Prefixes = Array();
	var $S;

	function ProcessorsPool()
	{
		$this->Application =& KernelApplication::Instance();
		$this->S =& $this->Application->Session;
	}

	function RegisterPrefix($prefix, $path, $class)
	{
		// echo " RegisterPrefix $prefix, $path, $class <br>";
		$prefix_item = Array(
			'path' => $path,
			'class' => $class
		);
		$this->Prefixes[$prefix] = $prefix_item;
	}

	function CreateProcessor($prefix, &$tag)
	{
		// echo " prefix : $prefix <br>";
		if (!isset($this->Prefixes[$prefix]))
			$this->Application->ApplicationDie ("<b>Filepath and ClassName for prefix $prefix not defined while processing ".htmlspecialchars($tag->GetFullTag())."!</b>");
		include_once($this->Prefixes[$prefix]['path']);
		$ClassName = $this->Prefixes[$prefix]['class'];
		$a_processor = new $ClassName($prefix);
		$this->SetProcessor($prefix, $a_processor);
	}

	function SetProcessor($prefix, &$a_processor)
	{
		$this->Processors[$prefix] =& $a_processor;
	}

	function &GetProcessor($prefix, &$tag)
	{
		if (!isset($this->Processors[$prefix]))
			$this->CreateProcessor($prefix, $tag);
		return $this->Processors[$prefix];
	}
}*/