<?php
/**
* @version	$Id: main_processor.php 16615 2018-04-06 13:43:58Z 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 kMainTagProcessor extends kTagProcessor {

	public function __construct()
	{
		parent::__construct();

		/** @var Params $actions */
		$actions = $this->Application->recallObject('kActions');

		$actions->Set('t', $this->Application->GetVar('t'));
		$actions->Set('sid', $this->Application->GetSID());
		$actions->Set('m_opener', $this->Application->GetVar('m_opener') );
	}

	/**
	 * Base folder for all template includes
	 *
	 * @param Array $params
	 * @return string
	 */
	function TemplatesBase($params)
	{
		static $cached = Array ();

		$cache_key = crc32( serialize($params) );

		if (!array_key_exists($cache_key, $cached)) {
			$module = array_key_exists('module', $params) ? $params['module'] : 'core';

			if ($this->Application->isAdmin) {
				if ($module == 'in-portal') {
					$module = 'kernel';
				}

				// remove leading slash + substitute module
				$module_path = $this->Application->findModule('Name', $module, 'Path');

				if ($module_path !== false) {
					$path = $module_path . 'admin_templates';
				}
				else {
					// remove leading slash + substitute module
					$path = preg_replace('/\/(.*?)\/(.*)/', $module . '/\\2', THEMES_PATH);
				}
			}
			else {
				$path = mb_substr(THEMES_PATH, 1);

				if (mb_strtolower($module) == 'in-portal') {
					$module_folder = 'platform';
				}
				else {
					$module_folder = $this->Application->findModule('Name', $module, 'TemplatePath');
				}

				$path .= rtrim('/' . trim($module_folder, '/'), '/') . '/';
			}

			$cached[$cache_key] = $this->Application->BaseURL() . $path;
		}

		return $cached[$cache_key];
	}

	/**
	 * Creates <base href ..> HTML tag for all templates
	 * affects future css, js files and href params of links
	 *
	 * @param Array $params
	 * @return string
	 * @access protected
	 * @see kMainTagProcessor::TemplatesBase
	 */
	protected function Base_Ref($params)
	{
		// tag TemplatesBase adds trailing "/" but only on Front-End
		$base_href = rtrim($this->TemplatesBase($params), '/');

		return '<base href="' . $base_href . '/" />';
	}

	/**
	 * Returns base url for web-site
	 *
	 * @return string
	 * @access public
	 */
	function BaseURL()
	{
		return $this->Application->BaseURL();
	}

	//for compatability with K3 tags
	function Base($params)
	{
		return $this->TemplatesBase($params).'/';
	}

	function ProjectBase($params)
	{
		return $this->Application->BaseURL();
	}

	/*function Base($params)
	{
		return $this->Application->BaseURL().$params['add'];
	}*/

	/**
	 * Used to create link to any template.
	 * use "pass" paramter if "t" tag to specify
	 * prefix & special of object to be represented
	 * in resulting url
	 *
	 * @param Array $params
	 * @return string
	 * @access public
	 */
	function T($params)
	{
		// by default link to current template
		$template = $this->SelectParam($params, 't,template');
		$prefix = array_key_exists('prefix', $params) ? $params['prefix'] : '';

		unset($params['t'], $params['template'], $params['prefix']);

		$no_html_escape = false;

		if ( isset($params['no_amp']) ) {
			$no_html_escape = $params['no_amp'];
			unset($params['no_amp']);
		}

		$ret = $this->Application->HREF($template, $prefix, $params);

		if ( !$no_html_escape ) {
			// most of the time links are placed into HTML document
			// TODO: in future always do escaping according to current "escape context"
			$ret = kUtil::escape($ret, kUtil::ESCAPE_HTML);
		}

		return $ret;
	}

	function Link($params)
	{
		// pass "m" prefix, instead of "all", that is by default on Front-End
		if (!array_key_exists('pass', $params)) {
			$params['pass'] = 'm';
		}

		return $this->T($params);
	}

	/**
	 * Performs redirect to provided template/url
	 *
	 * @param Array $params
	 * @return string
	 */
	function Redirect($params)
	{
		// By default link to current template.
		$template = $this->SelectParam($params, 't,template');
		$prefix = array_key_exists('prefix', $params) ? $params['prefix'] : '';

		unset($params['t'], $params['template'], $params['prefix']);

		// Pass "m" prefix, instead of "all", that is by default on Front-End.
		if ( !array_key_exists('pass', $params) ) {
			$params['pass'] = 'm';
		}

		$this->Application->Redirect($template, $params, $prefix);

		return '';
	}

	/*function Env($params)
	{
		$t = $params['template'];
		unset($params['template']);
		return $this->Application->BuildEnv($t, $params, 'm', false, false);
	}*/

	function FormAction($params)
	{
		if (!array_key_exists('pass', $params)) {
			$params['pass'] = 'all,m';
		}

		$params['pass_category'] = 1;

		return $this->Application->HREF('', '', $params);
	}

	/*// NEEDS TEST
	function Config($params)
	{
		return $this->Application->ConfigOption($params['var']);
	}

	function Object($params)
	{
		$name = $params['name'];
		$method = $params['method'];

		$tmp = $this->Application->recallObject($name);
		if ($tmp != null) {
			if (method_exists($tmp, $method))
				return $tmp->$method($params);
			else
				echo "Method $method does not exist in object ".get_class($tmp)." named $name<br>";
		}
		else
			echo "Object $name does not exist in the appliaction<br>";
	}*/

	/**
	 * Tag, that always returns true.
	 * For parser testing purposes
	 *
	 * @param Array $params
	 * @return bool
	 * @access public
	 */
	function True($params)
	{
		return true;
	}

	/**
	 * Tag, that always returns false.
	 * For parser testing purposes
	 *
	 * @param Array $params
	 * @return bool
	 * @access public
	 */
	function False($params)
	{
		return false;
	}

	/**
	 * Returns block parameter by name (used only as "check" parameter value for "m_if" tag!)
	 *
	 * @param Array $params
	 * @return stirng
	 * @access public
	 */
	function Param($params)
	{
		$name = $params['name'];

		if (array_key_exists($name, $this->Application->Parser->Captures)) {
			$capture_params = $params;
			$capture_params['name'] = '__capture_' . $name;

			$this->Application->Parser->SetParam($name, $this->Application->ParseBlock($capture_params));
		}

		$res = $this->Application->Parser->GetParam($name);

		if ($res === false) {
			$res = '';
		}

		if (array_key_exists('plus', $params)) {
			$res += $params['plus'];
		}

		return $res;
	}

	/**
	 * Compares block parameter with value specified
	 *
	 * @param Array $params
	 * @return bool
	 * @access public
	 */
	function ParamEquals($params)
	{
		$name = $this->SelectParam($params, 'name,var,param');
		$value = $params['value'];

		return ($this->Application->Parser->GetParam($name) == $value);
	}

	/*function PHP_Self($params)
	{
		return $HTTP_SERVER_VARS['PHP_SELF'];
	}
	*/

	/**
	 * Returns session variable value by name
	 *
	 * @param Array $params
	 * @return string
	 * @access public
	 */
	function Recall($params)
	{
		$var_name = $this->SelectParam($params,'name,var,param');

		if (isset($params['persistent']) && $params['persistent']) {
			$ret = $this->Application->RecallPersistentVar($var_name);
		}
		else {
			 $ret = $this->Application->RecallVar($var_name);
		}

		$ret = ($ret === false && isset($params['no_null'])) ? '' : $ret;
		if (getArrayValue($params, 'special') || getArrayValue($params, 'htmlchars')) {
			$ret = kUtil::escape($ret, kUtil::ESCAPE_HTML);
		}

		if (getArrayValue($params, 'urlencode')) {
			$ret = kUtil::escape($ret, kUtil::ESCAPE_URL);
		}

		return $ret;
	}

	function RemoveVar($params)
	{
		$this->Application->RemoveVar( $this->SelectParam($params,'name,var,param') );
	}

	// bad style to store something from template to session !!! (by Alex)
	// Used here only to test how session works, nothing more
	function Store($params)
	{
		//echo"Store $params[name]<br>";
		$name = $params['name'];
		$value = $params['value'];
		$this->Application->StoreVar($name,$value);
	}

	/**
	 * Links variable from request with variable from session
	 *
	 * @param Array $params
	 * @return string
	 * @access protected
	 */
	protected function LinkVar($params)
	{
		$var_name = $params['name'];
		$session_var_name = isset($params['session_name']) ? $params['session_name'] : $var_name;
		$default_value = isset($params['default']) ? $params['default'] : '';

		$this->Application->LinkVar($var_name, $session_var_name, $default_value);

		return '';
	}

	/**
	 * Links variable from request with variable from session and returns it's value
	 *
	 * @param Array $params
	 * @return string
	 * @access protected
	 */
	protected function GetLinkedVar($params)
	{
		$this->LinkVar($params);

		return $this->Application->GetVar( $params['name'] );
	}

	/**
	 * Sets application variable value(-s)
	 *
	 * @param Array $params
	 * @access public
	 */
	function Set($params)
	{
		foreach ($params as $param => $value) {
			$this->Application->SetVar($param, $value);
		}
	}

	/**
	 * Increment application variable
	 * specified by number specified
	 *
	 * @param Array $params
	 * @access public
	 */
	function Inc($params)
	{
		$this->Application->SetVar($params['param'], $this->Application->GetVar($params['param']) + $params['by']);
	}

	/**
	 * Retrieves application variable
	 * value by name
	 *
	 * @param Array $params
	 * @return string
	 * @access public
	 */
	function Get($params)
	{
		$name = $this->SelectParam($params, 'name,var,param');

		if ( strpos($name, '[') !== false ) {
			preg_match('/([^\[\]]+)\[(.*)\]/', $name, $regs);

			$function_params = explode('][', $regs[2]);
			$ret = $this->Application->GetVar($regs[1], array());
			kUtil::array_unshift_ref($function_params, $ret);

			$ret = call_user_func_array('getArrayValue', $function_params);
		}
		else {
			$ret = $this->Application->GetVar($name, '');
		}

		$ret = $this->Application->unescapeRequestVariable($ret);

		if ( array_key_exists('no_html_escape', $params) && $params['no_html_escape'] ) {
			return $ret;
		}

		return kUtil::escape($ret, kUtil::ESCAPE_HTML);
	}

	/**
	 * Retrieves application constant
	 * value by name
	 *
	 * @param Array $params
	 * @return string
	 * @access public
	 */
	function GetConst($params)
	{
		$constant_name = $this->SelectParam($params, 'name,const');

		return defined($constant_name) ? constant($constant_name) : '';
	}

	/**
	 * Retrieves configuration variable value by name
	 *
	 * @param Array $params
	 * @return string
	 * @access public
	 */
	function GetConfig($params)
	{
		$config_name = $this->SelectParam($params, 'name,var');
		$ret = $this->Application->ConfigValue($config_name);

		if ( isset($params['formatted']) && $params['formatted'] ) {
			$sql = 'SELECT ValueList
					FROM ' . TABLE_PREFIX . 'SystemSettings
					WHERE VariableName = ' . $this->Conn->qstr($config_name) . ' AND ElementType IN ("select", "radio")';
			$value_list = $this->Conn->GetOne($sql);

			if ( $value_list ) {
				/** @var InpCustomFieldsHelper $helper */
				$helper = $this->Application->recallObject('InpCustomFieldsHelper');

				$options = $helper->GetValuesHash($value_list);
				$ret = isset($options[$ret]) ? $options[$ret] : $ret;
			}
		}

		if ( isset($params['as_label']) && $params['as_label'] ) {
			$ret = $this->Application->Phrase($ret);
		}

		return $ret;
	}

	/**
	 * Compares configuration variable to a given value
	 *
	 * @param Array $params
	 * @return bool
	 * @deprecated
	 * @access protected
	 */
	protected function ConfigEquals($params)
	{
		$option = $this->SelectParam($params, 'name,option,var');

		return $this->Application->ConfigValue($option) == $params['value'];
	}

	/**
	 * Creates all hidden fields
	 * needed for kernel_form
	 *
	 * @param Array $params
	 * @return string
	 * @access protected
	 */
	protected function DumpSystemInfo($params)
	{
		/** @var Params $actions */
		$actions = $this->Application->recallObject('kActions');

		$actions->Set('t', $this->Application->GetVar('t'));

		$o = '';
		$params = $actions->GetParams();

		foreach ($params AS $name => $val) {
			$o .= "<input type='hidden' name='$name' id='$name' value='$val'>\n";
		}

		return $o;
	}

	/**
	 * Used for search sidebox on front-end only
	 *
	 * @param Array $params
	 * @return string
	 * @access protected
	 */
	protected function GetFormHiddens($params)
	{
		$t = $this->SelectParam($params, 'template,t');
		unset($params['template']);

		$form_fields = Array ();
		if ( $this->Application->RewriteURLs() ) {
			/** @var Session $session */
			$session = $this->Application->recallObject('Session');

			if ( $session->NeedQueryString() ) {
				$form_fields['sid'] = $this->Application->GetSID();
			}
		}
		else {
			$form_fields['env'] = $this->Application->BuildEnv($t, $params, 'm', false, false);
		}

		if ( $this->Application->GetVar('admin') == 1 ) {
			$form_fields['admin'] = 1;
		}

		$ret = '';
		$field_tpl = '<input type="hidden" name="%1$s" id="%1$s" value="%2$s"/>' . "\n";
		foreach ($form_fields as $form_field => $field_value) {
			$ret .= sprintf($field_tpl, $form_field, $field_value);
		}

		return $ret;
	}

	function Odd_Even($params)
	{
		$odd = $params['odd'];
		$even = $params['even'];
		if (!isset($params['var'])) {
			$var = 'odd_even';
		}
		else {
			$var = $params['var'];
		}

		if ($this->Application->GetVar($var) == 'even') {
			if (!isset($params['readonly']) || !$params['readonly']) {
				$this->Application->SetVar($var, 'odd');
			}
			return $even;
		}
		else {
			if (!isset($params['readonly']) || !$params['readonly']) {
				$this->Application->SetVar($var, 'even');
			}
			return $odd;
		}
	}

	/**
	 * Returns phrase translation by name
	 *
	 * @param Array $params
	 * @return string
	 * @access public
	 */
	function Phrase($params)
	{
		$phrase_name = $this->SelectParam($params, 'label,name,title');
		$default_translation = $this->SelectParam($params, 'default');

		$no_editing = isset($params['no_editing']) && $params['no_editing'];
		$translation = $this->Application->Phrase($phrase_name, !$no_editing);

		$phrase_key = mb_strtoupper($phrase_name);

		if ( $default_translation && strpos($translation, '!' . $phrase_key . '!') !== false ) {
			/** @var kDBItem $phrase */
			$phrase = $this->Application->recallObject('phrases.autocreate', null, Array ('skip_autoload' => true));

			if ( !$phrase->Load($phrase_key, 'PhraseKey') ) {
				$phrase->SetDBField('Phrase', $phrase_name);

				/** @var kMultiLanguageHelper $ml_helper */
				$ml_helper = $this->Application->recallObject('kMultiLanguageHelper');

				$languages = $ml_helper->getLanguages();

				foreach ($languages AS $language_id) {
					$phrase->SetDBField('l' . $language_id . '_Translation', $default_translation);
				}

				if ( $phrase->Create() ) {
					$translation = $default_translation;
				}
			}
		}

		if ( isset($params['escape']) && $params['escape'] ) {
			// html escaping here is redundant
			$translation = kUtil::escape($translation, kUtil::ESCAPE_JS);
		}

		return $translation;
	}

	// for tabs
	function is_active($params)
	{
		$test_templ = $this->SelectParam($params, 'templ,template,t');
		if ( !getArrayValue($params, 'allow_empty') ) {
			$if_true = getArrayValue($params, 'true') ? $params['true'] : 1;
			$if_false = getArrayValue($params, 'false') ? $params['false'] : 0;
		}
		else {
			$if_true = $params['true'];
			$if_false = $params['false'];
		}

		$physical_template = $this->Application->getPhysicalTemplate($this->Application->GetVar('t'));

		return preg_match('/^' . str_replace('/', '\/', $test_templ) . '/i', $physical_template) ? $if_true : $if_false;
	}

	function IsNotActive($params)
	{
		return !$this->is_active($params);
	}

	function IsActive($params)
	{
		return $this->is_active($params);
	}

	function is_t_active($params)
	{
		return $this->is_active($params);
	}

	function CurrentTemplate($params)
	{
		return $this->is_active($params);
	}

	/**
	 * Checks if session variable
	 * specified by name value match
	 * value passed as parameter
	 *
	 * @param Array $params
	 * @return string
	 * @access public
	 */
	function RecallEquals($params)
	{
		$name = $this->SelectParam($params, 'name,var');
		$value = $params['value'];

		if (isset($params['persistent']) && $params['persistent']) {
			return $this->Application->RecallPersistentVar($name) == $value;
		}

		return ($this->Application->RecallVar($name) == $value);
	}

	/**
	 * Checks if application variable specified by name value match value passed as parameter
	 *
	 * @param Array $params
	 * @return bool
	 * @access protected
	 * @deprecated
	 */
	protected function GetEquals($params)
	{
		$name = $this->SelectParam($params, 'var,name,param');

		return $this->Application->GetVar($name) == $params['value'];
	}

	function ModuleInclude($params)
	{
		$ret = '';
		$included = Array ();
		$block_params = array_merge($params, Array ('is_silent' => 2)); // don't make fatal errors in case if template is missing
		$current_template = $this->Application->GetVar('t');

		$replace_main = isset($params['replace_m']) && $params['replace_m'];
		$skip_prefixes = isset($params['skip_prefixes']) ? explode(',', $params['skip_prefixes']) : Array ();
		$cms_mode = $this->Application->GetVar('admin');

		foreach ($this->Application->ModuleInfo as $module_name => $module_data) {
			$module_key = mb_strtolower($module_name);

			if ( $module_name == 'In-Portal' ) {
				if ( !$cms_mode && $this->Application->isAdmin ) {
					// don't process In-Portal templates in admin
					continue;
				}

				// Front-End still relies on In-Portal module
				$module_prefix = $module_data['TemplatePath'];
			}
			elseif ( $this->Application->isAdmin && $module_data['Path'] != 'core/' ) {
				$module_prefix = $module_key . '/'; // was $module_data['Path'];
			}
			else {
				$module_prefix = $module_data['TemplatePath']; // always have trailing "/"
			}

			if ( in_array($module_prefix, $included) ) {
				// template by this path was already included by other module (e.g. in-portal used core's template)
				continue;
			}

			$block_params['t'] = $module_prefix . $this->SelectParam($params, $module_key . '_template,' . $module_key . '_t,template,t');

			$check_prefix = $module_data['Var'];

			if ( $check_prefix == 'adm' && $replace_main ) {
				$check_prefix = 'c';
			}

			if ( $block_params['t'] == $current_template || in_array($check_prefix, $skip_prefixes) ) {
				continue;
			}

			$no_data = $this->SelectParam($params, $module_key . '_block_no_data,block_no_data');
			if ( $no_data ) {
				$block_params['block_no_data'] = $module_prefix . '/' . $no_data;
			}

			$ret .= $this->Application->IncludeTemplate($block_params);
			$included[] = $module_prefix;
		}

		return $ret;
	}

	function ModuleEnabled($params)
	{
		return $this->Application->isModuleEnabled( $params['module'] );
	}

	/**
	 * Checks if debug mode is on
	 *
	 * @param Array $params
	 * @return bool
	 * @access public
	 */
	function IsDebugMode($params)
	{
		return defined('DEBUG_MODE') && $this->Application->isDebugMode();
	}

	/*function MassParse($params)
	{
		$qty = $params['qty'];
		$block = $params['block'];
		$mode = $params['mode'];

		$o = '';
		if ($mode == 'func') {
			$func = create_function('$params', '
					$o = \'<tr>\';
					$o.= \'<td>a\'.$params[\'param1\'].\'</td>\';
					$o.= \'<td>a\'.$params[\'param2\'].\'</td>\';
					$o.= \'<td>a\'.$params[\'param3\'].\'</td>\';
					$o.= \'<td>a\'.$params[\'param4\'].\'</td>\';
					$o.= \'</tr>\';
					return $o;
				');
			for ($i=1; $i<$qty; $i++) {
				$block_params['param1'] = rand(1, 10000);
				$block_params['param2'] = rand(1, 10000);
				$block_params['param3'] = rand(1, 10000);
				$block_params['param4'] = rand(1, 10000);
				$o .= $func($block_params);
			}
			return $o;
		}

		$block_params['name'] = $block;

		for ($i=0; $i<$qty; $i++) {
			$block_params['param1'] = rand(1, 10000);
			$block_params['param2'] = rand(1, 10000);
			$block_params['param3'] = rand(1, 10000);
			$block_params['param4'] = rand(1, 10000);
			$block_params['passed'] = $params['passed'];
			$block_params['prefix'] = 'm';

			$o.= $this->Application->ParseBlock($block_params);
		}
		return $o;
	}*/

	function LoggedIn($params)
	{
		return $this->Application->LoggedIn();
	}

	/**
	 * Allows to check if permission exists directly in template and perform additional actions if required
	 *
	 * @param Array $params
	 * @return bool
	 */
	function CheckPermission($params)
	{
		/** @var kPermissionsHelper $perm_helper */
		$perm_helper = $this->Application->recallObject('PermissionsHelper');

		return $perm_helper->TagPermissionCheck($params);
	}

	/**
	 * Checks if user is logged in and if not redirects it to template passed
	 *
	 * @param Array $params
	 */
	function RequireLogin($params)
	{
		$t = $this->Application->GetVar('t');
		$next_t = getArrayValue($params, 'next_template');

		if ( $next_t ) {
			$t = $next_t;
		}

		// check by permissions: begin
		if ((isset($params['perm_event']) && $params['perm_event']) ||
			(isset($params['perm_prefix']) && $params['perm_prefix']) ||
			(isset($params['permissions']) && $params['permissions'])) {

			/** @var kPermissionsHelper $perm_helper */
			$perm_helper = $this->Application->recallObject('PermissionsHelper');

			$perm_status = $perm_helper->TagPermissionCheck($params);
			if (!$perm_status) {
				list($redirect_template, $redirect_params) = $perm_helper->getPermissionTemplate($params);
				$this->Application->Redirect($redirect_template, $redirect_params);
			}
			else {
				return ;
			}
		}
		// check by permissions: end

		// check by configuration value: begin
		$condition = getArrayValue($params, 'condition');
		if (!$condition) {
			$condition = true;
		}
		else {
			if (substr($condition, 0, 1) == '!') {
				$condition = !$this->Application->ConfigValue(substr($condition, 1));
			}
			else {
				$condition = $this->Application->ConfigValue($condition);
			}
		}
		// check by configuration value: end

		// check by belonging to group: begin
		$group = $this->SelectParam($params, 'group');
		$group_access = true;
		if ($group) {
			$sql = 'SELECT GroupId
					FROM '.TABLE_PREFIX.'UserGroups
					WHERE Name = '.$this->Conn->qstr($group);
			$group_id = $this->Conn->GetOne($sql);

			if ($group_id) {
				$groups = explode(',', $this->Application->RecallVar('UserGroups'));
				$group_access = in_array($group_id, $groups);
			}
		}
		// check by belonging to group: end

		if ((!$this->Application->LoggedIn() || !$group_access) && $condition) {
			$redirect_params = $this->Application->HttpQuery->getRedirectParams(true);

			if (MOD_REWRITE) {
				// TODO: $next_t variable is ignored !!! (is anyone using m_RequireLogin tag with "next_template" parameter?)
				$redirect_params = Array (
					'm_cat_id' => 0,
					'next_template' => 'external:' . $_SERVER['REQUEST_URI'],
				);
			}
			else {
				$redirect_params['next_template'] = $t;
			}

			if (array_key_exists('pass_category', $params)) {
				$redirect_params['pass_category'] = $params['pass_category'];
			}

			if (array_key_exists('use_section', $params)) {
				$redirect_params['use_section'] = $params['use_section'];
			}

			if ( $this->Application->LoggedIn() && !$group_access) {
				$this->Application->Redirect($params['no_group_perm_template'], $redirect_params);
			}

			$this->Application->Redirect($params['login_template'], $redirect_params);
		}
	}

	/**
	 * Checks, that user belongs to a group with a given name
	 *
	 * @param Array $params
	 * @return bool
	 */
	protected function IsMember($params)
	{
		$sql = 'SELECT GroupId
				FROM ' . TABLE_PREFIX . 'UserGroups
				WHERE Name = ' . $this->Conn->qstr($params['group']);
		$group_id = $this->Conn->GetOne($sql);

		if ( $group_id ) {
			$groups = explode(',', $this->Application->RecallVar('UserGroups'));

			return in_array($group_id, $groups);
		}

		return false;
	}

	/**
	 * Checks if SSL is on and redirects to SSL URL if needed
	 * If SSL_URL is not defined in config - the tag does not do anything
	 * If for_logged_in_only="1" exits if user is not logged in.
	 * If called without params forces https right away. If called with by_config="1" checks the
	 * Require SSL setting from General Config and if it is ON forces https
	 *
	 * @param Array $params
	 */
	protected function CheckSSL($params)
	{
		$ssl = $this->Application->isAdmin ? $this->Application->ConfigValue('AdminSSL_URL') : false;

		if ( !$ssl ) {
			// not in admin or admin ssl url is empty
			$ssl_url = $this->Application->siteDomainField('SSLUrl');
			$ssl = $ssl_url !== false ? $ssl_url : $this->Application->ConfigValue('SSL_URL');
		}

		if ( !$ssl || ($this->Application->TemplatesCache->forceThemeName !== false) ) {
			// SSL URL is not set - no way to require SSL
			// internal parsing (e.g. "TemplateParser::_parseTemplate") -> don't redirect
			return;
		}

		$require = false;

		if ( isset($params['mode']) && $params['mode'] == 'required' ) {
			$require = true;
			if ( isset($params['for_logged_in_only']) && $params['for_logged_in_only'] && !$this->Application->LoggedIn() ) {
				$require = false;
			}

			if ( isset($params['condition']) ) {
				if ( !$this->Application->ConfigValue($params['condition']) ) {
					$require = false;
				}
			}
		}

		if ( defined('EDITING_MODE') && EDITING_MODE ) {
			// Match SSL mode on front-end to one in administrative console, when browse modes are used.
			$require = $this->Application->ConfigValue('Require_AdminSSL');
		}

		/** @var kHTTPQuery $http_query */
		$http_query = $this->Application->recallObject('HTTPQuery');

		$pass = $http_query->getRedirectParams();
		$pass['pass_events'] = 1; // to make sure all events are passed when redirect happens

		if ( $require ) {
			if ( PROTOCOL == 'https://' ) {
				$this->Application->SetVar('__KEEP_SSL__', 1);
				return;
			}

			$pass['__SSL__'] = 1;
			$this->Application->Redirect('', $pass);
		}
		else {
			if ( PROTOCOL == 'https://' && $this->Application->ConfigValue('Force_HTTP_When_SSL_Not_Required') ) {
				if ( $this->Application->GetVar('__KEEP_SSL__') ) {
					return;
				}

				// $pass_more = Array ('pass' => 'm', 'm_cat_id' => 0, '__SSL__' => 0);
				$pass['__SSL__'] = 0;
				$this->Application->Redirect('', $pass); // $pass_more
			}
		}
	}

	function ConstOn($params)
	{
		$name = $this->SelectParam($params,'name,const');
		return kUtil::constOn($name);
	}

	function SetDefaultCategory($params)
	{
		$category_id = $this->Application->findModule('Name', $params['module'], 'RootCat');
		$this->Application->SetVar('m_cat_id', $category_id);
	}

	function XMLTemplate($params)
	{
		$this->NoDebug($params);

		if ( isset($params['cache']) && $params['cache'] ) {
			$nextyear = intval(date('Y') + 1);

			$format = "D, d M Y H:i:s";
			$expiration = gmdate($format, time() + $params['cache']) . ' GMT';
			$last_modified = time();

			header('Cache-Control: public, cache, max-age=' . $params['cache']);
			header("Expires: $expiration");
			header('Pragma: public');

			// Getting headers sent by the client.
			$headers = $this->Application->HttpQuery->getHeaders();

			// Checking if the client is validating his cache and if it is current.
			if ( isset($headers['If-Modified-Since']) && (strtotime($headers['If-Modified-Since']) > $last_modified - $params['cache']) ) {
				// Client's cache IS current, so we just respond '304 Not Modified'.
				header('Last-Modified: ' . date($format, strtotime($headers['If-Modified-Since'])) . ' GMT', true, 304);
				exit;
			}
			else {
				// Image not cached or cache outdated, we respond '200 OK' and output the image.
				header('Last-Modified: ' . gmdate($format, $last_modified) . ' GMT', true, 200);
			}
		}

		// xml documents are usually long
		kUtil::setResourceLimit();

		if ( !$this->Application->GetVar('debug') ) {
			return $this->Application->XMLHeader(getArrayValue($params, 'xml_version'));
		}

		return '';
	}

	function Header($params)
	{
		header($params['data']);
	}

	function NoDebug($params)
	{
		if ( !$this->Application->GetVar('debug') ) {
			kUtil::safeDefine('DBG_SKIP_REPORTING', 1);
		}
	}

	/**
	 * Returns Home category name
	 *
	 * @param Array $params
	 * @return string
	 * @deprecated
	 */
	function RootCategoryName($params)
	{
		$no_editing = array_key_exists('no_editing', $params) && $params['no_editing'];

		return $this->Application->Phrase('la_rootcategory_name', !$no_editing);
	}

	/**
	 * Allows to attach file directly from email event template
	 *
	 * @param Array $params
	 */
	function AttachFile($params)
	{
		$path = FULL_PATH . '/' . $params['path'];
		$pseudo = isset($params['special']) ? 'EmailSender.' . $params['special'] : 'EmailSender';

		/** @var kEmailSendingHelper $esender */
		$esender = $this->Application->recallObject($pseudo);

		if ( file_exists($path) && is_file($path) ) {
			$esender->AddAttachment($path);
		}
	}

	function CaptchaImage($params)
	{
		$this->NoDebug($params);
		$this->Application->SetVar('skip_last_template', 1);

		/** @var kCaptchaHelper $captcha_helper */
		$captcha_helper = $this->Application->recallObject('CaptchaHelper');

		// generate captcha code
		$code = $captcha_helper->prepareCode( $this->Application->GetVar('var') );

		$captcha_helper->GenerateCaptchaImage($code, $this->Application->GetVar('w'), $this->Application->GetVar('h'), true);
	}

	function SID($params)
	{
		return $this->Application->GetSID();
	}

	function ModuleInfo($params)
	{
		return $this->Application->findModule($params['key'], $params['value'], $params['return']);
	}

	function Random($params)
	{
		return rand(1, 100000000);
	}

	/**
	 * Prints parser params, available at current deep level
	 *
	 * @param Array $params
	 * @return string
	 */
	function PrintCurrentParams($params)
	{
		$current_params = $this->Application->Parser->Params;

		foreach ($current_params as $param_name => $param_value) {
			if ( is_object($param_value) && !method_exists($param_value, '__toString') ) {
				$param_value = 'ClassName: ' . get_class($param_value);
			}

			$current_params[$param_name] = $param_name . ' = "' . $param_value . '"';
		}

		return '<pre>' . implode("\n", $current_params) . '</pre>';
	}

	/**
	 * Gets previously defined counter result
	 *
	 * @param Array $params
	 * @return int
	 */
	function GetCounter($params)
	{
		return $this->Application->getCounter($params['name'], $params);
	}

	/**
	 * Increments PageHit counter
	 *
	 * @param Array $params
	 * @return int
	 */
	function RegisterPageHit($params)
	{
		if ($this->Application->ConfigValue('UsePageHitCounter')) {
			// get current counte
			$sql = 'SELECT VariableValue
					FROM '.TABLE_PREFIX.'SystemSettings
					WHERE VariableName = "PageHitCounter"';
			$page_counter = (int)$this->Conn->GetOne($sql);

			$sql = 'UPDATE LOW_PRIORITY '.TABLE_PREFIX.'SystemSettings
					SET VariableValue = '.($page_counter + 1).'
					WHERE VariableName = "PageHitCounter"';
			$this->Conn->Query($sql);
		}
	}

	function Timestamp($params)
	{
		$format = isset($params['format']) ? $params['format'] : 'd.m.Y H:i:s';
		return adodb_date($format);
	}

	function GetUrlHiddenFileds($params)
	{
		$vars = Array ('page', 'per_page', 'sort_by');
		$ret = '<input type="hidden" name="main_list" value="1"/>';

		if (array_key_exists('skip', $params)) {
			$vars = array_diff($vars, $params['skip']);
		}

		foreach ($vars as $var_name) {
			$var_value = $this->Application->GetVar($var_name);

			if ($var_value) {
				$ret .= '<input type="hidden" name="' . $var_name . '" value="' . $var_value . '"/>';
			}
		}

		return $ret;
	}

	/**
	 * Returns current Page URL (without re-assembling it).
	 * "skip_query" param is optional and will remove the ?QUERY part from the result.
	 *
	 * @param Array $params
	 * @return string
	 * @access protected
	 */
	protected function CurrentPageLink($params)
	{
		if ( isset($params['skip_query']) && $params['skip_query'] ) {
			return preg_replace('/\?' . preg_quote($_SERVER['QUERY_STRING'], '/') . '$/', '', $_SERVER['REQUEST_URI']);
		}

		return $_SERVER['REQUEST_URI'];
	}

	/**
	 * Returns current maintenance mode state
	 *
	 * @param Array $params
	 * @return int
	 * @access protected
	 */
	protected function MaintenanceMode($params)
	{
		$check_ips = isset($params['check_ips']) ? $params['check_ips'] : true;

		return $this->Application->getMaintenanceMode($check_ips);
	}

	/**
	 * Checks if element with given name is defined
	 *
	 * @param Array $params
	 * @return int
	 * @access protected
	 */
	protected function ElementDefined($params)
	{
		return $this->Application->Parser->blockFound($params['name']);
	}
}
