Index: branches/RC/core/kernel/db/db_tag_processor.php
===================================================================
--- branches/RC/core/kernel/db/db_tag_processor.php	(revision 11912)
+++ branches/RC/core/kernel/db/db_tag_processor.php	(revision 11913)
@@ -1,2528 +1,2543 @@
 <?php
 /**
 * @version	$Id$
 * @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.net/license/ for copyright notices and details.
 */
 
 class kDBTagProcessor extends TagProcessor {
 
 	/**
 	* Description
 	*
 	* @var kDBConnection
 	* @access public
 	*/
 	var $Conn;
 
 	function kDBTagProcessor()
 	{
 		parent::kBase();
 		$this->Conn =& $this->Application->GetADODBConnection();
 	}
 
 
 	/**
 	 * Returns true if "new" button was pressed in toolbar
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function IsNewMode($params)
 	{
 		$object =& $this->getObject($params);
 		return $object->GetID() <= 0;
 	}
 
 	/**
 	 * Returns view menu name for current prefix
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function GetItemName($params)
 	{
 		$item_name = $this->Application->getUnitOption($this->Prefix, 'ViewMenuPhrase');
 		return $this->Application->Phrase($item_name);
 	}
 
 	function ViewMenu($params)
 	{
 		$block_params = $params;
 		unset($block_params['block']);
 		$block_params['name'] = $params['block'];
 
 		$list =& $this->GetList($params);
 		$block_params['PrefixSpecial'] = $list->getPrefixSpecial();
 		return $this->Application->ParseBlock($block_params);
 	}
 
 	function SearchKeyword($params)
 	{
 		$list =& $this->GetList($params);
 		return $this->Application->RecallVar($list->getPrefixSpecial().'_search_keyword');
 	}
 
 	/**
 	 * Draw filter menu content (for ViewMenu) based on filters defined in config
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function DrawFilterMenu($params)
 	{
 		$block_params = $this->prepareTagParams($params);
 		$block_params['name'] = $params['spearator_block'];
 		$separator = $this->Application->ParseBlock($block_params);
 		$filter_menu = $this->Application->getUnitOption($this->Prefix,'FilterMenu');
 		if (!$filter_menu) {
 			trigger_error('<span class="debug_error">no filters defined</span> for prefix <b>'.$this->Prefix.'</b>, but <b>DrawFilterMenu</b> tag used', E_USER_WARNING);
 			return '';
 		}
 
 		// Params: label, filter_action, filter_status
 		$block_params['name'] = $params['item_block'];
 
 		$view_filter = $this->Application->RecallVar($this->getPrefixSpecial().'_view_filter');
 		if ($view_filter === false) {
 			$event_params = Array ('prefix' => $this->Prefix, 'special' => $this->Special, 'name' => 'OnRemoveFilters');
 			$this->Application->HandleEvent( new kEvent($event_params) );
 			$view_filter = $this->Application->RecallVar($this->getPrefixSpecial().'_view_filter');
 		}
 		$view_filter = unserialize($view_filter);
 
 		$filters = Array();
 		$prefix_special = $this->getPrefixSpecial();
 
 		foreach ($filter_menu['Filters'] as $filter_key => $filter_params) {
 			$group_params = isset($filter_params['group_id']) ? $filter_menu['Groups'][ $filter_params['group_id'] ] : Array();
 			if (!isset($group_params['element_type'])) {
 				$group_params['element_type'] = 'checkbox';
 			}
 
 			if (!$filter_params) {
 				$filters[] = $separator;
 				continue;
 			}
 
 			$block_params['label'] = addslashes( $this->Application->Phrase($filter_params['label']) );
 			if (getArrayValue($view_filter,$filter_key)) {
 				$submit = 0;
 				if (isset($params['old_style'])) {
 					$status = $group_params['element_type'] == 'checkbox' ? 1 : 2;
 				}
 				else {
 					$status = $group_params['element_type'] == 'checkbox' ? '[\'img/check_on.gif\']' : '[\'img/menu_dot.gif\']';
 				}
 			}
 			else {
 				$submit = 1;
 				$status = 'null';
 			}
 			$block_params['filter_action'] = 'set_filter("'.$prefix_special.'","'.$filter_key.'","'.$submit.'",'.$params['ajax'].');';
 			$block_params['filter_status'] = $status; // 1 - checkbox, 2 - radio, 0 - no image
 			$filters[] = $this->Application->ParseBlock($block_params);
 		}
 
 		return implode('', $filters);
 	}
 
 	/**
 	 * Draws auto-refresh submenu in View Menu.
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function DrawAutoRefreshMenu($params)
 	{
 		$refresh_intervals = $this->Application->ConfigValue('AutoRefreshIntervals');
 		if (!$refresh_intervals) {
 			trigger_error('<span class="debug_error">no filters defined</span> for prefix <strong>'.$this->Prefix.'</strong>, but <strong>DrawAutoRefreshMenu</strong> tag used', E_USER_WARNING);
 			return '';
 		}
 
 		$refresh_intervals = explode(',', $refresh_intervals);
 		$view_name = $this->Application->RecallVar($this->getPrefixSpecial().'_current_view');
 		$current_refresh_interval = $this->Application->RecallPersistentVar($this->getPrefixSpecial().'_refresh_interval.'.$view_name);
 		if ($current_refresh_interval === false) {
 			// if no interval was selected before, then choose 1st interval
 			$current_refresh_interval = $refresh_intervals[0];
 		}
 
 		$ret = '';
 		$block_params = $this->prepareTagParams($params);
 		$block_params['name'] = $params['render_as'];
 
 		foreach ($refresh_intervals as $refresh_interval) {
 			$block_params['label'] = $this->_formatInterval($refresh_interval);
 			$block_params['refresh_interval'] = $refresh_interval;
 			$block_params['selected'] = $current_refresh_interval == $refresh_interval;
 			$ret .= $this->Application->ParseBlock($block_params);
 		}
 		return $ret;
 	}
 
 	/**
 	 * Tells, that current grid is using auto refresh
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function UseAutoRefresh($params)
 	{
 		$view_name = $this->Application->RecallVar($this->getPrefixSpecial().'_current_view');
 		return $this->Application->RecallPersistentVar($this->getPrefixSpecial().'_auto_refresh.'.$view_name);
 	}
 
 	/**
 	 * Returns current grid refresh interval
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function AutoRefreshInterval($params)
 	{
 		$view_name = $this->Application->RecallVar($this->getPrefixSpecial().'_current_view');
 		return $this->Application->RecallPersistentVar($this->getPrefixSpecial().'_refresh_interval.'.$view_name);
 	}
 
 	/**
 	 * Formats time interval using given text for hours and minutes
 	 *
 	 * @param int $intervalmMinutes
 	 * @param string $hour_text Text for hours
 	 * @param string $min_text Text for minutes
 	 * @return unknown
 	 */
 	function _formatInterval($interval, $hour_text = 'h', $min_text = 'min')
 	{
 		// 65
 		$minutes = $interval % 60;
 		$hours = ($interval - $minutes) / 60;
 
 		$ret = '';
 		if ($hours) {
 			$ret .= $hours.$hour_text.' ';
 		}
 
 		if ($minutes) {
 			$ret .= $minutes.$min_text;
 		}
 
 		return $ret;
 	}
 
 	function IterateGridFields($params)
 	{
 		$mode = $params['mode'];
 		$def_block = isset($params['block']) ? $params['block'] : '';
 		$force_block = isset($params['force_block']) ? $params['force_block'] : false;
 
 		$grids = $this->Application->getUnitOption($this->Prefix,'Grids');
 		$grid_config = $grids[$params['grid']]['Fields'];
 
 		$picker_helper =& $this->Application->RecallObject('ColumnPickerHelper');
 		/* @var $picker_helper kColumnPickerHelper */
 		$picker_helper->ApplyPicker($this->getPrefixSpecial(), $grid_config, $params['grid']);
 
 		if ($mode == 'fields') {
 			return "'".join("','", array_keys($grid_config))."'";
 		}
 
 		$std_params['pass_params'] = 'true';
 		$std_params['PrefixSpecial'] = $this->getPrefixSpecial();
 
 		$object =& $this->GetList($params);
 
 		$o = '';
 		$i = 0;
 		foreach ($grid_config as $field => $options) {
 			$i++;
 			$block_params = Array();
 			$block_params['name'] = $force_block ? $force_block : (isset($options[$mode.'_block']) ? $options[$mode.'_block'] : $def_block);
 			$block_params['field'] = $field;
 			$block_params['sort_field'] = isset($options['sort_field']) ? $options['sort_field'] : $field;
 			$block_params['filter_field'] = isset($options['filter_field']) ? $options['filter_field'] : $field;
 
 			$w = $picker_helper->GetWidth($field);
 			if ($w) $options['width'] = $w;
 
 			/*if (isset($options['filter_width'])) {
 				$block_params['filter_width'] = $options['filter_width'];
 			}
 			elseif (isset($options['width'])) {
 				if (isset($options['filter_block']) && preg_match('/range/', $options['filter_block'])) {
 					if ($options['width'] < 60) {
 						$options['width'] = 60;
 						$block_params['filter_width'] = 20;
 					}
 					else {
 						$block_params['filter_width'] = $options['width'] - 40;
 					}
 				}
 				else {
 					$block_params['filter_width'] = max($options['width']-10, 20);
 				}
 			}*/
 			/*if (isset($block_params['filter_width'])) $block_params['filter_width'] .= 'px';
 
 
 			if (isset($options['filter_block']) && preg_match('/range/', $options['filter_block'])) {
 					$block_params['filter_width'] = '20px';
 			}
 			else {
 				$block_params['filter_width'] = '97%';
 //				$block_params['filter_width'] = max($options['width']-10, 20);
 			}*/
 
 
 			$field_options = $object->GetFieldOptions($field);
 			if (array_key_exists('use_phrases', $field_options)) {
 				$block_params['use_phrases'] = $field_options['use_phrases'];
 			}
 
 			$block_params['is_last'] = ($i == count($grid_config));
 			$block_params = array_merge($std_params, $options, $block_params);
 			$o.= $this->Application->ParseBlock($block_params, 1);
 		}
 		return $o;
 	}
 
 	function PickerCRC($params)
 	{
 		/* @var $picker_helper kColumnPickerHelper */
 		$picker_helper =& $this->Application->RecallObject('ColumnPickerHelper');
 		$picker_helper->SetGridName($params['grid']);
 		$data = $picker_helper->LoadColumns($this->getPrefixSpecial());
 		return $data['crc'];
 	}
 
 	function FreezerPosition($params)
 	{
 		/* @var $picker_helper kColumnPickerHelper */
 		$picker_helper =& $this->Application->RecallObject('ColumnPickerHelper');
 		$picker_helper->SetGridName($params['grid']);
 		$data = $picker_helper->LoadColumns($this->getPrefixSpecial());
 		$freezer_pos = array_search('__FREEZER__', $data['order']);
 		return $freezer_pos === false || in_array('__FREEZER__', $data['hidden_fields']) ? 1 : ++$freezer_pos;
 	}
 
 	function GridFieldsCount($params)
 	{
 		$grids = $this->Application->getUnitOption($this->Prefix, 'Grids');
 		$grid_config = $grids[$params['grid']]['Fields'];
 
 		return count($grid_config);
 	}
 
 	/**
 	 * Prints list content using block specified
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function PrintList($params)
 	{
 		$params['no_table'] = 1;
 		return $this->PrintList2($params);
 	}
 
 	function InitList($params)
 	{
 		$list_name = isset($params['list_name']) ? $params['list_name'] : '';
 
 		$names_mapping = $this->Application->GetVar('NamesToSpecialMapping');
 
 		if( !getArrayValue($names_mapping, $this->Prefix, $list_name) )
 		{
 			$list =& $this->GetList($params);
 		}
 	}
 
 	function BuildListSpecial($params)
 	{
 		return $this->Special;
 	}
 
 	/**
 	 * Returns key, that identifies each list on template (used internally, not tag)
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function getUniqueListKey($params)
 	{
 		$types = $this->SelectParam($params, 'types');
 		$except = $this->SelectParam($params, 'except');
 		$list_name = $this->SelectParam($params, 'list_name');
 		if (!$list_name) {
 			$list_name = $this->Application->Parser->GetParam('list_name');
 		}
 
 		return $types.$except.$list_name;
 	}
 
 	/**
 	 * Enter description here...
 	 *
 	 * @param Array $params
 	 * @return kDBList
 	 */
 	function &GetList($params)
 	{
 		$list_name = $this->SelectParam($params, 'list_name,name');
 		if (!$list_name) {
 			$list_name = $this->Application->Parser->GetParam('list_name');
 		}
 
 		$requery = isset($params['requery']) && $params['requery'];
 		if ($list_name && !$requery){
 			$names_mapping = $this->Application->GetVar('NamesToSpecialMapping');
 
 			$special = is_array($names_mapping) && isset($names_mapping[$this->Prefix]) && isset($names_mapping[$this->Prefix][$list_name]) ? $names_mapping[$this->Prefix][$list_name] : false;
 //			$special = getArrayValue($names_mapping, $this->Prefix, $list_name);
 			if(!$special)
 			{
 				$special = $this->BuildListSpecial($params);
 			}
 		}
 		else
 		{
 			$special = $this->BuildListSpecial($params);
 		}
 
 		$prefix_special = rtrim($this->Prefix.'.'.$special, '.');
 		$params['skip_counting'] = true;
 		$list =& $this->Application->recallObject( $prefix_special, $this->Prefix.'_List', $params);
 		/* @var $list kDBList */
 
 		if ($requery) {
 			$this->Application->HandleEvent($an_event, $prefix_special.':OnListBuild', $params);
 		}
 
 		if (array_key_exists('offset', $params)) {
 			$list->Offset += $params['offset']; // apply custom offset
 		}
 
 		$list->Query($requery);
 
 		if (array_key_exists('offset', $params)) {
 			$list->Offset -= $params['offset']; // remove custom offset
 		}
 
 		$this->Special = $special;
 
 		if ($list_name) {
 			$names_mapping[$this->Prefix][$list_name] = $special;
 			$this->Application->SetVar('NamesToSpecialMapping', $names_mapping);
 		}
 
 		return $list;
 	}
 
 	function ListMarker($params)
 	{
 		$list =& $this->GetList($params);
 		$ret = $list->getPrefixSpecial();
 		if( getArrayValue($params, 'as_preg') ) $ret = preg_quote($ret, '/');
 		return $ret;
 	}
 
 	/**
 	 * Prepares name for field with event in it (used only on front-end)
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function SubmitName($params)
 	{
 		$list =& $this->GetList($params);
 
 		$prefix_special = $list->getPrefixSpecial();
 
 		return 'events['.$prefix_special.']['.$params['event'].']';
 	}
 
 	/**
 	 * Prints list content using block specified
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function PrintList2($params)
 	{
 		$per_page = $this->SelectParam($params, 'per_page,max_items');
 		if ($per_page !== false) $params['per_page'] = $per_page;
 
 		$list =& $this->GetList($params);
 		$o = '';
 
 		$direction 	= (isset($params['direction']) && $params['direction']=="H")?"H":"V";
 		$columns	= (isset($params['columns'])) ? $params['columns'] : 1;
 
 		$id_field = (isset($params['id_field'])) ? $params['id_field'] : $this->Application->getUnitOption($this->Prefix, 'IDField');
 
 		if ($columns > 1 && $direction == 'V') {
 			$records_left = array_splice($list->Records, $list->SelectedCount); // because we have 1 more record for "More..." link detection (don't need to sort it)
 			$list->Records = $this->LinearToVertical($list->Records, $columns, $list->GetPerPage());
 			$list->Records = array_merge($list->Records, $records_left);
 		}
 
 		$list->GoFirst();
 
 		$block_params=$this->prepareTagParams($params);
 		$block_params['name'] = $this->SelectParam($params, 'render_as,block');
 		$block_params['pass_params'] = 'true';
 		$block_params['column_width'] = $params['column_width'] = 100 / $columns;
 		$block_start_row_params = $this->prepareTagParams($params);
 		$block_start_row_params['name'] = $this->SelectParam($params, 'row_start_render_as,block_row_start,row_start_block');
 
 		$block_end_row_params=$this->prepareTagParams($params);
 		$block_end_row_params['name'] = $this->SelectParam($params, 'row_end_render_as,block_row_end,row_end_block');
 
 		$block_empty_cell_params = $this->prepareTagParams($params);
 		$block_empty_cell_params['name'] = $this->SelectParam($params, 'empty_cell_render_as,block_empty_cell,empty_cell_block');
 
 		$i=0;
 
 		$backup_id=$this->Application->GetVar($this->Prefix."_id");
 		$displayed = array();
 		$column_number = 1;
 
 		$cache_mod_rw = $this->Application->getUnitOption($this->Prefix, 'CacheModRewrite') && $this->Application->RewriteURLs();
 		$limit = isset($params['limit']) ? $params['limit'] : false;
 
 		while (!$list->EOL() && (!$limit || $i<$limit))
 		{
 			$this->Application->SetVar( $this->getPrefixSpecial().'_id', $list->GetDBField($id_field) ); // for edit/delete links using GET
 			$this->Application->SetVar( $this->Prefix.'_id', $list->GetDBField($id_field) );
 			$block_params['is_last'] = ($i == $list->SelectedCount - 1);
 			$block_params['last_row'] = ($i + (($i+1) % $columns) >= $list->SelectedCount - 1);
 			$block_params['not_last'] = !$block_params['is_last']; // for front-end
 
 			if ($cache_mod_rw) {
 				if ($this->Prefix == 'c') {
 					// for listing subcategories in category
 					$this->Application->setCache('filenames', $this->Prefix.'_'.$list->GetDBField($id_field), $list->GetDBField('NamedParentPath'));
 					$this->Application->setCache('category_tree', $list->GetDBField($id_field), $list->GetDBField('TreeLeft') . ';' . $list->GetDBField('TreeRight'));
 				} else {
 					// for listing items in category
 					$this->Application->setCache('filenames', 'c_'.$list->GetDBField('CategoryId'), $list->GetDBField('CategoryFilename'));
 					$this->Application->setCache('filenames', $this->Prefix.'_'.$list->GetDBField($id_field), $list->GetDBField('Filename'));
 				}
 			}
 
 			if ($i % $columns == 0) {
 				// record in this iteration is first in row, then open row
 				$column_number = 1;
 				$o.= $block_start_row_params['name'] ?
 						$this->Application->ParseBlock($block_start_row_params, 1) :
 						(!isset($params['no_table']) ? '<tr>' : '');
 			}
 			else {
 				$column_number++;
 			}
 
 			$block_params['first_col'] = $column_number == 1 ? 1 : 0;
 			$block_params['last_col'] = $column_number == $columns ? 1 : 0;
 
 			$block_params['column_number'] = $column_number;
 			$block_params['num'] = ($i+1);
 
 			$this->PrepareListElementParams($list, $block_params); // new, no need to rewrite PrintList
 			$o.= $this->Application->ParseBlock($block_params, 1);
 			array_push($displayed, $list->GetDBField($id_field));
 
 			if($direction == 'V' && $list->SelectedCount % $columns > 0 && $column_number == ($columns - 1) && ceil(($i + 1) / $columns) > $list->SelectedCount % ceil($list->SelectedCount / $columns)) {
 				// if vertical output, then draw empty cells vertically, not horizontally
 				$o .= $block_empty_cell_params['name'] ? $this->Application->ParseBlock($block_empty_cell_params, 1) : '<td>&nbsp;</td>';
 				$i++;
 			}
 
 			if (($i + 1) % $columns == 0) {
 				// record in next iteration is first in row too, then close this row
 				$o.= $block_end_row_params['name'] ?
 						$this->Application->ParseBlock($block_end_row_params, 1) :
 						(!isset($params['no_table']) ? '</tr>' : '');
 			}
 
 			$list->GoNext();
 			$i++;
 		}
 
 		// append empty cells in place of missing cells in last row
 		while ($i % $columns != 0) {
 			// until next cell will be in new row append empty cells
 			$o .= $block_empty_cell_params['name'] ? $this->Application->ParseBlock($block_empty_cell_params, 1) : '<td>&nbsp;</td>';
 
 			if (($i+1) % $columns == 0) {
 				// record in next iteration is first in row too, then close this row
 				$o .= $block_end_row_params['name'] ? $this->Application->ParseBlock($block_end_row_params, 1) : '</tr>';
 			}
 			$i++;
 		}
 
 		$cur_displayed = $this->Application->GetVar($this->Prefix.'_displayed_ids');
 		if (!$cur_displayed) {
 			$cur_displayed = Array();
 		}
 		else {
 			$cur_displayed = explode(',', $cur_displayed);
 		}
 
 		$displayed = array_unique(array_merge($displayed, $cur_displayed));
 		$this->Application->SetVar($this->Prefix.'_displayed_ids', implode(',',$displayed));
 
 		$this->Application->SetVar( $this->Prefix.'_id', $backup_id);
 		$this->Application->SetVar( $this->getPrefixSpecial().'_id', '');
 
 		if (isset($params['more_link_render_as'])) {
 			$block_params = $params;
 			$params['render_as'] = $params['more_link_render_as'];
 			$o .= $this->MoreLink($params);
 		}
 
 		return $o;
 	}
 
 	/**
 	 * Allows to modify block params & current list record before PrintList parses record
 	 *
 	 * @param kDBList $object
 	 * @param Array $block_params
 	 */
 	function PrepareListElementParams(&$object, &$block_params)
 	{
 //		$fields_hash =& $object->getCurrentRecord();
 
 	}
 
 	function MoreLink($params)
 	{
 		$per_page = $this->SelectParam($params, 'per_page,max_items');
 		if ($per_page !== false) $params['per_page'] = $per_page;
 		$list =& $this->GetList($params);
 		if ($list->PerPage < $list->RecordsCount) {
 			$block_params = $this->prepareTagParams($params);
 			$block_params['name'] = $this->SelectParam($params, 'render_as,block');
 
 			return $this->Application->ParseBlock($block_params);
 		}
 	}
 
 	function NotLastItem($params)
 	{
 		$object =& $this->getList($params); // maybe we should use $this->GetList($params) instead
 		return ($object->CurrentIndex < min($object->PerPage == -1 ? $object->RecordsCount : $object->PerPage, $object->RecordsCount) - 1);
 	}
 
 	function PageLink($params)
 	{
 		$t = isset($params['template']) ? $params['template'] : '';
 		unset($params['template']);
 
 		if (!$t) $t = $this->Application->GetVar('t');
 
 		if (isset($params['page'])) {
 			$this->Application->SetVar($this->getPrefixSpecial().'_Page', $params['page']);
 			unset($params['page']);
 		}
 
 		if (!isset($params['pass'])) {
 			$params['pass'] = 'm,'.$this->getPrefixSpecial();
 		}
 
 		return $this->Application->HREF($t, '', $params);
 	}
 
 	function ColumnWidth($params)
 	{
 		$columns = $this->Application->Parser->GetParam('columns');
 		return round(100/$columns).'%';
 	}
 
 	/**
 	 * Append prefix and special to tag
 	 * params (get them from tagname) like
 	 * they were really passed as params
 	 *
 	 * @param Array $tag_params
 	 * @return Array
 	 * @access protected
 	 */
 	function prepareTagParams($tag_params = Array())
 	{
 		/*if (isset($tag_params['list_name'])) {
 			$list =& $this->GetList($tag_params);
 			$this->Init($list->Prefix, $list->Special);
 		}*/
 
 		$ret = $tag_params;
 		$ret['Prefix'] = $this->Prefix;
 		$ret['Special'] = $this->Special;
 		$ret['PrefixSpecial'] = $this->getPrefixSpecial();
 		return $ret;
 	}
 
 	function GetISO($currency)
 	{
 		if ($currency == 'selected') {
 			$iso = $this->Application->RecallVar('curr_iso');
 		}
 		elseif ($currency == 'primary' || $currency == '') {
 			$iso = $this->Application->GetPrimaryCurrency();
 		}
 		else { //explicit currency
 			$iso = $currency;
 		}
 		return $iso;
 	}
 
 	function ConvertCurrency($value, $iso)
 	{
 		$converter =& $this->Application->recallObject('kCurrencyRates');
 		// convery primary currency to selected (if they are the same, converter will just return)
 		$value = $converter->Convert($value, 'PRIMARY', $iso);
 		return $value;
 	}
 
 	function AddCurrencySymbol($value, $iso)
 	{
 		$currency =& $this->Application->recallObject('curr.-'.$iso, null, Array('skip_autoload' => true));
 		if( !$currency->isLoaded() ) $currency->Load($iso, 'ISO');
 
 		$symbol = $currency->GetDBField('Symbol');
 		if (!$symbol) $symbol = $currency->GetDBField('ISO').'&nbsp;';
 		if ($currency->GetDBField('SymbolPosition') == 0) {
 			$value = $symbol.$value;
 		}
 		if ($currency->GetDBField('SymbolPosition') == 1) {
 			$value = $value.$symbol;
 		}
 		return $value;
 	}
 
 	/**
 	 * Get's requested field value
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function Field($params)
 	{
 		$field = $this->SelectParam($params, 'name,field');
 
 		if( !$this->Application->IsAdmin() ) $params['no_special'] = 'no_special';
 
 		$object =& $this->getObject($params);
 
 		if ( $this->HasParam($params, 'db')  )
 		{
 			$value = $object->GetDBField($field);
 		}
 		else
 		{
 			if( $this->HasParam($params, 'currency') )
 			{
 				$iso = $this->GetISO($params['currency']);
 				$original = $object->GetDBField($field);
 				$value = $this->ConvertCurrency($original, $iso);
 				$object->SetDBField($field, $value);
 				$object->Fields[$field]['converted'] = true;
 			}
 
 			$format = getArrayValue($params, 'format');
 			if (!$format || $format == '$format') {
 				$format = null;
 			}
 
 			$value = $object->GetField($field, $format);
 
 			if( $this->SelectParam($params, 'negative') )
 			{
 				if(strpos($value, '-') === 0)
 				{
 					$value = substr($value, 1);
 				}
 				else
 				{
 					$value = '-'.$value;
 				}
 			}
 
 			if( $this->HasParam($params, 'currency') )
 			{
 				$value = $this->AddCurrencySymbol($value, $iso);
 				$params['no_special'] = 1;
 			}
 		}
 
 		if( !$this->HasParam($params, 'no_special') ) $value = htmlspecialchars($value);
 		if( getArrayValue($params,'checked'	) ) $value = ($value == ( isset($params['value']) ? $params['value'] : 1)) ? 'checked' : '';
 		if( isset($params['plus_or_as_label']) ) {
 			$value = substr($value, 0,1) == '+' ? substr($value, 1) : $this->Application->Phrase($value);
 		}
 		elseif( isset($params['as_label']) && $params['as_label']  ) $value = $this->Application->Phrase($value);
 
 		$first_chars = $this->SelectParam($params,'first_chars,cut_first');
 		if($first_chars)
 		{
 			$needs_cut = mb_strlen($value) > $first_chars;
 			$value = mb_substr($value, 0, $first_chars);
 			if ($needs_cut) $value .= ' ...';
 		}
 		if( getArrayValue($params,'nl2br'	) ) $value = nl2br($value);
 
 		if ($value != '') $this->Application->Parser->DataExists = true;
 
 		if( $this->HasParam($params, 'currency') )
 		{
 			//restoring value in original currency, for other Field tags to work properly
 			$object->SetDBField($field, $original);
 		}
 
 		return $value;
 	}
 
 	function SetField($params)
 	{
 		// <inp2:SetField field="Value" src=p:cust_{$custom_name}"/>
 
 		$object =& $this->getObject($params);
 		$dst_field = $this->SelectParam($params, 'name,field');
 
 		list($prefix_special, $src_field) = explode(':', $params['src']);
 		$src_object =& $this->Application->recallObject($prefix_special);
 		$object->SetDBField($dst_field, $src_object->GetDBField($src_field));
 	}
 
 	/**
 	 * Checks if parameter is passed
 	 * Note: works like Tag and line simple method too
 	 *
 	 * @param Array $params
 	 * @param string $param_name
 	 * @return bool
 	 */
 	function HasParam($params, $param_name = null)
 	{
 		if( !isset($param_name) )
 		{
 			$param_name = $this->SelectParam($params, 'name');
 			$params = $this->Application->Parser->Params;
 		}
 		$value = isset($params[$param_name]) ? $params[$param_name] : false;
 		return $value && ($value != '$'.$param_name);
 	}
 
 	function PhraseField($params)
 	{
 		$field_label = $this->Field($params);
 		$translation = $this->Application->Phrase( $field_label );
 		return $translation;
 	}
 
 	function Error($params)
 	{
 		$field = $this->SelectParam($params, 'name,field');
 		$object =& $this->getObject($params);
 		$msg = $object->GetErrorMsg($field, false);
 		return $msg;
 	}
 
 	function HasError($params)
 	{
 		if ($params['field'] == 'any')
 		{
 			$object =& $this->getObject($params);
 
 			$skip_fields = getArrayValue($params, 'except');
 			$skip_fields = $skip_fields ? explode(',', $skip_fields) : Array();
 
 			return $object->HasErrors($skip_fields);
 		}
 		else
 		{
 			$fields = $this->SelectParam($params, 'field,fields');
 			$fields = explode(',', $fields);
 			$res = false;
 			foreach($fields as $field)
 			{
 				$params['field'] = $field;
 				$res = $res || ($this->Error($params) != '');
 			}
 			return $res;
 		}
 	}
 
 	function ErrorWarning($params)
 	{
 		if (!isset($params['field'])) {
 			$params['field'] = 'any';
 		}
 		if ($this->HasError($params)) {
 			$params['prefix'] = $this->getPrefixSpecial();
 			return $this->Application->ParseBlock($params);
 		}
 	}
 
 	function IsRequired($params)
 	{
 		$field = $params['field'];
 		$object =& $this->getObject($params);;
 
 		$formatter_class = getArrayValue($object->Fields, $field, 'formatter');
 		if ($formatter_class == 'kMultiLanguage')
 		{
 			$formatter =& $this->Application->recallObject($formatter_class);
 			$field = $formatter->LangFieldName($field);
 		}
 
 		$options = $object->GetFieldOptions($field);
 		return getArrayValue($options,'required');
 	}
 
 	function FieldOption($params)
 	{
 		$object =& $this->getObject($params);;
 		$options = $object->GetFieldOptions($params['field']);
 		$ret =  isset($options[$params['option']]) ? $options[$params['option']] : '';
 		if (isset($params['as_label']) && $params['as_label']) $ret = $this->Application->ReplaceLanguageTags($ret);
 		return $ret;
 	}
 
 	function PredefinedOptions($params)
 	{
 		$object =& $this->getObject($params);
 
 		$field = $params['field'];
 		$value = array_key_exists('value', $params) ? $params['value'] : $object->GetDBField($field);
 		$field_options = $object->GetFieldOptions($field);
 		if (!array_key_exists('options', $field_options) || !is_array($field_options['options'])) {
 			trigger_error('Options not defined for <strong>'.$object->Prefix.'</strong> field <strong>'.$field.'</strong>', E_USER_WARNING);
 			return '';
 		}
 
 		$options = $field_options['options'];
 
 		if ($this->HasParam($params, 'has_empty')) {
 			$empty_value = array_key_exists('empty_value', $params) ? $params['empty_value'] : '';
 			$options = array_merge_recursive2(Array ($empty_value => ''), $options); // don't use other array merge function, because they will reset keys !!!
 		}
 
 		$block_params = $this->prepareTagParams($params);
 		$block_params['name'] = $this->SelectParam($params, 'render_as,block');
 		$block_params['pass_params'] = 'true';
 		if (method_exists($object, 'EOL') && count($object->Records) == 0) {
 			// for drawing grid column filter
 			$block_params['field_name'] = '';
 		}
 		else {
 			$block_params['field_name'] = $this->InputName($params); // depricated (produces warning when used as grid filter), but used in Front-End (submission create), admin (submission view)
 		}
 
 		$selected_param_name = getArrayValue($params, 'selected_param');
 		if (!$selected_param_name) {
 			$selected_param_name = $params['selected'];
 		}
 		$selected = $params['selected'];
 
 		$o = '';
 		if ($this->HasParam($params, 'no_empty') && !getArrayValue($options, '')) {
 			// removes empty option, when present (needed?)
 			array_shift($options);
 		}
 
 		if (strpos($value, '|') !== false) {
 			// multiple checkboxes OR multiselect
 			$value = explode('|', substr($value, 1, -1) );
 			foreach ($options as $key => $val) {
 				$block_params['key'] = $key;
 				$block_params['option'] = $val;
 				$block_params[$selected_param_name] = ( in_array($key, $value) ? ' '.$selected : '');
 				$o .= $this->Application->ParseBlock($block_params, 1);
 			}
 		}
 		else {
 			// single selection radio OR checkboxes OR dropdown
 			foreach ($options as $key => $val) {
 				$block_params['key'] = $key;
 				$block_params['option'] = $val;
 				$block_params[$selected_param_name] = (strlen($key) == strlen($value) && ($key == $value) ? ' '.$selected : '');
 				$o .= $this->Application->ParseBlock($block_params, 1);
 			}
 		}
 		return $o;
 	}
 
 	function PredefinedSearchOptions($params)
 	{
 		$object =& $this->getObject($params);
 		/* @var $object kDBList */
 
 		$params['value'] = $this->SearchField($params);
 
 		return $this->PredefinedOptions($params);
 	}
 
 	function Format($params)
 	{
 		$field = $this->SelectParam($params, 'name,field');
 		$object =& $this->getObject($params);
 
 		$options = $object->GetFieldOptions($field);
 
 		$format = $options[ $this->SelectParam($params, 'input_format') ? 'input_format' : 'format' ];
 
 		$formatter_class = getArrayValue($options,'formatter');
 		if ($formatter_class) {
 			$formatter =& $this->Application->recallObject($formatter_class);
 			$human_format = getArrayValue($params,'human');
 			$edit_size = getArrayValue($params,'edit_size');
 			$sample = getArrayValue($params,'sample');
 			if($sample)
 			{
 				return $formatter->GetSample($field, $options, $object);
 			}
 			elseif($human_format || $edit_size)
 			{
 				$format = $formatter->HumanFormat($format);
 				return $edit_size ? strlen($format) : $format;
 			}
 		}
 
 		return $format;
 	}
 
 	/**
 	 * Returns grid padination information
 	 * Can return links to pages
 	 *
 	 * @param Array $params
 	 * @return mixed
 	 */
 	function PageInfo($params)
 	{
 		$object =& $this->GetList($params);
 		/* @var $object kDBList */
 
 		$type = $params['type'];
 		unset($params['type']); // remove parameters used only by current tag
 
 		$ret = '';
 		switch ($type) {
 			case 'current':
 				$ret = $object->Page;
 				break;
 
 			case 'total':
 				$ret = $object->GetTotalPages();
 				break;
 
 			case 'prev':
 				$ret = $object->Page > 1 ? $object->Page - 1 : false;
 				break;
 
 			case 'next':
 				$ret = $object->Page < $object->GetTotalPages() ? $object->Page + 1 : false;
 				break;
 		}
 
 		if ($ret && isset($params['as_link']) && $params['as_link']) {
 			unset($params['as_link']); // remove parameters used only by current tag
 			$params['page']	= $ret;
 			$current_page = $object->Page; // backup current page
 			$ret = $this->PageLink($params);
 			$this->Application->SetVar($object->getPrefixSpecial().'_Page', $current_page); // restore page
 		}
 
 		return $ret;
 	}
 
 	/**
 	 * Print grid pagination using
 	 * block names specified
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function PrintPages($params)
 	{
 		$list =& $this->GetList($params);
 		$prefix_special = $list->getPrefixSpecial();
 		$total_pages = $list->GetTotalPages();
 
 		if ($total_pages > 1) $this->Application->Parser->DataExists = true;
 
 		if($total_pages == 0) $total_pages = 1; // display 1st page as selected in case if we have no pages at all
 		$o = '';
 
 		// what are these 2 lines for?
 		$this->Application->SetVar($prefix_special.'_event','');
 		$this->Application->SetVar($prefix_special.'_id','');
 
 		$current_page = $list->Page; //  $this->Application->RecallVar($prefix_special.'_Page');
 
 		$block_params = $this->prepareTagParams($params);
 
 		$split = ( isset($params['split'] ) ? $params['split'] : 10 );
 
 		$split_start = $current_page - ceil($split/2);
 		if ($split_start < 1){
 			$split_start = 1;
 		}
 		$split_end = $split_start + $split-1;
 
 		if ($split_end > $total_pages) {
 			$split_end = $total_pages;
 			$split_start = max($split_end - $split + 1, 1);
 		}
 
 		if ($current_page > 1){
 			$prev_block_params = $this->prepareTagParams();
 
 			if ($total_pages > $split){
 				$prev_block_params['page'] = max($current_page-$split, 1);
 				$prev_block_params['name'] = $this->SelectParam($params, 'prev_page_split_render_as,prev_page_split_block');
 				if ($prev_block_params['name']){
 					$o .= $this->Application->ParseBlock($prev_block_params, 1);
 				}
 			}
 
 			$prev_block_params['name'] = 'page';
 			$prev_block_params['page'] = $current_page-1;
 			$prev_block_params['name'] = $this->SelectParam($params, 'prev_page_render_as,block_prev_page,prev_page_block');
 			if ($prev_block_params['name']) {
 				$this->Application->SetVar($this->getPrefixSpecial().'_Page', $current_page-1);
 				$o .= $this->Application->ParseBlock($prev_block_params, 1);
 			}
 		}
 		else {
 			if ( $no_prev_page_block = $this->SelectParam($params, 'no_prev_page_render_as,block_no_prev_page') ) {
 				$block_params['name'] = $no_prev_page_block;
 				$o .= $this->Application->ParseBlock($block_params, 1);
 			}
 		}
 
 		$separator_params['name'] = $this->SelectParam($params, 'separator_render_as,block_separator');
 		for ($i = $split_start; $i <= $split_end; $i++)
 		{
 			if ($i == $current_page) {
 				$block = $this->SelectParam($params, 'current_render_as,active_render_as,block_current,active_block');
 			}
 			else {
 				$block = $this->SelectParam($params, 'link_render_as,inactive_render_as,block_link,inactive_block');
 			}
 
 			$block_params['name'] = $block;
 			$block_params['page'] = $i;
 			$this->Application->SetVar($this->getPrefixSpecial().'_Page', $i);
 			$o .= $this->Application->ParseBlock($block_params, 1);
 
 			if ($this->SelectParam($params, 'separator_render_as,block_separator')
 				&& $i < $split_end)
 			{
 				$o .= $this->Application->ParseBlock($separator_params, 1);
 			}
 		}
 
 		if ($current_page < $total_pages){
 			$next_block_params = $this->prepareTagParams();
 			$next_block_params['page']=$current_page+1;
 			$next_block_params['name'] = $this->SelectParam($params, 'next_page_render_as,block_next_page,next_page_block');
 			if ($next_block_params['name']){
 				$this->Application->SetVar($this->getPrefixSpecial().'_Page', $current_page+1);
 				$o .= $this->Application->ParseBlock($next_block_params, 1);
 			}
 			if ($total_pages > $split){
 				$next_block_params['page']=min($current_page+$split, $total_pages);
 				$next_block_params['name'] = $this->SelectParam($params, 'next_page_split_render_as,next_page_split_block');
 				if ($next_block_params['name']){
 					$o .= $this->Application->ParseBlock($next_block_params, 1);
 				}
 			}
 		}
 		else {
 			if ( $no_next_page_block = $this->SelectParam($params, 'no_next_page_render_as,block_no_next_page') ) {
 				$block_params['name'] = $no_next_page_block;
 				$o .= $this->Application->ParseBlock($block_params, 1);
 			}
 		}
 
 		$this->Application->SetVar($this->getPrefixSpecial().'_Page', $current_page);
 		return $o;
 	}
 
 	/**
 	 * Print grid pagination using
 	 * block names specified
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function PaginationBar($params)
 	{
 		return $this->PrintPages($params);
 	}
 
 
 	/**
 	 * Returns field name (processed by kMultiLanguage formatter
 	 * if required) and item's id from it's IDField or field required
 	 *
 	 * @param Array $params
 	 * @return Array (id,field)
 	 * @access private
 	 */
 	function prepareInputName($params)
 	{
 		$field = $this->SelectParam($params, 'name,field');
 		$object =& $this->getObject($params);
 
 		$formatter_class = getArrayValue($object->Fields, $field, 'formatter');
 		if ($formatter_class == 'kMultiLanguage') {
 			$formatter =& $this->Application->recallObject($formatter_class);
 			/* @var $formatter kMultiLanguage */
 
 			$force_primary = isset($object->Fields[$field]['force_primary']) && $object->Fields[$field]['force_primary'];
 			$field = $formatter->LangFieldName($field, $force_primary);
 		}
 
 		if (array_key_exists('force_id', $params)) {
 			$id = $params['force_id'];
 		}
 		else {
 			$id_field = getArrayValue($params, 'IdField');
 			$id = $id_field ? $object->GetDBField($id_field) : $object->GetID();
 		}
 
 		return Array($id, $field);
 	}
 
 
 	/**
 	 * Returns input field name to
 	 * be placed on form (for correct
 	 * event processing)
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function InputName($params)
 	{
 		list($id, $field) = $this->prepareInputName($params);
 
 		$ret = $this->getPrefixSpecial().'['.$id.']['.$field.']';
 		if( getArrayValue($params, 'as_preg') ) $ret = preg_quote($ret, '/');
 		return $ret;
 	}
 
 	/**
 	 * Allows to override various field options through hidden fields with specific names in submit.
 	 * This tag generates this special names
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @author Alex
 	 */
 	function FieldModifier($params)
 	{
 		list($id, $field) = $this->prepareInputName($params);
 
 		$ret = 'field_modifiers['.$this->getPrefixSpecial().']['.$field.']['.$params['type'].']';
 		if( getArrayValue($params, 'as_preg') ) $ret = preg_quote($ret, '/');
 
 		if (isset($params['value'])) {
 			$object =& $this->getObject($params);
 			$field_modifiers[$field][$params['type']] = $params['value'];
 			$object->ApplyFieldModifiers($field_modifiers);
 		}
 
 		return $ret;
 	}
 
 	/**
 	 * Returns index where 1st changable sorting field begins
 	 *
 	 * @return int
 	 * @access private
 	 */
 	function getUserSortIndex()
 	{
 		$list_sortings = $this->Application->getUnitOption($this->Prefix, 'ListSortings');
 		$sorting_prefix = getArrayValue($list_sortings, $this->Special) ? $this->Special : '';
 
 		$user_sorting_start = 0;
 		if ( $forced_sorting = getArrayValue($list_sortings, $sorting_prefix, 'ForcedSorting') ) {
 			$user_sorting_start = count($forced_sorting);
 		}
 		return $user_sorting_start;
 	}
 
 	/**
 	 * Returns order direction for given field
 	 *
 	 *
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function Order($params)
 	{
 		$field = $params['field'];
 		$user_sorting_start = $this->getUserSortIndex();
 
 		$list =& $this->GetList($params);
 
 		if ($list->GetOrderField($user_sorting_start) == $field)
 		{
 			return strtolower($list->GetOrderDirection($user_sorting_start));
 		}
 		elseif($this->Application->ConfigValue('UseDoubleSorting') && $list->GetOrderField($user_sorting_start+1) == $field)
 		{
 			return '2_'.strtolower($list->GetOrderDirection($user_sorting_start+1));
 		}
 		else
 		{
 			return 'no';
 		}
 	}
 
 	/**
 	 * Detects, that current sorting is not default
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function OrderChanged($params)
 	{
 		$list =& $this->GetList($params);
 		$user_sorting_start = $this->getUserSortIndex();
 
 		$sorting_configs = $this->Application->getUnitOption($this->Prefix, 'ConfigMapping', Array ());
 		$list_sortings = $this->Application->getUnitOption($this->Prefix, 'ListSortings', Array ());
 		$sorting_prefix = getArrayValue($list_sortings, $this->Special) ? $this->Special : '';
 
 		if (array_key_exists('DefaultSorting1Field', $sorting_configs)) {
 			$list_sortings[$sorting_prefix]['Sorting'] = Array (
 				$this->Application->ConfigValue($sorting_configs['DefaultSorting1Field']) => $this->Application->ConfigValue($sorting_configs['DefaultSorting1Dir']),
 				$this->Application->ConfigValue($sorting_configs['DefaultSorting2Field']) => $this->Application->ConfigValue($sorting_configs['DefaultSorting2Dir']),
 			);
 		}
 
 		$sorting = getArrayValue($list_sortings, $sorting_prefix, 'Sorting');
 		$sort_fields = is_array($sorting) ? array_keys($sorting) : Array ();
 
 		for ($order_number = 0; $order_number < 2; $order_number++) {
 			// currect sorting in list
 			$sorting_pos = $user_sorting_start + $order_number;
 			$current_order_field = $list->GetOrderField($sorting_pos, true);
 			$current_order_direction = $list->GetOrderDirection($sorting_pos, true);
 
 			if (!$current_order_field || !$current_order_direction) {
 				// no sorting defined for this sorting position
 				continue;
 			}
 
 			// user sorting found
 			if (array_key_exists($order_number, $sort_fields)) {
 				// default sorting found
 				$default_order_field = $sort_fields[$order_number];
 				$default_order_direction = $sorting[$default_order_field];
 
 				if ($current_order_field != $default_order_field || $current_order_direction != $default_order_direction) {
 					// #1. user sorting differs from default sorting -> changed
 					return true;
 				}
 			}
 			else {
 				// #2. user sorting + no default sorting -> changed
 				return true;
 			}
 		}
 
 		// #3. user sorting match default or not defined -> not changed
 		return false;
 	}
 
 	/**
 	 * Get's information of sorting field at "pos" position,
 	 * like sorting field name (type="field") or sorting direction (type="direction")
 	 *
 	 * @param Array $params
 	 * @return mixed
 	 */
 	function OrderInfo($params)
 	{
 		$user_sorting_start = $this->getUserSortIndex() + --$params['pos'];
 		$list =& $this->GetList($params);
 //		$object =& $this->Application->recallObject( $this->getPrefixSpecial() );
 
 		if($params['type'] == 'field') return $list->GetOrderField($user_sorting_start);
 		if($params['type'] == 'direction') return $list->GetOrderDirection($user_sorting_start);
 	}
 
 	/**
 	 * Checks if sorting field/direction matches passed field/direction parameter
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function IsOrder($params)
 	{
 		$params['type'] = isset($params['field']) ? 'field' : 'direction';
 		$value = $this->OrderInfo($params);
 
 		if( isset($params['field']) ) return $params['field'] == $value;
 		if( isset($params['direction']) ) return $params['direction'] == $value;
 	}
 
 	/**
 	 * Returns list perpage
 	 *
 	 * @param Array $params
 	 * @return int
 	 */
 	function PerPage($params)
 	{
 		$object =& $this->getObject($params);
 		return $object->PerPage;
 	}
 
 	/**
 	 * Checks if list perpage matches value specified
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function PerPageEquals($params)
 	{
 		$object =& $this->getObject($params);
 		return $object->PerPage == $params['value'];
 	}
 
 	function SaveEvent($params)
 	{
 		// SaveEvent is set during OnItemBuild, but we may need it before any other tag calls OnItemBuild
 		$object =& $this->getObject($params);
 		return $this->Application->GetVar($this->getPrefixSpecial().'_SaveEvent');
 	}
 
 	function NextId($params)
 	{
 		$object =& $this->getObject($params);
 
 		$wid = $this->Application->GetTopmostWid($this->Prefix);
 		$session_name = rtrim($this->getPrefixSpecial().'_selected_ids_'.$wid, '_');
 		$ids = explode(',', $this->Application->RecallVar($session_name));
 
 		$cur_id = $object->GetID();
 
 		$i = array_search($cur_id, $ids);
 		if ($i !== false) {
 			return $i < count($ids) - 1 ? $ids[$i + 1] : '';
 		}
 		return '';
 	}
 
 	function PrevId($params)
 	{
 		$object =& $this->getObject($params);
 
 		$wid = $this->Application->GetTopmostWid($this->Prefix);
 		$session_name = rtrim($this->getPrefixSpecial().'_selected_ids_'.$wid, '_');
 		$ids = explode(',', $this->Application->RecallVar($session_name));
 
 		$cur_id = $object->GetID();
 
 		$i = array_search($cur_id, $ids);
 		if ($i !== false) {
 			return $i > 0 ? $ids[$i - 1] : '';
 		}
 		return '';
 	}
 
 	function IsSingle($params)
 	{
 		return ($this->NextId($params) === '' && $this->PrevId($params) === '');
 	}
 
 	function IsLast($params)
 	{
 		return ($this->NextId($params) === '');
 	}
 
 	function IsFirst($params)
 	{
 		return ($this->PrevId($params) === '');
 	}
 
 	/**
 	 * Checks if field value is equal to proposed one
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function FieldEquals($params)
 	{
 		$object =& $this->getObject($params);
 		$ret = $object->GetDBField($this->SelectParam($params, 'name,field')) == $params['value'];
 //		if( getArrayValue($params,'inverse') ) $ret = !$ret;
 		return $ret;
 	}
 
 	/**
 	 * Checks, that grid has icons defined and they should be shown
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function UseItemIcons($params)
 	{
 		$grids = $this->Application->getUnitOption($this->Prefix, 'Grids');
 		return array_key_exists('Icons', $grids[ $params['grid'] ]);
 	}
 
 	/**
 	 * Returns corresponding to grid layout selector column width
 	 *
 	 * @param Array $params
 	 * @return int
 	 */
 	function GridSelectorColumnWidth($params)
 	{
 		$width = 0;
 		if ($params['selector']) {
 			$width += $params['selector_width'];
 		}
 
 		if ($this->UseItemIcons($params)) {
 			$width += $params['icon_width'];
 		}
 
 		return $width;
 	}
 
 	/**
 	 * Returns grids item selection mode (checkbox, radio, )
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function GridSelector($params)
 	{
 		$grids = $this->Application->getUnitOption($this->Prefix, 'Grids');
 
 		return array_key_exists('Selector', $grids[ $params['grid'] ]) ? $grids[ $params['grid'] ]['Selector'] : $params['default'];
 	}
 
 	function ItemIcon($params)
 	{
 		$object =& $this->getObject($params);
 
 		$grids = $this->Application->getUnitOption($this->Prefix,'Grids');
 		$icons =& $grids[ $params['grid'] ]['Icons'];
 
 		$key = '';
 		$status_fields = $this->Application->getUnitOption($this->Prefix,'StatusField');
 		if(!$status_fields) return $icons['default'];
 
 		foreach($status_fields as $status_field)
 		{
 			$key .= $object->GetDBField($status_field).'_';
 		}
 		$key = rtrim($key,'_');
 		$value = ($key !== false) ? $key : 'default';
 
 		return isset($icons[$value]) ? $icons[$value] : $icons['default'];
 	}
 
 	/**
 	 * Generates bluebar title + initializes prefixes used on page
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function SectionTitle($params)
 	{
 		$preset_name = replaceModuleSection($params['title_preset']);
 		$title_presets = $this->Application->getUnitOption($this->Prefix,'TitlePresets');
 		$title_info = getArrayValue($title_presets, $preset_name);
 		if ($title_info === false) {
 			$title = str_replace('#preset_name#', $preset_name, $params['title']);
 			if ($this->Application->ConfigValue('UseSmallHeader') && isset($params['group_title']) && $params['group_title']) {
 				$title .= ' - '.$params['group_title'];
 			}
 			return $title;
 		}
 
 		if (getArrayValue($title_presets,'default')) {
 			// use default labels + custom labels specified in preset used
 			$title_info = array_merge_recursive2($title_presets['default'], $title_info);
 		}
 
 		$title = $title_info['format'];
 
 		// 1. get objects in use for title construction
 		$objects = Array();
 		$object_status = Array();
 		$status_labels = Array();
 
 		$prefixes = getArrayValue($title_info,'prefixes');
 		$all_tag_params = getArrayValue($title_info,'tag_params');
 		if ($prefixes) {
 			// extract tag_perams passed directly to SectionTitle tag for specific prefix
 			foreach ($params as $tp_name => $tp_value) {
 				if (preg_match('/(.*)\[(.*)\]/', $tp_name, $regs)) {
 					$all_tag_params[ $regs[1] ][ $regs[2] ] = $tp_value;
 					unset($params[$tp_name]);
 				}
 			}
 
 			$tag_params = Array();
 			foreach ($prefixes as $prefix_special) {
 				$prefix_data = $this->Application->processPrefix($prefix_special);
 				$prefix_data['prefix_special'] = rtrim($prefix_data['prefix_special'],'.');
 
 				if ($all_tag_params) {
 					$tag_params = getArrayValue($all_tag_params, $prefix_data['prefix_special']);
 					if (!$tag_params) $tag_params = Array();
 				}
 
 				$tag_params = array_merge_recursive2($params, $tag_params);
 				$objects[ $prefix_data['prefix_special'] ] =& $this->Application->recallObject($prefix_data['prefix_special'], $prefix_data['prefix'], $tag_params);
 				$object_status[ $prefix_data['prefix_special'] ] = $objects[ $prefix_data['prefix_special'] ]->IsNewItem() ? 'new' : 'edit';
 
 				// a. set object's status field (adding item/editing item) for each object in title
 				if (getArrayValue($title_info[ $object_status[ $prefix_data['prefix_special'] ].'_status_labels' ],$prefix_data['prefix_special'])) {
 					$status_labels[ $prefix_data['prefix_special'] ] = $title_info[ $object_status[ $prefix_data['prefix_special'] ].'_status_labels' ][ $prefix_data['prefix_special'] ];
 					$title = str_replace('#'.$prefix_data['prefix_special'].'_status#', $status_labels[ $prefix_data['prefix_special'] ], $title);
 				}
 
 				// b. setting object's titlefield value (in titlebar ONLY) to default in case if object beeing created with no titlefield filled in
 				if ($object_status[ $prefix_data['prefix_special'] ] == 'new') {
 					$new_value = $this->getInfo( $objects[ $prefix_data['prefix_special'] ], 'titlefield' );
 					if(!$new_value && getArrayValue($title_info['new_titlefield'],$prefix_data['prefix_special']) ) $new_value = $this->Application->Phrase($title_info['new_titlefield'][ $prefix_data['prefix_special'] ]);
 					$title = str_replace('#'.$prefix_data['prefix_special'].'_titlefield#', $new_value, $title);
 				}
 			}
 		}
 
 		// replace to section title
 		$section = array_key_exists('section', $params) ? $params['section'] : false;
 		if ($section) {
 			$sections_helper =& $this->Application->recallObject('SectionsHelper');
 			/* @var $sections_helper kSectionsHelper */
 
 			$section_data =& $sections_helper->getSectionData($section);
 			$title = str_replace('#section_label#', '!' . $section_data['label'] . '!', $title);
 		}
 
 		// 2. replace phrases if any found in format string
 		$title = $this->Application->ReplaceLanguageTags($title, false);
 
 		// 3. find and replace any replacement vars
 		preg_match_all('/#(.*_.*)#/Uis',$title,$rets);
 		if ($rets[1]) {
 			$replacement_vars = array_keys( array_flip($rets[1]) );
 			foreach ($replacement_vars as $replacement_var) {
 				$var_info = explode('_',$replacement_var,2);
 				$object =& $objects[ $var_info[0] ];
 				$new_value = $this->getInfo($object,$var_info[1]);
 				$title = str_replace('#'.$replacement_var.'#', $new_value, $title);
 			}
 		}
 
 		// replace trailing spaces inside title preset + '' occurences into single space
 		$title = preg_replace('/[ ]*\'\'[ ]*/', ' ', $title);
 
 		if ($this->Application->ConfigValue('UseSmallHeader') && isset($params['group_title']) && $params['group_title']) {
 			$title .= ' - '.$params['group_title'];
 		}
 
 		$cut_first = getArrayValue($params, 'cut_first');
 		if ($cut_first && mb_strlen($title) > $cut_first) {
 			if (!preg_match('/<a href="(.*)">(.*)<\/a>/',$title)) {
 				$title = mb_substr($title, 0, $cut_first).' ...';
 			}
 		}
 
 		return $title;
 	}
 
 	function getInfo(&$object, $info_type)
 	{
 		switch ($info_type)
 		{
 			case 'titlefield':
 				$field = $this->Application->getUnitOption($object->Prefix,'TitleField');
 				return $field !== false ? $object->GetField($field) : 'TitleField Missing';
 				break;
 
 			case 'recordcount':
 				$of_phrase = $this->Application->Phrase('la_of');
 				return $object->NoFilterCount != $object->RecordsCount ? $object->RecordsCount.' '.$of_phrase.' '.$object->NoFilterCount : $object->RecordsCount;
 				break;
 
 			default:
 				return $object->GetField($info_type);
 				break;
 		}
 	}
 
 	function GridInfo($params)
 	{
 		$object =& $this->GetList($params);
 		/* @var $object kDBList */
 
 		switch ($params['type']) {
 			case 'filtered':
 				return $object->GetRecordsCount();
 			case 'total':
 				return $object->GetNoFilterCount();
 			case 'from':
 				return $object->RecordsCount ? $object->Offset+1 : 0; //0-based
 			case 'to':
 				return $object->PerPage > 0 ? min($object->Offset + $object->PerPage, $object->RecordsCount) : $object->RecordsCount;
 			case 'total_pages':
 				return $object->GetTotalPages();
 			case 'needs_pagination':
 				return ($object->PerPage != -1) && (($object->RecordsCount > $object->PerPage) || ($object->Page > 1));
 		}
 	}
 
 	/**
 	 * Parses block depending on its element type.
 	 * For radio and select elements values are taken from 'value_list_field' in key1=value1,key2=value2
 	 * format. key=value can be substituted by <SQL>SELECT f1 AS OptionName, f2 AS OptionValue... FROM <PREFIX>TableName </SQL>
 	 * where prefix is TABLE_PREFIX
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function ConfigFormElement($params)
 	{
 		$object =& $this->getObject($params);
 		$field = $params['field'];
 
 		$helper =& $this->Application->recallObject('InpCustomFieldsHelper');
 		/* @var $helper InpCustomFieldsHelper */
 
 		$element_type = $object->GetDBField($params['element_type_field']);
 
 		if($element_type == 'label') $element_type = 'text';
 		$params['name'] = $params['blocks_prefix'].$element_type;
 
 		switch ($element_type) {
 			case 'select':
 			case 'multiselect':
 			case 'radio':
 				$field_options = $object->GetFieldOptions($field, 'options');
 
 				if ($object->GetDBField('DirectOptions')) {
 					// used for custom fields
 					$field_options['options'] = $object->GetDBField('DirectOptions');
 				}
 				else {
 					// used for configuration
 					$field_options['options'] = $helper->GetValuesHash($object->GetDBField($params['value_list_field']), ',');
 				}
 
 				$object->SetFieldOptions($field, $field_options);
 				break;
 
 			case 'text':
 			case 'textarea':
 				$params['field_params'] = $helper->ParseConfigSQL($object->GetDBField($params['value_list_field']));
 				break;
 
 			case 'password':
 			case 'checkbox':
 			default:
 				break;
 		}
 		return $this->Application->ParseBlock($params, 1);
 	}
 
 	/**
 	 * Get's requested custom field value
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 */
 	function CustomField($params)
 	{
 		$params['name'] = 'cust_'.$this->SelectParam($params, 'name,field');
 		return $this->Field($params);
 	}
 
 	function CustomFieldLabel($params)
 	{
 		$object =& $this->getObject($params);
 
 		$field = $this->SelectParam($params, 'name,field');
 
 		$sql = 'SELECT FieldLabel
 				FROM '.$this->Application->getUnitOption('cf', 'TableName').'
 				WHERE FieldName = '.$this->Conn->qstr($field);
 		return $this->Application->Phrase($this->Conn->GetOne($sql));
 	}
 
 	/**
 	 * transposes 1-dimensional array elements for vertical alignment according to given columns and per_page parameters
 	 *
 	 * @param array $arr
 	 * @param int $columns
 	 * @param int $per_page
 	 * @return array
 	 */
 	function LinearToVertical(&$arr, $columns, $per_page)
 	{
 		$rows = $columns;
 		// in case if after applying per_page limit record count less then
 		// can fill requrested column count, then fill as much as we can
 		$cols = min(ceil($per_page / $columns), ceil(count($arr) / $columns));
 		$imatrix = array();
 		for ($row = 0; $row < $rows; $row++) {
 			for ($col = 0; $col < $cols; $col++) {
 				$source_index = $row * $cols + $col;
 				if (!isset($arr[$source_index])) {
 					// in case if source array element count is less then element count in one row
 					continue;
 				}
 				$imatrix[$col * $rows + $row] = $arr[$source_index];
 			}
 		}
 
 		ksort($imatrix);
 		return array_values($imatrix);
 	}
 
 	/**
 	 * If data was modfied & is in TempTables mode, then parse block with name passed;
 	 * remove modification mark if not in TempTables mode
 	 *
 	 * @param Array $params
 	 * @return string
 	 * @access public
 	 * @author Alexey
 	 */
 	function SaveWarning($params)
 	{
 		$main_prefix = getArrayValue($params, 'main_prefix');
 		if ($main_prefix && $main_prefix != '$main_prefix') {
 			$top_prefix = $main_prefix;
 		}
 		else {
 			$top_prefix = $this->Application->GetTopmostPrefix($this->Prefix);
 		}
 
 		$temp_tables = substr($this->Application->GetVar($top_prefix.'_mode'), 0, 1) == 't';
 		$modified = $this->Application->RecallVar($top_prefix.'_modified');
 
 		if ($temp_tables && $modified) {
 			$block_params = $this->prepareTagParams($params);
 			$block_params['name'] = $this->SelectParam($params, 'render_as,name');
 			$block_params['edit_mode'] = $temp_tables ? 1 : 0;
 			return $this->Application->ParseBlock($block_params);
 		}
 		$this->Application->RemoveVar($top_prefix.'_modified');
 		return '';
 	}
 
 	/**
 	 * Returns list record count queries (on all pages)
 	 *
 	 * @param Array $params
 	 * @return int
 	 */
 	function TotalRecords($params)
 	{
 		$list =& $this->GetList($params);
 		if (!$list->Counted) $list->CountRecs();
 		return $list->RecordsCount;
 	}
 
 	/**
 	 * Range filter field name
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function SearchInputName($params)
 	{
 		$field = $this->SelectParam($params, 'field,name');
 
 		$ret = 'custom_filters['.$this->getPrefixSpecial().']['.$params['grid'].']['.$field.']['.$params['filter_type'].']';
 
 		if (isset($params['type'])) {
 			$ret .= '['.$params['type'].']';
 		}
 
 		return $ret;
 	}
 
 	/**
 	 * Return range filter field value
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function SearchField($params) // RangeValue
 	{
 		$field = $this->SelectParam($params, 'field,name');
 
 		$view_name = $this->Application->RecallVar($this->getPrefixSpecial().'_current_view');
 		$custom_filter = $this->Application->RecallPersistentVar($this->getPrefixSpecial().'_custom_filter.'.$view_name/*, ALLOW_DEFAULT_SETTINGS*/);
 		$custom_filter = $custom_filter ? unserialize($custom_filter) : Array();
 
 		if (isset($custom_filter[ $params['grid'] ][$field])) {
 			$ret = $custom_filter[ $params['grid'] ][$field][ $params['filter_type'] ]['submit_value'];
 			if (isset($params['type'])) {
 				$ret = $ret[ $params['type'] ];
 			}
 
 			if( !$this->HasParam($params, 'no_special') ) $ret = htmlspecialchars($ret);
 			return $ret;
 		}
 
 		return '';
 	}
 
 	function SearchFormat($params)
 	{
 		$field = $params['field'];
 		$object =& $this->GetList($params);
 
 		$options = $object->GetFieldOptions($field);
 
 		$format = $options[ $this->SelectParam($params, 'input_format') ? 'input_format' : 'format' ];
 
 		$formatter_class = getArrayValue($options,'formatter');
 		if($formatter_class)
 		{
 			$formatter =& $this->Application->recallObject($formatter_class);
 			$human_format = getArrayValue($params,'human');
 			$edit_size = getArrayValue($params,'edit_size');
 			$sample = getArrayValue($params,'sample');
 			if($sample)
 			{
 				return $formatter->GetSample($field, $options, $object);
 			}
 			elseif($human_format || $edit_size)
 			{
 				$format = $formatter->HumanFormat($format);
 				return $edit_size ? strlen($format) : $format;
 			}
 		}
 
 		return $format;
 	}
 
 	/**
 	 * Returns error of range field
 	 *
 	 * @param unknown_type $params
 	 * @return unknown
 	 */
 	function SearchError($params)
 	{
 		$field = $this->SelectParam($params, 'field,name');
 
 		$error_var_name = $this->getPrefixSpecial().'_'.$field.'_error';
 		$pseudo = $this->Application->RecallVar($error_var_name);
 		if ($pseudo) {
 			$this->Application->RemoveVar($error_var_name);
 		}
 
 		$object =& $this->Application->recallObject($this->Prefix.'.'.$this->Special.'-item', null, Array('skip_autoload' => true));
 		/* @var $object kDBItem */
 
 		$object->SetError($field, $pseudo);
 		return $object->GetErrorMsg($field, 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/';
 	}
 
 	/**
 	 * Returns object used in tag processor
 	 *
 	 * @access public
 	 * @return kDBBase
 	 */
 	function &getObject($params = Array())
 	{
 		$object =& $this->Application->recallObject($this->getPrefixSpecial(), $this->Prefix, $params);
 		if (isset($params['requery']) && $params['requery']) {
 			$this->Application->HandleEvent($q_event, $this->getPrefixSpecial().':LoadItem', $params);
 		}
 		return $object;
 	}
 
 	/**
 	 * Checks if object propery value matches value passed
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function PropertyEquals($params)
 	{
 		$object =& $this->getObject($params);
 		$property_name = $this->SelectParam($params, 'name,var,property');
 		return $object->$property_name == $params['value'];
 	}
 
 	/**
 	 * Group list records by header, saves internal order in group
 	 *
 	 * @param Array $records
 	 * @param string $heading_field
 	 */
 	function groupRecords(&$records, $heading_field)
 	{
 		$sorted = Array();
 		$i = 0; $record_count = count($records);
 		while ($i < $record_count) {
 			$sorted[ $records[$i][$heading_field] ][] = $records[$i];
 			$i++;
 		}
 
 		$records = Array();
 		foreach ($sorted as $heading => $heading_records) {
 			$records = array_merge_recursive($records, $heading_records);
 		}
 	}
 
 	function DisplayOriginal($params)
 	{
 		return false;
 	}
 
 	function MultipleEditing($params)
 	{
 		$wid = $this->Application->GetTopmostWid($this->Prefix);
 		$session_name = rtrim($this->getPrefixSpecial().'_selected_ids_'.$wid, '_');
 		$selected_ids = explode(',', $this->Application->RecallVar($session_name));
 
 		$ret = '';
 		if ($selected_ids) {
 			$selected_ids = explode(',', $selected_ids);
 			$object =& $this->getObject( array_merge_recursive2($params, Array('skip_autoload' => true)) );
 			$params['name'] = $params['render_as'];
 			foreach ($selected_ids as $id) {
 				$object->Load($id);
 				$ret .= $this->Application->ParseBlock($params);
 			}
 		}
 
 		return $ret;
 	}
 
 	/**
 	 * Returns import/export process percent
 	 *
 	 * @param Array $params
 	 * @return int
 	 * @deprecated Please convert to event-model, not tag based
 	 */
 	function ExportStatus($params)
 	{
 		$export_object =& $this->Application->recallObject('CatItemExportHelper');
 
 		$event = new kEvent($this->getPrefixSpecial().':OnDummy');
 
 		$action_method = 'perform'.ucfirst($this->Special);
 		$field_values = $export_object->$action_method($event);
 
 		// finish code is done from JS now
 		if ($field_values['start_from'] >= $field_values['total_records'])
 		{
 			if ($this->Special == 'import') {
 				// this is used?
 				$this->Application->StoreVar('PermCache_UpdateRequired', 1);
 				$this->Application->Redirect('categories/cache_updater', Array('m_opener' => 'r', 'pass' => 'm', 'continue' => 1, 'no_amp' => 1));
 			}
 			elseif ($this->Special == 'export') {
 				// used for orders export in In-Commerce
 				$finish_t = $this->Application->RecallVar('export_finish_t');
 				$this->Application->Redirect($finish_t, Array('pass' => 'all'));
 				$this->Application->RemoveVar('export_finish_t');
 			}
 		}
 
 		$export_options = $export_object->loadOptions($event);
 		return $export_options['start_from']  * 100 / $export_options['total_records'];
 	}
 
 	/**
 	 * Returns path where exported category items should be saved
 	 *
 	 * @param Array $params
 	 */
 	function ExportPath($params)
 	{
 		$ret = EXPORT_PATH.'/';
 
 		if( getArrayValue($params, 'as_url') )
 		{
 			$ret = str_replace( FULL_PATH.'/', $this->Application->BaseURL(), $ret);
 		}
 
 		$export_options = unserialize($this->Application->RecallVar($this->getPrefixSpecial().'_options'));
 		$ret .= $export_options['ExportFilename'].'.'.($export_options['ExportFormat'] == 1 ? 'csv' : 'xml');
 
 		return $ret;
 	}
 
 	function FieldTotal($params)
 	{
 		$list =& $this->GetList($params);
 
 		return $list->GetFormattedTotal($this->SelectParam($params, 'field,name'), $params['function']);
 	}
 
-	function SetFCKDefaultLanguage()
+	/**
+	 * Returns FCKEditor locale, that matches default site language
+	 *
+	 * @return string
+	 */
+	function _getFCKLanguage()
 	{
-		$lang_id = $this->Application->GetDefaultLanguageId();
-		$sql="SELECT Locale FROM ".TABLE_PREFIX."Language WHERE LanguageId = ".$lang_id;
-		$lang_prefix = strtolower($this->Conn->GetOne($sql));
-		$lang_file=strtolower($this->Conn->GetOne($sql)).'.js';
-		if (file_exists(FULL_PATH.EDITOR_PATH.'/editor/lang/'.$lang_file))
-		{
-			return $lang_prefix;
-		}
-		$aLangPrefix = explode("-",$lang_prefix);
-		if (file_exists(FULL_PATH.EDITOR_PATH.'/editor/lang/'.$aLangPrefix[0].'.js'))
-		{
-			return $aLangPrefix[0];
+		static $language_code = null;
+
+		if (!isset($language_code)) {
+			$language_code = 'en'; // defaut value
+
+			$sql = 'SELECT Locale
+					FROM '. $this->Application->getUnitOption('lang', 'TableName') . '
+					WHERE LanguageId = ' . $this->Application->GetDefaultLanguageId(); // $this->Application->GetVar('m_lang');
+			$locale = strtolower( $this->Conn->GetOne($sql) );
+
+			if (file_exists(FULL_PATH . EDITOR_PATH . 'editor/lang/' . $locale . '.js')) {
+				// found language file, that exactly matches locale name (e.g. "en")
+				$language_code = $locale;
+			}
+			else {
+				$locale = explode('-', $locale);
+				if (file_exists(FULL_PATH . EDITOR_PATH . 'editor/lang/' . $locale[0] . '.js')) {
+					// language file matches first part of locale (e.g. "ru-RU")
+					$language_code = $locale[0];
+				}
+			}
 		}
-		return 'en';
+
+		return $language_code;
 	}
 
 
 	function FCKEditor($params)
 	{
 		$params['no_special'] = 1;
 		$params['format'] = array_key_exists('format', $params) ? $params['format'] . ';fck_ready' : 'fck_ready';
 		$value = $this->Field($params);
 		$name = array_key_exists('name', $params) ? $params['name'] : $this->InputName($params);
 
 		$theme_path = substr($this->Application->GetFrontThemePath(), 1) . '/inc/';
 		if (!file_exists(FULL_PATH . '/' . $theme_path . 'style.css')) {
 			$theme_path = EDITOR_PATH;
 		}
 
 		$styles_xml = $this->Application->BaseURL() . $theme_path . 'styles.xml';
 		$styles_css = $this->Application->BaseURL() . $theme_path . 'style.css';
 
 		$bgcolor = array_key_exists('bgcolor', $params) ? $params['bgcolor'] : $this->Application->GetVar('bgcolor');
 		if (!$bgcolor) {
 			$bgcolor = '#ffffff';
 		}
 
 		$preview_url = '';
 		$page_id = $this->Application->GetVar('c_id');
 		$content_id = $this->Application->GetVar('content_id');
 		if ($page_id && $content_id) {
 			// editing content block from Front-End, not category in admin
 			$sql = 'SELECT NamedParentPath
 					FROM ' . $this->Application->getUnitOption('c', 'TableName') . '
 					WHERE ' . $this->Application->getUnitOption('c', 'IDField') . ' = ' . $page_id;
 			$template = strtolower( $this->Conn->GetOne($sql) );
 
 			$url_params = Array ('m_cat_id' => $page_id, 'no_amp' => 1, 'editing_mode' => EDITING_MODE_CMS, 'pass' => 'm');
 			$preview_url = $this->Application->HREF($template, '_FRONT_END_', $url_params, 'index.php');
 			$preview_url = preg_replace('/&(admin|editing_mode)=[\d]/', '', $preview_url);
 		}
 
 		include_once(FULL_PATH . EDITOR_PATH . 'fckeditor.php');
 
 		$oFCKeditor = new FCKeditor($name);
 		$oFCKeditor->FullUrl    = $this->Application->BaseURL();
 		$oFCKeditor->BaseUrl    = BASE_PATH . '/';
 		$oFCKeditor->BasePath	= BASE_PATH . EDITOR_PATH;
 		$oFCKeditor->Width		= $params['width'] ;
 		$oFCKeditor->Height		= $params['height'] ;
 		$oFCKeditor->ToolbarSet	= $page_id && $content_id ? 'Advanced' : 'Default';
 		$oFCKeditor->Value		= $value;
 		$oFCKeditor->PreviewUrl	= $preview_url;
-		$oFCKeditor->DefaultLanguage = $this->SetFCKDefaultLanguage();
+		$oFCKeditor->DefaultLanguage = $this->_getFCKLanguage();
 		$oFCKeditor->LateLoad = array_key_exists('late_load', $params) && $params['late_load'];
 		$oFCKeditor->Config = Array (
 			//'UserFilesPath' => $pathtoroot.'kernel/user_files',
 			'ProjectPath' => BASE_PATH . '/',
 			'CustomConfigurationsPath' => $this->Application->BaseURL() . 'core/admin_templates/js/inp_fckconfig.js',
 			'StylesXmlPath' => $styles_xml,
 			'EditorAreaCSS' => $styles_css,
 			'DefaultStyleLabel' => $this->Application->Phrase('la_editor_default_style'),
 //				'Debug' => 1,
 			'Admin' => 1,
 			'K4' => 1,
 			'newBgColor' => $bgcolor,
 			'PreviewUrl' => $preview_url,
 			'BaseUrl' => BASE_PATH . '/',
-			'DefaultLanguage' => $this->SetFCKDefaultLanguage(),
+			'DefaultLanguage' => $this->_getFCKLanguage(),
 			'EditorAreaStyles' => 'body { background-color: '.$bgcolor.' }',
 		);
 
 		return $oFCKeditor->CreateHtml();
 	}
 
 	function IsNewItem($params)
 	{
 		$object =& $this->getObject($params);
 		return $object->IsNewItem();
 	}
 
 	/**
 	 * Creates link to an item including only it's id
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function ItemLink($params)
 	{
 		$object =& $this->getObject($params);
 
 		if (!isset($params['pass'])) {
 			$params['pass'] = 'm';
 		}
 
 		$params[$object->getPrefixSpecial().'_id'] = $object->GetID();
 
 		$m =& $this->Application->recallObject('m_TagProcessor');
 		return $m->t($params);
 	}
 
 	/**
 	 * Calls OnNew event from template, when no other event submitted
 	 *
 	 * @param Array $params
 	 */
 	function PresetFormFields($params)
 	{
 		$prefix = $this->getPrefixSpecial();
 		if (!$this->Application->GetVar($prefix.'_event')) {
 			$this->Application->HandleEvent(new kEvent($prefix.':OnNew'));
 		}
 	}
 
 	function PrintSerializedFields($params)
 	{
 		$object =& $this->getObject();
 		$field = $this->SelectParam($params, 'field');
 		$data = unserialize($object->GetDBField($field));
 		$o = '';
 		$std_params['name'] = $params['render_as'];
 		$std_params['field'] = $params['field'];
 		$std_params['pass_params'] = true;
 		foreach ($data as $key => $row) {
 			$block_params = array_merge($std_params, $row, array('key'=>$key));
 			$o .= $this->Application->ParseBlock($block_params);
 		}
 		return $o;
 	}
 	/**
 	 * Checks if current prefix is main item
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function IsTopmostPrefix($params)
 	{
 		return $this->Prefix == $this->Application->GetTopmostPrefix($this->Prefix);
 	}
 
 	function PermSection($params)
 	{
 		$section = $this->SelectParam($params, 'section,name');
 		$perm_sections = $this->Application->getUnitOption($this->Prefix, 'PermSection');
 		return isset($perm_sections[$section]) ? $perm_sections[$section] : '';
 	}
 
 	function PerPageSelected($params)
 	{
 		$list =& $this->GetList($params);
 		return $list->PerPage == $params['per_page'] ? $params['selected'] : '';
 	}
 
 	/**
 	 * Returns prefix + generated sepcial + any word
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function VarName($params)
 	{
 		$list =& $this->GetList($params);
 
 		return $list->getPrefixSpecial().'_'.$params['type'];
 	}
 
 	/**
 	 * Returns edit tabs by specified preset name or false in case of error
 	 *
 	 * @param string $preset_name
 	 * @return mixed
 	 */
 	function getEditTabs($preset_name)
 	{
 		$presets = $this->Application->getUnitOption($this->Prefix, 'EditTabPresets');
 
 		if (!$presets || !isset($presets[$preset_name]) || count($presets[$preset_name]) == 0) {
 			return false;
 		}
 
 		return count($presets[$preset_name]) > 1 ? $presets[$preset_name] : false;
 	}
 
 	/**
 	 * Detects if specified preset has tabs in it
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function HasEditTabs($params)
 	{
 		return $this->getEditTabs($params['preset_name']) ? true : false;
 	}
 
 	/**
 	 * Sorts edit tabs based on their priority
 	 *
 	 * @param Array $tab_a
 	 * @param Array $tab_b
 	 * @return int
 	 */
 	function sortEditTabs($tab_a, $tab_b)
 	{
 		if ($tab_a['priority'] == $tab_b['priority']) {
 			return 0;
 		}
 
 		return $tab_a['priority'] < $tab_b['priority'] ? -1 : 1;
 	}
 
 	/**
 	 * Prints edit tabs based on preset name specified
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function PrintEditTabs($params)
 	{
 		$edit_tabs = $this->getEditTabs($params['preset_name']);
 		if (!$edit_tabs) {
 			return ;
 		}
 		usort($edit_tabs, Array (&$this, 'sortEditTabs'));
 
 		$ret = '';
 		$block_params = $this->prepareTagParams($params);
 		$block_params['name'] = $params['render_as'];
 
 		foreach ($edit_tabs as $tab_info) {
 			$block_params['title'] = $tab_info['title'];
 			$block_params['template'] = $tab_info['t'];
 			$ret .= $this->Application->ParseBlock($block_params);
 		}
 
 		return $ret;
 	}
 
 	/**
 	 * Performs image resize to required dimensions and returns resulting url (cached resized image)
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function ImageSrc($params)
 	{
 		$max_width = isset($params['MaxWidth']) ? $params['MaxWidth'] : false;
 		$max_height = isset($params['MaxHeight']) ? $params['MaxHeight'] : false;
 
 		$logo_filename = isset($params['LogoFilename']) ? $params['LogoFilename'] : false;
 		$logo_h_margin = isset($params['LogoHMargin']) ? $params['LogoHMargin'] : false;
 		$logo_v_margin = isset($params['LogoVMargin']) ? $params['LogoVMargin'] : false;
 		$object =& $this->getObject($params);
 
 		$field = $this->SelectParam($params, 'name,field');
 		return $object->GetField($field, 'resize:'.$max_width.'x'.$max_height.';wm:'.$logo_filename.'|'.$logo_h_margin.'|'.$logo_v_margin);
 	}
 
 	/**
 	 * Allows to retrieve given setting from unit config
 	 *
 	 * @param Array $params
 	 * @return mixed
 	 */
 	function UnitOption($params)
 	{
 		return $this->Application->getUnitOption($this->Prefix, $params['name']);
 	}
 
 	/**
 	 * Returns list of allowed toolbar buttons or false, when all is allowed
 	 *
 	 * @param Array $params
 	 * @return string
 	 */
 	function VisibleToolbarButtons($params)
 	{
 		$preset_name = replaceModuleSection($params['title_preset']);
 		$title_presets = $this->Application->getUnitOption($this->Prefix, 'TitlePresets');
 
 		if (!array_key_exists($preset_name, $title_presets)) {
 			trigger_error('Title preset not specified or missing (in tag "<strong>' . $this->getPrefixSpecial() . ':' . __METHOD__ . '</strong>")', E_USER_WARNING);
 			return false;
 		}
 
 		$preset_info = $title_presets[$preset_name];
 		if (!array_key_exists('toolbar_buttons', $preset_info) || !is_array($preset_info['toolbar_buttons'])) {
 			return false;
 		}
 
 		// always add search buttons
 		array_push($preset_info['toolbar_buttons'], 'search', 'search_reset_alt');
 		$toolbar_buttons = array_map('addslashes', $preset_info['toolbar_buttons']);
 
 		return $toolbar_buttons ? "'" . implode("', '", $toolbar_buttons) . "'" : 'false';
 	}
 
 	/**
 	 * Checks, that "To" part of at least one of range filters is used
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function RangeFiltersUsed($params)
 	{
 		$search_helper =& $this->Application->recallObject('SearchHelper');
 		/* @var $search_helper kSearchHelper */
 
 		return $search_helper->rangeFiltersUsed($this->getPrefixSpecial(), $params['grid']);
 	}
 
 	/**
 	 * This is abstract tag, used to modify unit config data based on template, where it's used.
 	 * Tag is called from "combined_header" block in admin only.
 	 *
 	 * @param Array $params
 	 */
 	function ModifyUnitConfig($params)
 	{
 
 	}
 
 	/**
 	 * Checks, that field is visible on edit form
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function FieldVisible($params)
 	{
 		$check_field = $params['field'];
 		$fields = $this->Application->getUnitOption($this->Prefix, 'Fields');
 
 		if (!array_key_exists($check_field, $fields)) {
 			// field not found in real fields array -> it's 100% virtual then
 			$fields = $this->Application->getUnitOption($this->Prefix, 'VirtualFields');
 		}
 
 		if (!array_key_exists($check_field, $fields)) {
 			$params['field'] = 'Password';
 			return $check_field == 'VerifyPassword' ? $this->FieldVisible($params) : true;
 		}
 
 		$show_mode = array_key_exists('show_mode', $fields[$check_field]) ? $fields[$check_field]['show_mode'] : true;
 
 		if ($show_mode === smDEBUG) {
 			return defined('DEBUG_MODE') && DEBUG_MODE;
 		}
 
 		return $show_mode;
 	}
 
 	/**
 	 * Checks, that there area visible fields in given section on edit form
 	 *
 	 * @param Array $params
 	 * @return bool
 	 */
 	function FieldsVisible($params)
 	{
 		if (!$params['fields']) {
 			return true;
 		}
 
 		$check_fields = explode(',', $params['fields']);
 		$fields = $this->Application->getUnitOption($this->Prefix, 'Fields');
 		$virtual_fields = $this->Application->getUnitOption($this->Prefix, 'VirtualFields');
 
 		foreach ($check_fields as $check_field) {
 			// when at least one field in subsection is visible, then subsection is visible too
 
 			if (array_key_exists($check_field, $fields)) {
 				$show_mode = array_key_exists('show_mode', $fields[$check_field]) ? $fields[$check_field]['show_mode'] : true;
 			}
 			else {
 				$show_mode = array_key_exists('show_mode', $virtual_fields[$check_field]) ? $virtual_fields[$check_field]['show_mode'] : true;
 			}
 
 			if (($show_mode === true) || (($show_mode === smDEBUG) && (defined('DEBUG_MODE') && DEBUG_MODE))) {
 				// field is visible
 				return true;
 			}
 		}
 
 		return false;
 	}
 }
 
 ?>
\ No newline at end of file