<?php
/**
* @version	$Id: tag_processor.php 14241 2011-03-16 20:24:35Z 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 {

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

		function CheckTag($tag, $prefix)
		{
			$Method = $tag;
			if(method_exists($this, $Method))
			{
				return true;
			}
			else {
				if ($this->Application->hasObject('TagsAggregator')) {
					$aggregator =& $this->Application->recallObject('TagsAggregator');
					$tmp = $this->Application->processPrefix($prefix);
					$tag_mapping = $aggregator->GetArrayValue($tmp['prefix'], $Method);
					if ($tag_mapping) {
						return true;
					}
				}
			}
		}

		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;

				$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_recursive2($this->Application->Parser->Params, $params);
				}

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

				$this->Prefix = $backup_prefix;
				$this->Special = $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;
				}

				$this->Application->handleError(E_USER_ERROR, 'Tag Undefined:<br><b>'.$prefix.':'.$tag.'</b>', $file, $line);
				return false;
			}
		}

		function processAggregatedTag($tag, $params, $prefix, $file = 'unknown', $line = 0)
		{
			if ($this->Application->hasObject('TagsAggregator')) {
				$Method = $tag;
				$aggregator =& $this->Application->recallObject('TagsAggregator');
				$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);
					$processor->Prefix = $tmp['prefix'];
					$processor->Special = 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
					if ($this->Application->isDebugMode()) {
						$this->Application->Debugger->appendTrace();
					}
					$this->Application->handleError(E_USER_ERROR, 'Tag <b>'.$Method.'</b> Undefined in '.get_class($this).'[Agregated Tag]:<br><b>'.$tag.'</b>', $file, $line);
				}
			}

			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
	 * @access public
	 */
	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);
				if (((string)$value != '') && ((string)$value != '0')) {
					return $value;
				}
			}

			return '';
		}

		if (!is_array($params)) {
			// really happens?
			return;
		}

		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];
	}
}*/