/**
* Форма поиска
*
* @version 4.1
* Правила встраивания поисковой формы на HTML-страницу:

Для доступа к возможностям поисковой формы на странице надо прописать ссылку для загрузки
данного скрипта, вот так:

<script src="http://exat.ru/touronline/scripts/4/common.js" charset="Windows-1251"></script>

Ссылка для загрузки скрипта может располагаться в любом месте страницы,
но ДО вызова конструктора объекта ExatSearchForm.

После закрытия тега </form> нужно создать объект ExatSearchForm
и вызвать его метод initForm().

Все элементы управления на поисковой форме необязательны, но если в ней
встретятся элементы управления с префиксом из имени формы, сконкатенированным
с одним из зарезервированных id, то методы объекта ExatSearchForm
будут соответствующим образом манипулировать их содержимым.

Теоретически на странице может быть несколько поисковых форм, но они должны быть
с разными id, и для каждой должен быть создан свой экземпляр объекта ExatSearchForm.

Пример:

<script src="http://exat.ru/touronline/scripts/4/common.js" charset="Windows-1251"></script>
<form id="exat" method="post">
...
</form>
<script>
var esf = new ExatSearchForm('exat', '3v234564563')
esf.initForm()
</script>
*/


/** Конструктор класса ExatSearchForm.
 * @access public
 * @param formId   - значение атрибута id тега form, для которого конструируется
 *   объект. Загрузка HTML-текста формы в момент конструирования объекта необязательна.
 * @param clientId - зашифрованный идентификатор клиентских настроек
 * @param defaults - необязательный объект, значения по умолчанию для параметров
 *   поиска, которые будут использованы при отсутствии свойств параметра values
 *   метода initForm,либо при сбросе после ошибки. Поддерживаемые свойства:
 *   departureId       - код точки отправления. По умолчанию 64(Москва).
 *   tourTypeIds       - коды туров через запятую. По умолчанию - все типы туров.
 *   countryId         - код страны. По умолчанию 0 (не выбрана).
 *   countryFilter		 - id групп стран через запятую.
 *   countryIncTrans   - значение галочки "только с вкл. перелётом": 0=не зависит от страны,
 *     1=зависит от страны. По умолчанию 1.
 *   resortIds         - коды курортов через запятую. По умолчанию - все курорты.
 *   minDate           - дата тура "от" в формате "DD.MM.YYYY".
 *     Пустая строка (не путать с null или undefined) = без ограничений.
 *   minDateOffset     - смещение в днях от текущей даты для даты тура "от".
 *     По умолчанию - неделя вперёд от текущей даты. Игнорируется при наличии minDate.
 *   maxDate           - дата тура "до" в формате "DD.MM.YYYY".
 *     Пустая строка (не путать с null или undefined) = без ограничений.
 *   maxDateOffset     - смещение в днях от текущей даты для даты тура "до".
 *     По умолчанию - две недели вперёд от текущей даты. Игнорируется при наличии maxDate.
 *   minDuration       - длительность тура "от" в днях. По умолчанию - 8 дней (неделя). 0=[все]
 *   maxDuration       - длительность тура "до" в днях. По умолчанию - 8 дней (неделя). 0=[все]
 *   minNightsDuration       - длительность тура "от" в ночях. По умолчанию - 7 ночей (неделя). 0=[все]
 *   maxNightsDuration       - длительность тура "до" в ночях. По умолчанию - 7 ночей (неделя). 0=[все]
 *   categoryIds       - коды категорий отелей через запятую. По умолчанию - все категории.
 *   hotelIds          - коды отелей через запятую. По умолчанию - все отели (ограничены только категориями).
 *   minAmount         - цена "от" в валюте currencyId.
 *   maxAmount         - цена "до" в валюте currencyId.
 *   currencyId        - код валюты. По умолчанию - доллары, если для страны нет своей валюты по умолчанию.
 *   foodTypeIds       - коды типов питания через запятую. По умолчанию - все типы питания.
 *   serviceIds        - коды услуг через запятую. По умолчанию - все услуги.
 *   accommodation     - размещение в виде строки ВЗР_РЕБ
 *   show123Acc        - 0 или 1: отображать ли размещение 1/2/3 взрослых
 *     в списке доступных размещений, если есть DBL. По умолчанию 1.
 *   ages              - возраста детей через запятую
 *   transportRequired - 0 или 1: искать ли только туры с включённым перелётом.
 *     По умолчанию 1, но зависит от countryIncTrans
 *   resortFilter      - 0 или 1, поиск маршрутов только по выбранным курортам/странам, и ни по каким другим.
 *   resultType				 - 'tours' или 'hotels': в каком виде будут представлены результаты поиска -- в виде списка туров или списка отелей.
 * дополнительные поля, только для профессиональной версии:
 *   tourOperatorIds   - коды туроператоров через запятую. По умолчанию - все "предпочтительные" туроператоры.
 *   includeStop       - 0 или 1: показывать ли остановленные продажи. По умолчанию 0.
 *   limit       - количество строк в странице результатов. По умолчанию 20.
 *   showTourCount     - битовая маска, управляющая показом числа туров в опциях списков выбора (1 -- отправление, 2 -- страна, 4 -- курорт, 8 -- отель). По умолчанию 0.
 *	 resortDepth			 - глубина отображения дерева курортов (1 -- показывать только подкурорты страны первого уровня, напр. Болгария / Банско)
 * @param host - необязательный параметр, указывающий имя HTTP-хоста, с которого будут подгружаться данные.
 *   По умолчанию равен "http://exat.ru"
 * @param params - необязательный параметр (ассоциативный массив).
 *   params[newWindowParams] - свойства нового окна (2-ой аргумент метода window.open)
 *     По умолчанию равен "resizable=yes, scrollbars=yes"
 *   params[alertLocks] - блокировка уведомлений об ошибках
 */
var allCountryText;
function ExatSearchForm(formId, clientId, defaults, host, params)
{
	this.clientId = clientId;
	this.formId = formId;
	this.host = (typeof(host)=='undefined') ? "http://exat.ru" : host;
	this.params = (typeof(params)=='undefined') ? { newWindowParams : 'resizable=yes, scrollbars=yes' } : params;
	window.exatForms[formId] = this;

	// константы

	this.ONE_DAY_MS = 1000 * 3600 * 24; //количество миллисекунд в сутках
	this.DEF_HOURS  = 4;
	this.MAX_TOUR_DAYS     = 22; // максимальное количество дней для генерации из суточных цен

	//специальные константы для случаев, когда ничего не выбрано
	this.ALL_TOUR_TYPES     = 0xffffffff;
	this.ALL_CATEGORIES     = 0xffffffff;
	this.ALL_FOOD_TYPES     = 0xffffffff;
	this.ALL_ACCOMMODATIONS = 0xffffffff;
	this.MAX_AMOUNT         = 999999999;

	this.ACC_TEXT = new Array( '1 / 2 / 3 взр',
		'1 взр',  '2 взр',  '3 взр',  '4 взр', '5 взр',  '6 взр',  '7 взр',  '8 взр',
		'9 взр', '10 взр', '11 взр', '12 взр','13 взр', '14 взр', '15 взр', '16 и более взр',
		'1 взр + 1 реб', '1 взр + 2 реб', '1 взр + 3 реб', '1 взр + 4 и более детей',
		'2 взр + 1 реб', '2 взр + 2 реб', '2 взр + 3 реб', '2 взр + 4 и более детей',
		'3 взр + 1 реб', '3 взр + 2 реб', '3 взр + 3 реб', '3 взр + 4 и более детей',
		'4 и более взр + 1 реб', '4 и более взр + 2 реб', '4 и более взр + 3 реб', '4 и более взр + 4 и более детей'
	);

	this.ACC_VAL = new Array(0,
		'1_0', '2_0', '3_0', '4_0', '5_0', '6_0', '7_0', '8_0',
		'9_0','10_0','11_0','12_0','13_0','14_0','15_0','16_0',
		'1_1', '1_2', '1_3', '1_4', '2_1', '2_2', '2_3', '2_4',
		'3_1', '3_2', '3_3', '3_4', '4_1', '4_2', '4_3', '4_4');


	this.CAT_TEXT    = new Array('[все]', '5*', '4*', '3*', '2*', '1*', 'HV-1', 'HV-2', 'без кат.');
	this.CAT_VAL     = new Array(this.ALL_CATEGORIES, '5', '4', '3', '2', '1', '17', '16', '0');
	this.CAT_NEW_VAL = new Array(this.ALL_CATEGORIES, '11,10', '9,8', '7,6', '5,4', '3,2', '17', '16', '0');

	this.departureData    = null; //ассоциативный массив: код точки отправления=>Array(название,маска доступных типов туров, Array(код страны, ...))
	this.tourTypeData     = null; //ассоциативный массив: код типа тура=>название типа тура
	this.countryData      = null; //ассоциативный массив: код страны=>Array(название страны, маска типов туров)
	this.foodTypeData     = null; //ассоциативный массив: код типа питания=>название типа питания
	this.currencyData     = null; //ассоциативный массив: код валюты=>название валюты
	this.servicesData     = null; //ассоциативный массив: код услуги=>Array()
	this.tourOperatorData = null; //ассоциативный массив: код туроператора=>название туроператора
	this.resortData       = [];   //ассоциативный массив: 'x'+код точки отправления+'-'+код страны => Array()

	/* Идентификаторы элементов управления внутри формы,
	 * которыми умеет манипулировать ExatSearchForm
	 * Предполагается, что на странице перед каждым идентификатором
	 * будет префикс в виде идентификатора формы
	 *
	 * Элементы управления профессиональной версии (отображение стопов, технической информации,
	 * переключатель старого/нового вида результатов поиска) здесь не отражены,
	 * для них обработчики надо прописывать явно
	 */
	this.controls = [
		{name:'DepartureCtrl', onchange:1},
		{name:'TourTypeCtrl', onchange:1},
		{name:'CountryCtrl', onchange:1},
		{name:'CountryFilterCtrl', onchange:1},
		{name:'ResortCtrl', onchange:1},
		{name:'MinDateCtrl', onchange:1},
		{name:'MaxDateCtrl', onchange:1},
		{name:'MinDurationCtrl', onchange:1},
		{name:'MaxDurationCtrl', onchange:1},
		{name:'MinNightsDurationCtrl', onchange:1},
		{name:'MaxNightsDurationCtrl', onchange:1},
		{name:'MinAmountCtrl', onchange:1},
		{name:'MaxAmountCtrl', onchange:1},
		{name:'CurrencyCtrl', onchange:1},
		{name:'CategoryCtrl', onchange:1},
		{name:'HotelCtrl', onchange:1},
		{name:'FoodTypeCtrl', onchange:1},
		{name:'AccommodationCtrl', onchange:1},
		{name:'AgeCtrl', onchange:1},
		{name:'ServiceCtrl', onchange:1},
		{name:'TourOperatorCtrl', onchange:1},
		{name:'TransportRequiredCtrl', onclick:1},
		{name:'ResortFilterCtrl', onchange:1},
		{name:'LimitCtrl', onchange:1},
		{name:'ResultTypeCtrl', onchange:1},
		{name:'SubmitCtrl', onclick:1},
		{name:'ResetCtrl', onclick:1}
	];

	this.initTimeout = 0; //сброс таймера начальной инициализации для initForm
	this.resortException = false; //специальный случай комбинации страна/тип тура/точка отправления, по которой нет туров
	this.nextNewWindowName = this.generateNewWindowName(); //заранее определяем имя нового окна для тестирования
 	this.prefTourOperators = ''; //список предпочтительных туроператоров, действующий, когда выбран пункт "все"

	//предусмотрим вариант отсутствия аргумента values совсем
	this.defaults = (typeof(defaults)=='undefined' || defaults==null) ? {} : defaults;
	var htmlDefaults=window[this.formId + 'Defaults'];
	if(htmlDefaults)
		this.defaults=htmlDefaults;

	if(this.defaults.minNightsDuration==null)
		if(this.defaults.minDuration==null)
			this.defaults.minNightsDuration = 8;
		else
			this.defaults.minNightsDuration = this.defaults.minDuration;
	if(this.defaults.maxNightsDuration==null)
		if(this.defaults.maxDuration==null)
			this.defaults.maxNightsDuration = 8;
		else
			this.defaults.maxNightsDuration = this.defaults.maxDuration;
	if(this.defaults.minDuration==null)       this.defaults.minDuration = 8;
	if(this.defaults.maxDuration==null)       this.defaults.maxDuration = 8;

	if(this.defaults.departureId==null)       this.defaults.departureId = 64;/* Москва */
	if(this.defaults.countryId==null)         this.defaults.countryId = x_from;
	if(this.defaults.countryFilter==null)      this.defaults.countryFilter = 0;
	if(this.defaults.countryIncTrans==null)   this.defaults.countryIncTrans = 1;
	if(this.defaults.minDateOffset==null)     this.defaults.minDateOffset = 7;
	if(this.defaults.maxDateOffset==null)     this.defaults.maxDateOffset = 21;
	if(this.defaults.minAmount==null)         this.defaults.minAmount = 0;
	if(this.defaults.maxAmount==null)         this.defaults.maxAmount = this.MAX_AMOUNT;
	if(this.defaults.currencyId==null)        this.defaults.currencyId = 'undefined'; /* not USD */
	if(this.defaults.accommodation==null)     this.defaults.accommodation = accomm;
	if(this.defaults.show123Acc==null)        this.defaults.show123Acc = 1;
	if(this.defaults.transportRequired==null) this.defaults.transportRequired = 1;
	if(this.defaults.resortFilter==null)      this.defaults.resortFilter = 0;
	if(this.defaults.includeStop==null)       this.defaults.includeStop = 0;
	if(this.defaults.showTechInfo==null)       this.defaults.showTechInfo = 0;
	if(this.defaults.showTourOperator==null)       this.defaults.showTourOperator = 0;
	if(this.defaults.limit==null)             this.defaults.limit = 20;
	if(this.defaults.showTourCount==null)			this.defaults.showTourCount = 0;
	if(this.defaults.resortDepth==null)				this.defaults.resortDepth = 1;
	if(this.defaults.resultType==null)				this.defaults.resultType = 'tours';
	
	
	//placeItemId[]
	
	//загрузка дополнительных скриптов в конце конструктора инициализации, иначе Opera выполняет сначала эти подгруженные скрипты, а потом уже остальную часть конструктора
	this.AutoRefreshTimeout = 720000; //Период автоматической перезагрузки данных формы во избежание устаревания
	this.loadPrefData();
  this.loadInitData();
}


ExatSearchForm.prototype.loadPrefData = function() {
	if(typeof(exatPrefData) == 'undefined') {
  	exatPrefData = [];
  }
	//если динамические настройки предпочтения ещё не загружены для предыдущей формы, загружаем
	if(typeof(exatPrefData[this.clientId]=='undefined')) {
		document.write('<script type="text/javascript" src="'+this.host+'/touronline/?jsapp=getpreference&ver=4&client_id='+this.clientId+'" charset="Windows-1251"></script>');
	}
}


ExatSearchForm.prototype.loadInitData = function() {
	// Последний выполненный запрос будет автоматически повторяться, чтобы данные не устаревали
	if (this.LoadResortTimeout != null) {
		clearTimeout(this.LoadResortTimeout);
	}
	if (this.LoadInitTimeout != null) {
		clearTimeout(this.LoadInitTimeout);
	}
	this.LoadInitTimeout = setTimeout('exatForms.' + this.formId + '.loadInitData()', this.AutoRefreshTimeout);

	//загрузим начальные общие справочники
	this.loadScript(this.host
		+ '/touronline/?jsapp=getjs&ver=4&file=data&form_id='
		+ this.formId
		+ '&showTourCount='
	  + this.defaults.showTourCount
		+ (this.clientId ? '&client_id=' + this.clientId : ''));
}


ExatSearchForm.prototype.getInitVal = function(name) {
	if(this.values!=undefined && this.values[name]!=null) {
		return this.values[name];
	}
	else {
		return this.defaults[name];
	}
}


ExatSearchForm.prototype.getInitArr = function(name) {
	var strIds='';
	if(this.values!=undefined && this.values[name]!=null) {
		if(this.values[name]=="")
			return [];
		else
			strIds=this.values[name];
	}
	else if(this.defaults!=undefined && this.defaults[name]!=null) {
		if(this.defaults[name]=="")
			return [];
		else
			strIds=this.defaults[name];
	}
	else {
		return [];
	}
	strIds=String(strIds);
	strIds=strIds.replace(/^,/,'');
	return strIds.split(",");
}

ExatSearchForm.prototype.array2hash = function(arraydata){
	var hashdata=new Array();
	for(var i=0; i<arraydata.length; i++){
		hashdata[arraydata[i]]=2;
	}
	return hashdata;
}

/** Инициализация всех элементов управления формы.
 * @access public
 * @param values - необязательный ассоциативный массив данных инициализации формы.
 *  См. описание параметра defaults конструктора
 */
ExatSearchForm.prototype.initForm = function(values)
{
	// запомним значения, на случай, если придётся откладывать initForm по таймауту
	if(typeof(values)!='undefined' && values!=null) {
		this.values = values;
	}
	var reason = '';
	if(typeof(exatPrefData)=='undefined' || typeof(exatPrefData[this.clientId])=='undefined') {
		reason = "не загружены предпочтения клиента с client_id=" + this.clientId;
	}
	else if(this.tourOperatorData == null) {
		reason = "не загружены начальные данные (data.js)";
	}

	if (reason!='') {
		if(this.initTimeout >= 150) {
			throw new Error('Не удалось инициализировать поисковую форму в течении 30 сек.' +
				' Причина: ' + reason +
				'. Попробуйте перезагрузить страницу (удерживая клавишу Ctrl, нажмите F5).' +
				' В случае повторного появления ошибки ' +
				'обратитесь в службу технической поддержки');
			return;
		}
		else {
			this.initTimeout++;
			setTimeout('window.exatForms[\''+this.formId+'\'].initForm()', 200);
			return;
		}
	}

	this.form = document.getElementById(this.formId);
	if(!this.form) {
		this.reportError('Форма с id="'+this.formId+'" не найдена');
		return;
	}

	// запрет сабмита по нажатие Enter в текстовом поле формы, так как в этом случае не запускается обработчик
	this.form.onsubmit=function(){return false;};

	this.departureId = this.getInitVal('departureId');
	this.countryId = this.getInitVal('countryId');

	this.resortIds = [];
	var ids = this.getInitArr('resortId');
	for(var i=0; i<ids.length; ++i) {
		this.resortIds[Number(ids[i])] = true;
	}

	this.tourTypeMask = 0;
	var ids = this.getInitArr('tourTypeIds');
	for(i=0; i<ids.length; ++i) {
		this.tourTypeMask |= ids[i];
	}
	if(!this.tourTypeMask) {
		this.tourTypeMask=this.ALL_TOUR_TYPES;
	}

	var dNow = new Date();
	dNow.setHours(this.DEF_HOURS);
	dNow.setMinutes(0);
	dNow.setSeconds(0);
	dNow.setMilliseconds(0);

	var minDate = this.getInitVal('minDate');
	if(minDate == null) {
		this.minTimestamp = Number(dNow.getTime()
			+ this.ONE_DAY_MS * this.getInitVal('minDateOffset'));
	}
	else if(minDate == ''){
		this.minTimestamp = 0;
	}
	else {
		// у нас граница суток считается в 4 часа ночи, что бы не было проблем со сдвигом времени
		this.minTimestamp = exatToTime(minDate)+this.DEF_HOURS*1000*3600;
	}

	var maxDate = this.getInitVal('maxDate');
	if(maxDate == null) {
		this.maxTimestamp = Number(dNow.getTime()
			+ this.ONE_DAY_MS * this.getInitVal('maxDateOffset'));
	}
	else if(maxDate == ''){
		this.maxTimestamp = 0;
	}
	else {
		this.maxTimestamp = exatToTime(maxDate) +this.DEF_HOURS*1000*3600;
	}

	this.minDuration = Number(this.getInitVal('minDuration'));
	this.maxDuration = Number(this.getInitVal('maxDuration'));
	// можно было бы обойтись this.minDuration, но в будующем это могут стать разные параметры
	this.minNightsDuration = Number(this.getInitVal('minNightsDuration'));
	this.maxNightsDuration = Number(this.getInitVal('maxNightsDuration'));
	this.minAmount = Number(this.getInitVal('minAmount'));
	this.maxAmount = Number(this.getInitVal('maxAmount'));

	this.foodTypeMask = 0;
	var ids = this.getInitArr('foodTypeIds');
	for(var i = 0; i < ids.length; ++i) {
		this.foodTypeMask |= 1<<(ids[i]-1);
	}
	if(!this.foodTypeMask) {
		this.foodTypeMask=this.ALL_FOOD_TYPES;
	}

	this.categoryMask = 0;
	var ids = this.getInitArr('categoryIds');
	for(var i = 0; i < ids.length; ++i) {
		this.categoryMask |= 1<<ids[i];
	}
	if(!this.categoryMask) {
		this.categoryMask=this.ALL_CATEGORIES;
	}

	this.hotelIds = this.array2hash(this.getInitArr('hotelIds'));
	this.serviceIds = this.array2hash(this.getInitArr('serviceIds'));
	this.tourOperatorDefIds = this.array2hash(this.getInitArr('tourOperatorIds'));
	this.show123Acc = this.getInitVal('show123Acc');

	this.accommodationId = 0;
	var acc = this.getInitVal('accommodation');
	if(acc!=0 && acc.indexOf('_')==-1)
		acc=acc+'_0';
	for(i = 0; i < this.ACC_VAL.length; ++i) {
		if(acc == this.ACC_VAL[i]) {
			this.accommodationId = i;
			break;
		}
	}
	this.ages			   = this.getInitVal('ages');

	this.transportRequired = this.getInitVal('transportRequired');
	this.countryIncTrans   = this.getInitVal('countryIncTrans');
	var countryFilter      = this.getInitArr('countryFilter');
	this.countryFilter = [];
	for (var cfi = 0; cfi < countryFilter.length; cfi++) {
		if (countryFilter[cfi] != 0) {
			this.countryFilter.push(countryFilter[cfi]);
		}
	}
	this.resortFilter      = this.getInitVal('resortFilter');
	this.includeStop       = this.getInitVal('includeStop');
	this.showTechInfo       = this.getInitVal('showTechInfo');
	this.showTourOperator       = this.getInitVal('showTourOperator');
	this.limit             = this.getInitVal('limit');
	this.showTourCount     = this.getInitVal('showTourCount');
	this.resortDepth			 = this.getInitVal('resortDepth');
	this.resultType			 = this.getInitVal('resultType');

	this.resetTourOperatorEvent = false;

	this.categoryRange      = this.ALL_CATEGORIES;      //доступные для выбора категориии в зависимости от выбранных курортов
	this.foodTypeRange      = this.ALL_FOOD_TYPES;      //доступные для выбора типы питания в зависимости от выбранных курортов
	this.accommodationRange = this.ALL_ACCOMMODATIONS;  //доступные для выбора размещения в зависимости от выбранного курорта
	this.accommodationHandSelectedId = -1;               //вручную выбранное размещение из массива this.ACC_TEXT

	this.clearControls();

	this.initDepartureCtrl();
	this.initTourTypeCtrl();
	this.initCountryCtrl();
	this.initCountryFilterCtrl();
	this.initServicesCtrl();
	this.initCurrencyCtrl();

	if(this.resortException) {
		var c = this.form.elements[this.formId + 'ResortCtrl'];
		if(c) {
			c.appendChild(exatCreateOptionElement('', 'Нет туров по маршруту.'));
			c.appendChild(exatCreateOptionElement('', 'Выберите другой маршрут'));
			c.appendChild(exatCreateOptionElement('', 'или другой тип тура.'));
			c.disabled = true;
		}
	}

	if (this.countryId) {
		if (this.resortData['x' + this.departureId + '-' + this.countryId]) {
			this.fillResort();
		} else {
			this.asyncLoadResort();
		}
	}
	this.initTransportRequiredCtrl();
	this.initResortFilterCtrl();
	this.initLimitCtrl();
	this.initResultTypeCtrl();

	var ctrl = this.form.elements[this.formId + 'MinAmountCtrl'];
	if(ctrl) {
		ctrl.value = (this.minAmount>0) ? this.minAmount : '';
	}

	ctrl = this.form.elements[this.formId + 'MaxAmountCtrl'];
	if(ctrl) {
		ctrl.value = (this.maxAmount < this.MAX_AMOUNT && this.maxAmount>0) ? this.maxAmount : '';
	}
	//установка обработчиков событий
	for (var i = 0; i < this.controls.length; i++) {
		var c = this.form.elements[this.formId + this.controls[i].name];
		if(c) {
			if(!c.onchange && this.controls[i].onchange) {
				c.onchange = new Function(
					"window.exatForms['" + this.formId + "'].on"
					+ this.controls[i].name + "Change" + "()");
			}
			if(!c.onclick && this.controls[i].onclick) {
				c.onclick = new Function(
					"window.exatForms['" + this.formId + "'].on"
					+ this.controls[i].name + "Click" + "()");
			}
		}
	}

	this.enableControls();
	this.resortException = false;

	if(typeof(this.values)!='undefined') {
		delete this.values;
	}

	this.initTimeout = 0;

	if(this.form.elements[this.formId + 'IncludeStopCtrl']){
		var checkIncludeStop=this.form.elements[this.formId + 'IncludeStopCtrl'];
		checkIncludeStop.checked=this.includeStop;
	}
	if(this.form.elements[this.formId + 'ShowTechInfoCtrl']){
		var checkShowTechInfo=this.form.elements[this.formId + 'ShowTechInfoCtrl'];
		checkShowTechInfo.checked=this.showTechInfo;
	}
	if(this.form.elements[this.formId + 'ShowTourOperatorCtrl']){
		var checkShowTourOperator=this.form.elements[this.formId + 'ShowTourOperatorCtrl'];
		checkShowTourOperator.checked=this.showTourOperator || this.showTechInfo;
		checkShowTourOperator.disabled=this.showTechInfo;
	}
	this.formInitAutoAppend();
}

ExatSearchForm.prototype.formInitAutoAppend = function(){
}

ExatSearchForm.prototype.test = function(){
//D EBUG BEGIN
     var res = [];
	obj=this.hotelIds;
     for (var prop in obj) {
//return;
          if (obj.hasOwnProperty(prop)) {
               if (useValues=0     && (typeof(obj[prop]) != 'boolean') && (obj[prop] == Number(obj[prop]))){
                    res.push(obj[prop]);
               } else if (prop == Number(prop)) {
                    res.push(prop);
               }
          }
     }
     var rrr=res.join(',');
alert(rrr);
//D EBUG END
}
/** Подготовить массив данных поискового запроса клиентской версии
 * Каждый элемент массива - пара (имя, строка)
 * В строке может быть несколько значений через запятую
 * Можно вызывать для самостоятельной отправки запроса, не через функцию submitForm
 * Совпадает по именам полей с сервисом xml_tours, кроме двух доп. полей client_id и lcc
 * @access public
 * @return объект, где свойства содержат данные поискового запроса
 */
ExatSearchForm.prototype.getSubmitData = function()
{
	var q = [
		['departureId', this.departureId],
		['lcc',         this.countryId],
		['currencyId',  this.currencyId],
		['maxGenDays',  this.MAX_TOUR_DAYS],
		['limit',       this.limit]
	];

	if(!!this.form && typeof this.form.client_id != 'undefined'){
		this.form.client_id.value=this.clientId;
	}else{
		q.push(['client_id',  this.clientId]);
	}

	if(this.transportRequired > 0) {
		q.push(['transportRequired',  1]);
	}

	if(this.resortFilter > 0) {
		q.push(['selectedPlacesOnly',  1]);
	}

	if(this.countryFilter) {
		if (this.countryFilter instanceof Array) {
			q.push(['countryFilter', exatJoinNumbers(this.countryFilter, true)]);
		} else {
			q.push(['countryFilter', +this.countryFilter]);
		}
	}

if(this.includeStop > 0) {
		q.push(['includeStop',  1]);
	}
	if(!this.resortIds || !this.resortIds.length) {
		q.push(['placeGroupId[]', this.countryId ]);
		q.push(['placeItemId[]', this.countryId ]);
	}
	else {
		var resortStr = exatJoinNumbers(this.resortIds, /*isArray=*/ false);
		if(resortStr.length) {
			q.push(['placeGroupId[]', resortStr ]);
			q.push(['placeItemId[]', resortStr ]);
		}
		else {
			q.push(['placeGroupId[]', this.countryId ]);
			q.push(['placeItemId[]', this.countryId ]);
		}
	}
	if(this.tourTypeMask!=this.ALL_TOUR_TYPES) {
		var a = '';
		for(var i=0; i<31; ++i) {
			if(this.tourTypeMask & (1<<i)) {
				a += (a.length ? ',' : '') + (1<<i);
			}
		}
		q.push(['tourTypeId[]', a]);
	}
	if(this.categoryMask!=this.ALL_CATEGORIES) {
		var a = '';
		for(var i=0; i<31; ++i) {
			if(this.categoryMask & (1<<i)) {
				a += (a.length ? ',' : '') + i;
			}
		}
		q.push(['categoryId[]', a]);
	}
	if(this.foodTypeMask!=this.ALL_FOOD_TYPES) {
		var a = '';
		for(var i=0; i<31; ++i) {
			if(this.foodTypeMask & (1<<i)) {
				a += (a.length ? ',' : '') + (i+1);
			}
		}
		q.push(['foodTypeId[]', a]);
	}
	if(this.minTimestamp > 0) {
		q.push(['minDate', exatFromTime(this.minTimestamp)]);
	}
	if(this.maxTimestamp > 0) {
		q.push(['maxDate', exatFromTime(this.maxTimestamp)]);
	}
	if(this.minDuration > 0) {
		q.push(['minDuration', this.minDuration]);
	}
	if(this.maxDuration > 0) {
		q.push(['maxDuration', this.maxDuration]);
	}
	if(this.minNightsDuration > 0) {
		q.push(['minNightsDuration', this.minNightsDuration]);
	}
	if(this.maxNightsDuration > 0) {
		q.push(['maxNightsDuration', this.maxNightsDuration]);
	}
	if(this.minAmount > 0) {
		q.push(['minAmount', this.minAmount]);
	}
	if(this.maxAmount!=this.MAX_AMOUNT) {
		q.push(['maxAmount', this.maxAmount]);
	}
	if(this.accommodationId > 0) {
		q.push(['accommodation', this.ACC_VAL[this.accommodationId]]);
	}
	if(this.ages && this.ages.length) {
		q.push(['ages[]', this.ages]);
	}
	var hotels = exatJoinNumbers(this.hotelIds, /*isArray=*/ false);//у отелей могут быть отрицательные id, поэтому свойство length массива проверять нельзя
	if(hotels.length) {
		q.push(['hotelId[]', hotels]);
	}
	if(!!this.serviceIds && this.serviceIds.length) {
		q.push(['serviceId[]', exatJoinNumbers(this.serviceIds, /*isArray=*/ false)]);
	}
	if(this.tourOperatorIds && this.tourOperatorIds.length) {
		var str = exatJoinNumbers(this.tourOperatorIds, /*isArray=*/ false);
		if(str.length) {
			q.push(['tourOperatorId[]', str]);
		}
	}
	else {
		if(this.prefTourOperators.length > 0) {
			q.push(['tourOperatorId[]', this.prefTourOperators]);
		}
	}
	if (this.resultType != 'tours') {
		q.push(['resultType', this.resultType]);
	}
	return q;
}

/** Сконвертировать объект с параметрами запроса в строку суффикса
 * @access public
 * @param sdata объект с параметрами для конвертации в строку запроса,
 *   полученный, например, через getSubmitData
 * @return URL suffix to append to search query
 */
ExatSearchForm.prototype.getSubmitSuffix = function(sdata)
{
	var result = '';
	for(var i=0; i< sdata.length; ++i) {
		result += '&' + sdata[i][0] + '=' + sdata[i][1];
	}
	return result;
}

/** Получить стандартный префикс для action
 * @access public
 * @return строка префикса
 */
ExatSearchForm.prototype.getSubmitPrefix = function()
{
	return this.host + '/touronline/result-v2.php?';
}

/** Отправить поисковый запрос
 * @access public
 * @param openNewWindow - если true, то будет открыто новое окно
 * @param customAction - если не пуст, то запрос будет отправлен на указнный action url
 */
ExatSearchForm.prototype.submitForm = function(openNewWindow, customAction)
{
	if (!this.checkParameters()) {
		return false;
	}
	holder=window.document.location.protocol+'//'+window.document.location.hostname+'/';
	this.form.action = (customAction ? customAction : this.getSubmitPrefix())
		+ this.getSubmitSuffix(this.getSubmitData())
		+'&holder='+str2code(holder) //escape(window.document.location)
	;
	
    t = ((this.form.action).indexOf('&'));
	
    r = ((this.form.action).substr(t))+"&page=";
    
    r = r.split('placeGroupId[]').join('placeGroupId');
    r = r.split('placeItemId[]').join('placeItemId');
    r = r.split('categoryId[]').join('categoryId');

    window.location.href = 'http://www.in-turs.ru/country.php?'+r;
	 
	
   
	/*if(openNewWindow) {
		var wnd  = window.open('', this.nextNewWindowName, this.params['newWindowParams']);

		wnd.document.write('Пожалуйста, подождите. Идет поиск туров...');
		wnd.focus();
		this.form.target = this.nextNewWindowName;
		this.nextNewWindowName = this.generateNewWindowName();
	}
	
	this.form.submit();
	*/
}

ExatSearchForm.prototype.onSubmitCtrlClick = function()
{
	this.submitForm(true);
}

ExatSearchForm.prototype.onResetCtrlClick = function()
{
	this.initForm();
}

ExatSearchForm.prototype.resetForm = function()
{
	this.initForm();
}

ExatSearchForm.prototype.generateNewWindowName = function()
{
	return 'result_' + exatGenRandomStr(10);
}

/**
* Динамическая загрузка скрипта
*/
ExatSearchForm.prototype.loadScript = function(url) {
	var s = document.createElement('script');
	s.src = url;
	s.language = 'javascript';
	try {
		s.charset = 'Windows-1251';
	} catch (e) {}
	// Dirty fix for an occasional IE7 bug
	document.body.insertBefore(s, document.body.firstChild);
}

/** Динамическая асинхронная загрузка данных курортов и др. после выбора страны.
 * @access protected, но предназначена для вызова только из скриптов системы "Ехать!"
 */
ExatSearchForm.prototype.asyncLoadResort = function() {
	// Последний выполненный запрос будет автоматически повторяться, чтобы данные не устаревали
	if (this.LoadResortTimeout != null) {
		clearTimeout(this.LoadResortTimeout);
	}
	if (this.LoadInitTimeout != null) {
		clearTimeout(this.LoadInitTimeout);
	}
	this.LoadResortTimeout = setTimeout('exatForms.' + this.formId + '.asyncLoadResort()', this.AutoRefreshTimeout);

	this.loadScript(this.host + '/touronline/?jsapp=getjs&ver=4&file=data-'
		+ this.departureId + '-' + this.countryId
		+ '&form_id=' + this.formId
	  + '&showTourCount=' + this.showTourCount
		+ (this.clientId ? '&client_id=' + this.clientId : ''));
}

/** Заполнение списка курортов и зависимых от них данных.
 * @access public, но предназначена для вызова только из скриптов системы "Ехать!"
 */
ExatSearchForm.prototype.fillResort = function()
{
	this.initResortCtrl();
	this.initLCDCtrl();
	this.initCategoryCtrl();
	this.initFoodTypeCtrl();
	this.initAccommodationCtrl();
	this.initHotelCtrl();
	this.initTourOperatorCtrl();

	this.enableControls();
}

/** Заполнение данных, привязанных к текущим выбранным точке отправления и стране
 * @access public, но для вызова только из скриптов "Ехать!"
 * @param departureId - код точки отправления
 * @param countryId - код страны
 * @param propName - имя свойства, куда вписать массив данных
 * @param propVal - данные
 */
ExatSearchForm.prototype.setResortParam = function(departureId, countryId, propName, propVal) {
	var id = 'x' + departureId + '-' + countryId;
	if (!this.resortData[id]) {
		this.resortData[id] = [];
	}
	this.resortData[id][propName] = propVal;
}

/** Получить данные свойства, учитывая выбранную точку отправления и страну
 * @access protected
 * @param propName имя свойства
 * @return null, если не выбрана страна или данные ещё не загружены, иначе -
 *   значение свойства с именем propName
 */
ExatSearchForm.prototype.getResortData = function(propName)
{
	if (!this.countryId) {
		return null;
	}

	var id = 'x' + this.departureId + '-' + this.countryId;
	if (!this.resortData[id]) {
		this.asyncLoadResort();//отдадим команду на загрузку данных
		return null;//но не будем дожидаться загрузки
	}

	return this.resortData[id][propName];
}

/** Возвратить строку символов с объёдинёнными битами дат/длительностей по курортам
 * В каждом символе используется только шесть бит
 * @param indx 0=даты, 1=длительности
 * @return строка с символами с установленными битами
 */
ExatSearchForm.prototype.getString6 = function(indx)
{
	var r = this.getResortData('lcd');
	if(r==null) {
		reportWarning("Не выбрана страна или не загружены данные курортов");
		return '';
	}

	var res = '';
	var allResorts = true; //выбраны [все] курорты
	for(var resortId in this.resortIds) {
		if(resortId != Number(resortId)) continue;
		allResorts = false;
		break;
	}
	for(resortId in r) {
		if(resortId != Number(resortId)) continue;
		if(allResorts || this.resortIds[resortId]) {
			var str = r[resortId][indx];
			if (str.length < res.length) {
				// Если строка с упакованными датами короче текущего значения res, дополним ее пустышками
				var padLength = res.length - str.length;
				var padString = "";
				for (var i = 0; i < padLength; i++) {
					padString += '?';
				}
        str += padString;
			}
			var len = str.length;
			if(res=='') {
				for (var i = 0; i < len; i++) {
					res += '?';
				}
			}
			var buffer = '';
			for (var j = 0; j < len; j++) {
				buffer += String.fromCharCode(((str.charCodeAt(j) - 63) | (res.charCodeAt(j) - 63)) + 63);
			}
			res = buffer;
		}
	}

	return res;
}

/** Заполнить список значений single select "точка отправления" и выбрать одно
 * в соответствии с this.departureId
 * @access protected
 */
ExatSearchForm.prototype.initDepartureCtrl = function()
{
	var c = this.form.elements[this.formId +'DepartureCtrl'];
	if (!c || c.nodeName != 'SELECT') {
		return 1;
	}

	exatClearCtrl(c);

	var arr = this.departureData;
	var f = false;

	for (var i in arr) {
		if(i!=Number(i)) continue; //пропустим нечисловые свойства
		var o = exatCreateOptionElement(i, arr[i][0]);

		if (i == this.departureId) {
			f = true;
			o.setAttribute('selected', 'selected');
		}
		c.appendChild(o);
	}

	if (!f){
		//не нашли, выбираем первую попавшуюся точку отправления
		if(c.firstChild) {
			c.firstChild.setAttribute('selected', 'selected');
			this.departureId = c.firstChild.value;
		}
		else {
			this.departureId = 0;
			this.reportError("Нет доступных точек отправления");
		}
	}
}

/** Заполнить список значений single/multi select "типы туров"
 * и выбрать одно или несколько значений в соответствии с this.tourTypeMask
 * @access protected
 */
ExatSearchForm.prototype.initTourTypeCtrl = function()
{
	var c = this.form.elements[this.formId + 'TourTypeCtrl'];

	if(!c) {
		return 1;
	}

	exatClearCtrl(c);

	//битовая маска доступных типов туров в текущей точке отправления
	var availableTourTypes = this.departureData[this.departureId][1];

	var firstElement = exatCreateOptionElement(0, '[все]');
	if(this.tourTypeMask == this.ALL_TOUR_TYPES) {
		firstElement.setAttribute('selected', true);
	}

	c.appendChild(firstElement);
	var allSelected = true;

	//в tourTypeId установлен всегда только один бит
	for(var tourTypeId in this.tourTypeData) {
		if (tourTypeId!=Number(tourTypeId) || !(tourTypeId & availableTourTypes)) {
			continue;
		}

		var o = exatCreateOptionElement(tourTypeId, this.tourTypeData[tourTypeId]);

		if (!(tourTypeId & this.tourTypeMask)) {
			this.tourTypeMask &= ~tourTypeId;
			allSelected = false;
		}

		c.appendChild(o);
	}
	var selectTourType=false;

	if(allSelected) {
		exatSelectChild(firstElement);
		selectTourType=true;
	}
	else {
		for (var opt = c.firstChild.nextSibling; opt; opt = opt.nextSibling) {
			if(this.tourTypeMask & opt.value) {
				exatSelectChild(opt);
				selectTourType=true;
			}
		}
	}
	if(!selectTourType){
		exatSelectChild(firstElement);
	}
}


/** Заполнить список значений для select "группа стран"
 * @access protected
 */
ExatSearchForm.prototype.initCountryFilterCtrl = function()
{
	var c = this.form.elements[this.formId + 'CountryFilterCtrl'];
	if(!c || !this.countryGroups) {
		return;
	}
	exatClearCtrl(c);
	c.appendChild(exatCreateOptionElement(0, '[все]'));
	var countryIds = this.departureData[this.departureId][2];
	for (var i = 0; i < this.countryGroups.length; i++) {
		var groupIsPopulated = false;
		for (var j = 0; j < countryIds.length; j++) {
			var countryId = countryIds[j];
			if (typeof(this.countryData[countryId]) != 'undefined'
				&& this.countryData[countryId][1] & this.tourTypeMask
			) {
				if (this.countryData[countryId][2]) {
					for (var gi = 0; gi < this.countryData[countryId][2].length; gi++) {
						if (this.countryData[countryId][2][gi] == this.countryGroups[i][0]) {
							groupIsPopulated = true;
							break;
						}
					}
				}
			}
		}
		if (!groupIsPopulated) {
			continue;
		}
		c.appendChild(exatCreateOptionElement(this.countryGroups[i]['0'], this.countryGroups[i]['1']));
	}
	if (!!this.countryFilter) {
		var val = this.countryFilter;
		if (!(this.countryFilter instanceof Array)) {
			val = [+this.countryFilter];
		}
		for (var i = 0; i < c.options.length; i++) {
			for (var j = 0; j < val.length; j++) {
				if (c.options[i].value == val[j]) {
					c.options[i].selected = true;
				}
			}
		}
	}
}

/** Заполнить список значений для single select "страна" и выбрать одно значение
 * в соответствии с this.countryId
 * @access protected
 */
ExatSearchForm.prototype.initCountryCtrl = function()
{
	var c = this.form.elements[this.formId + 'CountryCtrl'];
	if(!c) {
		return;
	}
	exatClearCtrl(c);

	var f = false;

	var availableCountryIds = this.departureData[this.departureId][2];

	c.appendChild(exatCreateOptionElement(0, allCountryText?allCountryText:'выберите страну'));
	for (var i = 0; i <availableCountryIds.length; ++i) {
		var countryId = availableCountryIds[i];
		if (!(this.countryData[countryId] && this.countryData[countryId][1] & this.tourTypeMask)) {
			continue;
		}
		if (this.countryFilter instanceof Array) {
			var countryFilter = this.countryFilter;
		} else if (+this.countryFilter) {
			var countryFilter = [+this.countryFilter];
		}
		if (!!countryFilter) {
			var countryFits = 0;
			if (this.countryData[countryId][2]) {
				for (var fi = countryFilter.length; fi--;) {
					if (+countryFilter[fi] == 0) {
						countryFits++;
					} else {
						for (var ci = this.countryData[countryId][2].length; ci--;) {
							if (+this.countryData[countryId][2][ci] == +countryFilter[fi]) {
								countryFits++;
							}
						}
					}
				}
			}
			if (countryFits != countryFilter.length) {
				continue;
			}
		}

		var o = exatCreateOptionElement(countryId, this.countryData[countryId][0]);

		if(countryId == this.countryId)
		{
			f = true;
			o.setAttribute('selected', 'selected');
		}

		c.appendChild(o);
	}

	if (!f) {
		this.countryId = 0;
	}

	//this.resortIds = [];
}

/** Установить значение checkbox "только с включённым перелётом"
 * в соответствии с this.transportRequired, поменяв перед этим при необходимости
 * значение  и this.transportRequired в соответствии с  this.countryIncTrans
 * @access protected
 */
ExatSearchForm.prototype.initTransportRequiredCtrl = function()
{
	if(this.countryId > 0 && this.countryIncTrans > 0 &&
		 typeof(exatPrefData[this.clientId].prefIncludeCheckbox) != 'undefined' &&
	   typeof(exatPrefData[this.clientId].prefIncludeCheckbox[this.countryId]) != 'undefined')
	{
		this.transportRequired = exatPrefData[this.clientId].prefIncludeCheckbox[this.countryId] ? 1 : 0;
	} else {
		this.transportRequired = this.defaults.transportRequired;
	}

	var c = this.form.elements[this.formId+'TransportRequiredCtrl'];

	if(c) {
		exatSetCheckedValue(c, this.transportRequired);
	}
}

/** Заполнить список значений single/multi select "курорты" и выбрать одно
 * или несколько значений в соответствии с массивом this.resortIds
 * @access protected
 */
ExatSearchForm.prototype.initResortCtrl = function() {
	var c = this.form.elements[this.formId+'ResortCtrl'];
	var isSelected=false;
	if(!c) {
		return 1;
	}

	exatClearCtrl(c);

	if(!Number(this.countryId)) {
		return 0;
	}

	this.foodTypeRange      = this.ALL_FOOD_TYPES;
	this.categoryRange      = this.ALL_CATEGORIES;
	this.accommodationRange = this.ALL_ACCOMMODATIONS;

	var resortData = this.getResortData('resorts');
	if (!resortData) {
		return 0;
	}


	var firstElement = exatCreateOptionElement(this.countryId, '[все]');

	c.appendChild(firstElement);

	var filled = false;

	for (var resortId in resortData) {
		if (resortId!=Number(resortId) || !(resortData[resortId][1] & this.tourTypeMask)){
			continue;
		}

		if (resortData[resortId][4] && resortData[resortId][4].length) {
			filled = true;
			if (resortData[resortId][4].length > ((this.resortDepth + 1) * 7)) {
				continue; // отображать курорт не нужно, задана меньшая глубина дерева
			}
			if (resortData[resortId][4].length <= 7) {
				continue; // отображать курорт не нужно, это корневой курорт (страна)
			}
		}

		filled = true;
		var opt = exatCreateOptionElement(resortId, resortData[resortId][0]);


		if(this.resortIds[resortId]) {
			opt.setAttribute('selected', 'selected');
			isSelected=true;
			this.resortIds[resortId] = 2;
		}
		var optt = c.appendChild(opt);
		if (resortData[resortId][0].charAt(0) != String.fromCharCode(160)) {
			optt.style.fontWeight = "bold";
			//optt.style.color = "blue";

		}
	}

	//удалим из resortIds невыбранные курорты
	for(resortId in this.resortIds) {
		if(resortId == Number(resortId) && this.resortIds[resortId] != 2) {
			delete this.resortIds[resortId];
		}
	}

	this.resortException = false;

	if (!filled) {
		this.resortException = true;
		return -1;
	}
	if(!isSelected)
		firstElement.setAttribute('selected', true);
	return 0;
}

/** Установить значение checkbox "туры только в выбранные курорты"
 * в соответствии с this.resortFilter
 * @access protected
 */
ExatSearchForm.prototype.initResortFilterCtrl = function()
{
	var c = this.form.elements[this.formId+'ResortFilterCtrl'];

	if(!c) {
		return 1;
	}

	if (c && c.nodeName == 'INPUT' && c.getAttribute('type') == 'checkbox') {
		c.checked = this.resortFilter;
	}
}


/** Заполнить список значений single select'ов "дата от"/"до",
 * длительность от"/"до" и выбрать значения в соответствии
 * с this.minTimestamp, this.maxTimestamp, this.minDuration, this.maxDuration,
 * а также this.transportRequired
 * @access protected
 */
ExatSearchForm.prototype.initLCDCtrl = function()
{
	var oCl, oCh;
	var cl, ch;
	var ddstr;

	var symb;
	var tmpDate;
	var val, name;

	var d0         = this.getResortData('date');
	if(d0==null) { //данные не подгружены (возможно, туров нет в этой связке точка отправления/страна)
		return;
	}
	var dNow       = new Date();

	// Даты
	d0.setHours(this.DEF_HOURS);
	d0.setMinutes(0);
	d0.setSeconds(0);
	d0.setMilliseconds(0);

	dNow.setHours(this.DEF_HOURS);
	dNow.setMinutes(0);
	dNow.setSeconds(0);
	dNow.setMilliseconds(0);

	var zeroTime = d0.getTime();
	var nowTime  = dNow.getTime();

	cnl = this.form.elements[this.formId + 'MinNightsDateCtrl'];
	cnh = this.form.elements[this.formId + 'MaxNightsDateCtrl'];
	cl = this.form.elements[this.formId + 'MinDateCtrl'];
	ch = this.form.elements[this.formId + 'MaxDateCtrl'];

	if(cnl) {
		exatClearCtrl(cnl);
		oCl = exatCreateOptionElement(0, '[все]');
		cnl.appendChild(oCl);
	}

	if (cnh) {
		exatClearCtrl(cnh);
		oCh = exatCreateOptionElement(0, '[все]');
		cnh.appendChild(oCh);
	}
	if(cl) {
		exatClearCtrl(cl);
		oCl = exatCreateOptionElement(0, '[все]');
		cl.appendChild(oCl);
	}

	if (ch) {
		exatClearCtrl(ch);
		oCh = exatCreateOptionElement(0, '[все]');
		ch.appendChild(oCh);
	}

	var loSel = null;
	var hiSel = null;
	var lonSel = null;
	var hinSel = null;

	ddstr  = this.getString6(0);
	for (j = 0; j < ddstr.length; j++) {

		symb = ddstr.charCodeAt(j) - 63;

		if (symb) {
			for (var l = 1; l < 7; l++) {
				if (Math.pow(2, l - 1) & symb) {
					tmpTime     = zeroTime + this.ONE_DAY_MS * (j * 6 + l);
					val         = tmpTime;
					name        = exatGetNiceDate(tmpTime);

					if(cnl) {
						oCnl = cnl.appendChild(exatCreateOptionElement(val, name));
						if(this.minTimestamp > 0
							&& tmpTime <= this.minTimestamp
						) {
							//пытаемся выбрать предыдущую дату "от", если нет - то ближайшую более раннюю
							lonSel = oCnl;
						}
					}

					if(cnh) {
						oCnh = cnh.appendChild(exatCreateOptionElement(val, name));
						if(this.maxTimestamp > 0 && !hinSel && tmpTime >= this.maxTimestamp) {
							//пытаемся выбрать предыдущую дату "до", если нет - то ближайшую более позднюю
							hinSel = oCnh;
						}
					}
					if(cl) {
						oCl = cl.appendChild(exatCreateOptionElement(val, name));
						if(this.minTimestamp > 0
							&& tmpTime <= this.minTimestamp
						) {
							//пытаемся выбрать предыдущую дату "от", если нет - то ближайшую более раннюю
							loSel = oCl;
						}
					}

					if(ch) {
						oCh = ch.appendChild(exatCreateOptionElement(val, name));
						if(this.maxTimestamp > 0 && !hiSel && tmpTime >= this.maxTimestamp) {
							//пытаемся выбрать предыдущую дату "до", если нет - то ближайшую более позднюю
							hiSel = oCh;
						}
					}
				}
			}
		}
	}
	if(cnl) {
		lonSel = lonSel ? lonSel : cnl.firstChild;
		this.minTimestamp = lonSel.value;
		exatSelectChild(lonSel);
	}
	if(cnh) {
		hinSel = hinSel ? hinSel : cnh.firstChild;
		this.maxTimestamp = hinSel.value;
		exatSelectChild(hinSel ? hinSel : cnh.firstChild);
	}
	if(cl) {
		loSel = loSel ? loSel : cl.firstChild;
		this.minTimestamp = loSel.value;
		exatSelectChild(loSel);
	}
	if(ch) {
		hiSel = hiSel ? hiSel : ch.firstChild;
		this.maxTimestamp = hiSel.value;
		exatSelectChild(hiSel ? hiSel : ch.firstChild);
	}


	// Продолжительности

	cnl = this.form.elements[this.formId + 'MinNightsDurationCtrl'];
	cnh = this.form.elements[this.formId + 'MaxNightsDurationCtrl'];
	cl = this.form.elements[this.formId + 'MinDurationCtrl'];
	ch = this.form.elements[this.formId + 'MaxDurationCtrl'];

	if(cnl) {
		exatClearCtrl(cnl);
		oCnl = exatCreateOptionElement(0, '[все]');
		cnl.appendChild(oCnl);
	}

	if (cnh) {
		exatClearCtrl(cnh);
		oCnh = exatCreateOptionElement(0, '[все]');
		cnh.appendChild(oCnh);
	}
	if(cl) {
		exatClearCtrl(cl);
		oCl = exatCreateOptionElement(0, '[все]');
		cl.appendChild(oCl);
	}

	if (ch) {
		exatClearCtrl(ch);
		oCh = exatCreateOptionElement(0, '[все]');
		ch.appendChild(oCh);
	}

	ddstr = this.getString6(1);

	lonSel = null;
	hinSel = null;
	loSel = null;
	hiSel = null;

	if (this.transportRequired || ((ddstr.charCodeAt(0) - 63) & 0x03) == 0) {
		//если "только с перелётом" или нет туров на 1/2 дня (т.е. суточных)
		for (var j = 0; j < ddstr.length; j++) {
			symb = ddstr.charCodeAt(j) - 63;
			if (symb) {

				//пропустим в for'e туры на 1 день, т.к. это признак "суток",
				//а "сутки" у нас сейчас автоматически складываются
				for (var m = 1 + (j?0:1); m < 7; m++) {


					if ( (1 << (m - 1)) & symb) {



						val  = (j * 6 + m);
						name = val;
						nightsname=name-1;

						if(cnl) {
							oCnl = exatCreateOptionElement(val, nightsname);
							if(this.minNightsDuration > 0 && val <= this.minNightsDuration) {
								lonSel = oCnl;
							}
							cnl.appendChild(oCnl);
						}

						if(cnh) {
							oCnh = exatCreateOptionElement(val, nightsname);
							if(this.maxNightsDuration > 0 && !hinSel && val >= this.maxNightsDuration) {
								hinSel = oCnh;
							}
							cnh.appendChild(oCnh);
						}
						if(cl) {
							oCl = exatCreateOptionElement(val, name);
							if(this.minDuration > 0 && val <= this.minDuration) {
								loSel = oCl;
							}
							cl.appendChild(oCl);
						}

						if(ch) {
							oCh = exatCreateOptionElement(val, name);
							if(this.maxDuration > 0 && !hiSel && val >= this.maxDuration) {
								hiSel = oCh;
							}
							ch.appendChild(oCh);
						}
					}
				}
			}
		}
	}
	else {
		for(var j = 2; j <= this.MAX_TOUR_DAYS; j++) {
			val=j;
			name=j;
			nightsname=name-1;
			if(cnl) {
				oCnl = exatCreateOptionElement(val, nightsname);
				if (this.minNightsDuration > 0 && j <= this.minNightsDuration) {
					lonSel = oCnl;
				}
				cnl.appendChild(oCnl);
			}

			if(cnh) {
				oCnh = exatCreateOptionElement(val, nightsname);
				if (this.maxNightsDuration > 0 && !hinSel && j >= this.maxNightsDuration) {
					hinSel = oCnh;
				}
				cnh.appendChild(oCnh);
			}
			if(cl) {
				oCl = exatCreateOptionElement(val, name);
				if (this.minDuration > 0 && j <= this.minDuration) {
					loSel = oCl;
				}
				cl.appendChild(oCl);
			}

			if(ch) {
				oCh = exatCreateOptionElement(val, name);
				if (this.maxDuration > 0 && !hiSel && j >= this.maxDuration) {
					hiSel = oCh;
				}
				ch.appendChild(oCh);
			}
		}

	}

	if(cnl) {
		lonSel = lonSel ? lonSel : cnl.firstChild;
		this.minDuration = this.minNightsDuration = lonSel.value;
		exatSelectChild(lonSel);
	}
	if(cnh) {
		hinSel = hinSel ? hinSel : cnh.firstChild;
		this.maxDuration = this.maxNightsDuration = hinSel.value;
		exatSelectChild(hinSel ? hinSel : cnh.firstChild);
	}
	if(cl) {
		loSel = loSel ? loSel : cl.firstChild;
		this.minNightsDuration = this.minDuration = parseInt(loSel.value);
		exatSelectChild(loSel);
	}
	if(ch) {
		hiSel = hiSel ? hiSel : ch.firstChild;
		this.maxNightsDuration = this.maxDuration = parseInt(hiSel.value);
		exatSelectChild(hiSel ? hiSel : ch.firstChild);
	}

	return true;
}


/** Заполнить список значений single/multi select "категория отеля",
 * в соответствии с this.categoryIds
 * @access protected
 */
ExatSearchForm.prototype.initCategoryCtrl = function()
{
	var c = this.form.elements[this.formId + 'CategoryCtrl'];

	if(!c) {
		return;
	}

	exatClearCtrl(c);

	firstElement = exatCreateOptionElement(this.CAT_VAL[0], this.CAT_TEXT[0]);
	if(this.categoryMask==this.ALL_CATEGORIES || this.categoryMask==0) {
		exatSelectChild(firstElement);
	}

	c.appendChild(firstElement);

	var mask = 0;

	for (var i  = 1; i < this.CAT_TEXT.length; i++) {
		var element = exatCreateOptionElement(this.CAT_NEW_VAL[i], this.CAT_TEXT[i]);

		var vals = this.CAT_NEW_VAL[i].split(",");
		for(var j=0; j <vals.length; ++j) {
			if (this.categoryMask != this.ALL_CATEGORIES && (1 << vals[j] & this.categoryMask)) {
				exatSelectChild(element);
				mask |= 1 << vals[j];
			}
		}
		c.appendChild(element);
	}
}

/** Заполнить список значений single/multi select "типы питания",
 * в соответствии с this.foodTypeMask и доступными типами питания
 * @access protected
 */
ExatSearchForm.prototype.initFoodTypeCtrl = function()
{
	var c = this.form.elements[this.formId + 'FoodTypeCtrl'];

	if(!c) { //this control is optional
		return;
	}

	exatClearCtrl(c);

	var availableFoodTypes = this.getResortData('foodTypes');

	if (!availableFoodTypes) {
		return;
	}

	firstElement = exatCreateOptionElement(this.ALL_FOOD_TYPES, '[все]');
	c.appendChild(firstElement);

	var m = 0;

	//собираем маску доступных типов питания в зависимости от выбранных типов туров
	for (var tourTypeId in availableFoodTypes) {
		if (tourTypeId==Number(tourTypeId) && (this.tourTypeMask & tourTypeId)) {
			m |= availableFoodTypes[tourTypeId];
		}
	}

	//ограничиваем маску только питанием, доступным в выбранных курортах
	m &= this.foodTypeRange;

	var newMask       = 0;
	var selectedCount = 0;

	//заполняем новую маску выбранных типов питания newMask
	for(var foodTypeId in this.foodTypeData) {
		if(foodTypeId != Number(foodTypeId)) {
			continue; // пропускаем нечисловые свойства, которые могут появиться
			          // из-за прототипирования
		}
		if(m & (1<<(foodTypeId-1))) {
			o = exatCreateOptionElement(foodTypeId, this.foodTypeData[foodTypeId]);
			c.appendChild(o);
			if(this.foodTypeMask & (1<<(foodTypeId-1))) {
				newMask |= (1<<(foodTypeId-1));
				selectedCount++;
			}
		}
	}
	if (selectedCount == (c.length - 1)) {
		exatSelectChild(c.firstChild);
		newMask = this.ALL_FOOD_TYPES;
	}
	else {
		for (o = c.firstChild; o; o=o.nextSibling) {
			if(newMask & (1 << (o.getAttribute('value')-1) )) {
				exatSelectChild(o);
			}
		}
	}
	this.foodTypeMask = newMask;
}

/** Заполнить список значений single select "размещение",
 * в соответствии с this.accommodationId и доступными размещениями
 * @access protected
 */
ExatSearchForm.prototype.initAccommodationCtrl = function()
{
	var c = this.form.elements[this.formId + 'AgeCtrl'];
	if(c && typeof(this.ages)!='undefined')
		c.value=this.ages;
	var c = this.form.elements[this.formId + 'AccommodationCtrl'];

	if(!c) {
		return;
	}

	exatClearCtrl(c);


	var availableAccommodations = this.getResortData('accommodations');
	if (!availableAccommodations) {
		return;
	}

	var m = 0;

	//собираем маску доступных размещений в зависимости от выбранных типов туров
	for (var tourTypeId in availableAccommodations) {
		if (tourTypeId==Number(tourTypeId) && (this.tourTypeMask & tourTypeId)) {
			m |= availableAccommodations[tourTypeId];
		}
	}

	//ограничиваем маску только размещениями, доступными в выбранных курортах
	m &= this.accommodationRange;

	var firstId = null;

	if ( this.show123Acc && (m & 2)) {
		// поиск по 1/2/3 приведёт к каким-то результатам, если есть 2 взр.
		o = exatCreateOptionElement(this.ACC_VAL[0], this.ACC_TEXT[0]);
		c.appendChild(o);
		firstId = 0;
	}

	var newId = null;

	for (i = 0; i < 32; i++) {
		if (m & (1 << i)) {
			if(firstId==null) {
				firstId = i+1;
			}
			o = exatCreateOptionElement(i+1, this.ACC_TEXT[i+1]);
			if(this.accommodationHandSelectedId >=0) {
				if(this.accommodationHandSelectedId==i+1) {
					o.setAttribute("selected","selected");
					newId = i+1;
				}
			}
			else {
				if(this.accommodationId==i+1) {
					o.setAttribute("selected","selected");
					newId = i+1;
				}
			}
			c.appendChild(o);
		}
	}

	if (newId!=null) {
		this.accommodationId = newId;
	}
	else {
		if(firstId != null) {
			this.accommodationId = firstId;
		}
		else {
			this.accommodationId = 0;
		}
	}
}

/** Заполнить список значений single/multi select "отель",
 * в соответствии с this.hotelIds и доступными отелями
 * @access protected
 */
ExatSearchForm.prototype.initHotelCtrl = function()
{
	var c = this.form.elements[this.formId+'HotelCtrl'];

	if(!c) {
		return;
	}

	exatClearCtrl(c);
	var availableHotels = this.getResortData('hotels');
	if (!availableHotels) {
		return;
	}

	var f  = false; //признак уже встретившейся фортуны
	var hotelSelected = false; //был ли выбран хотя бы один отель
	var tm = this.tourTypeMask;
	var fm = this.foodTypeMask & this.foodTypeRange;
	var am = this.accommodationRange;
	var cm = (this.categoryMask == this.ALL_CATEGORIES) ? 0xffffffff : this.categoryMask;

	firstElement = exatCreateOptionElement('', '[все]');
	c.appendChild(firstElement);

	var allResortsSelected = true;
	for(var resortId in this.resortIds) {
		if(resortId != Number(resortId)) continue;
		allResortsSelected = false;
		break;
	}
	var strHotelIds=","+this.hotelIds.join(",")+",";
	for (var i =0; i < availableHotels.length; ++i) {
		var item = availableHotels[i];

		if (!((1 << item[2]) & cm)) {
			continue;
		}

		if (!(item[3] & tm) || !(item[4] & fm) || !(item[5] & am)) {
			continue;
		}

		// если выбран конкретный курорт или курорты, проверить, находится ли отель в нем или в одном из его подкурортов
		if (!allResortsSelected && !this.resortIds[item[6]]) {
			var availableResorts = this.getResortData('resorts');
			var hotelPlace = item[6];
			if (availableResorts[hotelPlace] && availableResorts[hotelPlace][4]) {
			  var hotelPlacePath = new String(availableResorts[hotelPlace][4].toString());
			} else {
				// курорт, где размещен отель, не найден или не имеет placePath (некорректные данные с сервера)
				continue;
			}
			// перебираем все выбранные курорты; если путь к отелю включает путь к выбранному курорту в позиции 0, то отель считается принадлежащим курорту и не пропускается
			var skipThisHotel = true;
	    for(var resortId in this.resortIds) {
		    if(resortId != Number(resortId)) continue;
				if (availableResorts[resortId] && availableResorts[resortId][4]) {
					var currResortPlacePath = availableResorts[resortId][4];
					if (hotelPlacePath.indexOf(currResortPlacePath) == 0) {
						skipThisHotel = false;
						continue;
					}
				}
			}
			if (skipThisHotel == true) {
				continue;
			}
		}

		var val = item[0];
		if (isNaN(val)) {//фортуна
			if (!f) {
				f = true;
				val = 0;
				o = exatCreateOptionElement(val, "[фортуна]");
			}
			else {
				continue;
			}
		}
		else {
			o = exatCreateOptionElement(val, item[1]);
		}
		if(strHotelIds.indexOf(","+val+",") !== -1
			|| this.hotelIds[val]!=undefined && this.hotelIds[val]==2
		){
			o.setAttribute("selected", "selected");
			hotelSelected = true;
			this.hotelIds[val] = 2; //to show it's used
		}
		c.appendChild(o);
	}

	//удалим из hotelIds невыбранные курорты
	for(hotelId in this.hotelIds) {
		if(hotelId == Number(hotelId) && this.hotelIds[hotelId] != 2) {
			delete this.hotelIds[hotelId];
		}
	}


	if(!hotelSelected) {
		//ни один отель не был выбран, тогда выбираем пункт "[все]"
		exatSelectChild(c.firstChild);
		this.hotelIds=new Array();
	}
}

/** Заполнить список значений single select "валюта",
 * в соответствии с this.currencyId и предпочтениями
 * @access protected
 */
ExatSearchForm.prototype.initCurrencyCtrl = function()
{
	var c = this.form.elements[this.formId + 'CurrencyCtrl'];
	if(!c) {
		return;
	}

	exatClearCtrl(c);

	var o;
	var prefCur;

	if(this.currencyId)
	{
		prefCur = this.currencyId;
	}
	if( this.countryId
		&& typeof(exatPrefData[this.clientId].prefCurrency) != 'undefined'
		&& typeof(exatPrefData[this.clientId].prefCurrency[this.countryId]) != 'undefined')
	{
		prefCur = exatPrefData[this.clientId].prefCurrency[this.countryId];
	}

	if(typeof(this.defaults.currencyId) != 'undefined'
		&& this.defaults.currencyId>0
	)
		prefCur = this.defaults.currencyId;
	for(var currencyId in this.currencyData) {
		if(currencyId != Number(currencyId)) {
			continue;
		}
		o = exatCreateOptionElement(currencyId, this.currencyData[currencyId]);

		if(prefCur && prefCur == currencyId) {
			exatSelectChild(o);
		}

		c.appendChild(o);
	}
  this.currencyId = Number(c.options[c.selectedIndex].value);
}

/** Заполнить список значений multi select "услуги",
 * и выбрать некоторые в соответствии с this.serviceIds
 * @access protected
 */
ExatSearchForm.prototype.initServicesCtrl = function()
{
	var c = this.form.elements[this.formId+'ServiceCtrl'];

	if(!c) {
		return;
	}

	exatClearCtrl(c);

	var noServicesSelected = true;
	for(var serviceId in this.serviceIds) {
		if(serviceId == Number(serviceId)) {
			noServicesSelected = false;
			break;
		}
	}

	firstElement = exatCreateOptionElement('', '[все]');
	if(noServicesSelected) {
		firstElement.setAttribute('selected', true);
	}

	c.appendChild(firstElement);
	for (var serviceGroupId in this.servicesData) {
		if(serviceGroupId != Number(serviceGroupId)) {
			continue;
		}
		var g = exatCreateGroupElement(this.servicesData[serviceGroupId][0]);
		var sarr = this.servicesData[serviceGroupId][1];

		for (var i = 0; i < sarr.length; ++i) {
			if(typeof(sarr[i])!='object') {
				continue;
			}
			var opt = exatCreateOptionElement(sarr[i][1], sarr[i][0]);
			if(this.serviceIds[sarr[i][1]]) {
				opt.setAttribute('selected', true);
			}
			g.appendChild(opt);
		}

		c.appendChild(g);
	}
}


/** Заполнить список значений multi select "туроператоры",
 * и выбрать некоторых в соответствии с this.tourOperatorIds и с предыдущими значениями контрола "Туроператоры"
 * @access protected
 */
ExatSearchForm.prototype.initTourOperatorCtrl = function()
{
	var c = this.form.elements[this.formId + 'TourOperatorCtrl'];

	if(!c) {
		return;
	}

	var prevTo = new Array();
	var allTourOperatorsSelected = true;
	if(this.tourOperatorDefIds!=-1 && this.tourOperatorDefIds.length>0){
		prevTo=this.tourOperatorDefIds;
	}else{

		if (c.firstChild && !c.firstChild.selected && !this.resetTourOperatorEvent) {
			for(o = c.firstChild.nextSibling; o; o = o.nextSibling)	{
				if(o.selected) {
					prevTo[o.value] = 2;
				} else {
					prevTo[o.value] = 1;
				}
			}
		}

		for(var toId in this.tourOperatorIds) {
			if(toId == Number(toId)) {
				allTourOperatorsSelected = false;
				prevTo[toId] = 2;
			}
		}
	}
	exatClearCtrl(c);
	var selTourOperatorIds=this.tourOperatorIds;
	this.tourOperatorIds = [];

	var availableTourOperators = this.getResortData('tourOperators');

	if (!availableTourOperators) {
		return;
	}

	var tm = this.tourTypeMask;
	var fm = this.foodTypeMask & this.foodTypeRange;
	var am = this.accommodationRange;

 	var usePrefTo       = false;
 	var resortToCnt     = 0;
 	this.prefTourOperators = '';

	if( typeof(exatPrefData[this.clientId].arrPrefTo) != 'undefined' &&
		exatPrefData[this.clientId].arrPrefTo.length > 0)
	{
		usePrefTo = true;
	}

	var f = 0; //количество выбранных туроператоров
	var allInPref = true; //все имеющиеся туроператоры - в предпочтениях, поэтому можно this.prefTourOperators сделать пустой

	var firstElement = exatCreateOptionElement('', '[все]');
	if(allTourOperatorsSelected) {
		firstElement.setAttribute('selected', true);
	}

	c.appendChild(firstElement);

	for (var i = 0; i < availableTourOperators.length; ++i) {
		var item = availableTourOperators[i];
		var toId = item[0];

		if (!(item[1] & tm) || !(item[2] & fm) || !(item[3] & am)) {
			continue;
		}

		resortToCnt++;

		if (usePrefTo && !exatPrefData[this.clientId].arrPrefTo[toId]){
			allInPref = false;
			continue;
		}

		this.prefTourOperators += (this.prefTourOperators.length > 0 ) ? (','+ toId) : toId;

		element = exatCreateOptionElement(toId, this.tourOperatorData[toId]);

		if(prevTo.length > 0 && (prevTo[toId] == 2 || !prevTo[toId] && this.tourOperatorDefIds==-1)) {
			//выбираем всех вновь появившихся туроператоров и тех, кто был выбран на пред. этапе
			exatSelectChild(element);
			this.tourOperatorIds[toId] = true;
			f++;
		}
		c.appendChild(element);
	}

	if(allInPref) {
		this.prefTourOperators = '';
	}

	if (c.length == 1) {
		// есть только пункт [все], а самих ТО ни одного
		c.removeChild(c.firstChild);
	} else if (f > 0 && f < (c.length - 1)) {
		// есть выделенные ТО, поэтому снимается выделение с пункта [все]
		exatUnselectChild(c.firstChild);
	} else if (f > 0 && f == (c.length - 1)) {
		// все ТО выделены, поэтому с них снимается выделение и выделяется пункт [все]
		var o;

		for(o = c.firstChild.nextSibling; o; o = o.nextSibling) {
			exatUnselectChild(o);
			delete this.tourOperatorIds[o.value];
		}
		exatSelectChild(c.firstChild);
	}
	this.tourOperatorDefIds=-1;
}

/** Заполнить список значений single select "размер страницы"
 * и выбрать пункт, соответствующий this.limit
 * @access protected
 */
ExatSearchForm.prototype.initLimitCtrl = function()
{
	var c = this.form.elements[this.formId + 'LimitCtrl'];
	if(!c) {
		return;
	}

	exatClearCtrl(c);
	var limits = [20,100,500,1000];

	for(var i=0; i<limits.length; ++i) {
		o = exatCreateOptionElement(limits[i], limits[i] + ' туров');

		if(limits[i] == this.limit) {
			exatSelectChild(o);
		}

		c.appendChild(o);
	}
	this.limit = Number(c.options[c.selectedIndex].value);
}

ExatSearchForm.prototype.initResultTypeCtrl = function() {
	var c = this.form.elements[this.formId + 'ResultTypeCtrl'];
	if(!c) {
		return;
	}
	if (this.resultType == 'hotels') {
		c.checked = true;
	} else {
		c.checked = false;
	}
}

/** Включить все элементы управления формы
 * @access protected
 */
ExatSearchForm.prototype.enableControls = function()
{
	for (var i = 0; i < this.controls.length; i++) {
		if(this.controls[i].name == 'ResortCtrl' && this.resortException) {
			continue;
		}
		var ctrl = this.form.elements[this.formId + this.controls[i].name];
		if(ctrl && this.controls[i].name == 'AgeCtrl' && this.getChildren() == 0) {
		    ctrl.disabled = true;
		    continue;
		}
		if(ctrl) {
			//TODO: Opera иногда не прорисовывает select'ы после disabled=false, и надо их выбирать заново
			/*
			var selIdx;
			if(ctrl.options && ctrl.type=='select-one') {
				selIdx = ctrl.selectedIndex;
			}
			*/
			ctrl.disabled = false;

			/*
			if(ctrl.options) {
				if(ctrl.type=='select-one') {
					ctrl.selectedIndex = selIdx;
				}
				else {
					for(var j = 0; j<ctrl.options.length; ++j) {
						if(ctrl.options[j].selected) {
							ctrl.options[j].selected = true;
						}
					}
				}
			}
			*/
		}
	}
}

/** Отключить все элементы управления формы
 * @access protected
 */
ExatSearchForm.prototype.disableControls = function()
{
	for (var i = 0; i < this.controls.length; i++) {
		var ctrl = this.form.elements[this.formId + this.controls[i].name];
		if(ctrl) {
			ctrl.disabled = true;
		}
	}
}
/** обработчик события onChange для single select id=_DepartureCtrl
 * может быть вызван сразу после конструктора
 */
ExatSearchForm.prototype.onDepartureCtrlChange = function()
{
	if(!this.form) {
		return;
	}
	var c = this.form.elements[this.formId + 'DepartureCtrl'];
	if (!c) {
		return;
	}
	this.setDepartureId(c.value);
}

ExatSearchForm.prototype.setDepartureId = function(departureId)
{
	this.disableControls();
	this.departureId = departureId;
	this.resetTourOperatorEvent = true;
	this.initTourTypeCtrl();
	this.countryFilter = 0;
	this.initCountryCtrl();
	this.initCountryFilterCtrl();
	if(this.initResortCtrl() == -1) {
		this.initForm();
		return;
	}
	this.initCategoryCtrl();
	this.initFoodTypeCtrl();
	this.initAccommodationCtrl();
	this.initHotelCtrl();
	this.initTourOperatorCtrl();

	this.resetTourOperatorEvent = false;

	this.enableControls();
}

/** обработчик события onChange для single или multi select id=_TourTypeCtrl
 */
ExatSearchForm.prototype.onTourTypeCtrlChange = function()
{
	if(!this.form) {
		return;
	}
	var ctrl = this.form.elements[this.formId + 'TourTypeCtrl'];
	if(!ctrl) {
		return;
	}

	var mask = 0;
	for (var o = ctrl.firstChild; o; o = o.nextSibling) {
		if (!o.selected) {
			continue;
		}
		if(o.getAttribute('value')=='0') {
			mask = this.ALL_TOUR_TYPES;
			break;
		}
		mask |= o.getAttribute('value');
	}
	this.setTourTypeMask(mask);
}

ExatSearchForm.prototype.setTourTypeMask = function(mask)
{
	this.disableControls();

	this.resetTourOperatorEvent = true;

	this.tourTypeMask = mask;

	this.countryFilter = 0;
	this.initCountryCtrl();
	this.initCountryFilterCtrl();

	if(this.initResortCtrl() == -1) {
		this.initForm({resortIds:'-1'});
		return;
	}
	this.initCategoryCtrl();
	this.initFoodTypeCtrl();
	this.initAccommodationCtrl();
	this.initHotelCtrl();
	this.initTourOperatorCtrl();

	this.resetTourOperatorEvent = false;

	this.enableControls();
}


/** обработчик события onChange для  select id=_CountryFilterCtrl
 */
ExatSearchForm.prototype.onCountryFilterCtrlChange = function()
{
	if(!this.form) {
		return;
	}
	var c = this.form.elements[this.formId + 'CountryFilterCtrl'];
	if (!c) {
		return;
	}
	var f = exatGetSelectValue(c);
	if (f instanceof Array) {
		for (var i = f.length; i--; ) {
			if (f[i] == 0) {
				for (var oi = c.options.length; oi--;) {
					if (c.options[oi].value == 0) {
						c.options[oi].selected = false;
						f = exatGetSelectValue(c);
						break;
					}
				}
			}
		}
	}
	this.setCountryFilter(f);
}

/** обработчик события onChange для single select id=_CountryCtrl
 */
ExatSearchForm.prototype.onCountryCtrlChange = function()
{
	if(!this.form) {
		return;
	}
	var c = this.form.elements[this.formId + 'CountryCtrl'];
	if (!c) {
		return;
	}
	this.setCountryId(c.value);
}

ExatSearchForm.prototype.setCountryFilter = function(flags) {
	this.disableControls();
	this.countryFilter = flags;
	var oldCountryId = this.countryId;
	this.initCountryCtrl();
	if (!!oldCountryId && !this.countryId) {
		this.initForm({countryFilter:flags});
	}
	this.enableControls();
}

ExatSearchForm.prototype.setCountryId = function(countryId)
{
	this.disableControls();

	if(countryId != this.countryId) {
		this.countryId = Number(countryId);
		this.resortIds = [];
		this.hotelIds = [];
	}

	this.resetTourOperatorEvent = true;

	if (!Number(this.countryId)) {
		this.initForm();

		this.enableControls();
		return;
	}

	this.initCurrencyCtrl();
	this.initTransportRequiredCtrl();
	if (this.resortData['x' + this.departureId + '-' + this.countryId]) {
		this.fillResort();
	} else {
		this.asyncLoadResort();
	}

	this.resetTourOperatorEvent = false;
}

/** обработчик события onChange для single или multi select name=_ResortCtrl
 */
ExatSearchForm.prototype.onResortCtrlChange = function()
{
	if(!this.form) {
		return;
	}
	var ctrl = this.form.elements[this.formId + 'ResortCtrl'];
	if(!ctrl) {
		return;
	}

	this.disableControls();

	var resortIds = [];

	for (var o = ctrl.firstChild; o; o = o.nextSibling) {
		if (!o.selected) {
			continue;
		}

		var id = o.getAttribute('value');

		if (id == this.countryId) {
			resortIds = [];
			break;
		}

		resortIds[id] = true;
	}

	this.setResortIds(resortIds);
}

ExatSearchForm.prototype.setResortIds = function(resortIds)
{
	this.resortIds = resortIds;

	if (!resortIds.length) {
		this.foodTypeRange      = this.ALL_FOOD_TYPES;
		this.accommodationRange = this.ALL_ACCOMMODATIONS;
	} else {
		var l = this.getResortData('resorts');
		var fr = 0;
		var ar = 0;

		for (resortId in this.resortIds) {
			if(resortId != Number(resortId)) {
				continue;
			}
			if (resortId == this.countryId) {
				fr = this.ALL_FOOD_TYPES;
				ar = this.ALL_ACCOMMODATIONS;
			} else {
				if(fr != this.ALL_FOOD_TYPES) {
					fr |= l[resortId][2];
				}
				if(ar != this.ALL_ACCOMMODATIONS) {
					ar |= l[resortId][3];
				}
			}
		}

		this.foodTypeRange      = fr;
		this.accommodationRange = ar;
	}

	this.hotelIds = []; //TODO: когда курорты будут деревом, необзательно выбор другого курорта должен сбрасывать выбор отелей

	this.disableControls();
	this.initLCDCtrl();
	this.initCategoryCtrl();
	this.initFoodTypeCtrl();
	this.initAccommodationCtrl();
	this.initHotelCtrl();
	this.initTourOperatorCtrl();
	this.enableControls();
}

/** обработчик события onChange для single или multi select name=_CategoryCtrl
 */
ExatSearchForm.prototype.onCategoryCtrlChange = function()
{
	if(!this.form) {
		return;
	}
	var ctrl = this.form.elements[this.formId+'CategoryCtrl'];
	if(!ctrl) {
		return;
	}

	var mask = 0;
	for (var o = ctrl.firstChild; o; o = o.nextSibling) {
		if (!o.selected) {
			continue;
		}
		if(o.getAttribute('value') == this.ALL_CATEGORIES) {
			this.setCategoryMask(this.ALL_CATEGORIES);
			return;
		}

		var vals = o.getAttribute('value').split(",");
		for(var j=0; j<vals.length; ++j) {
			mask |= 1 << vals[j];
		}
	}
	this.setCategoryMask(mask);
}


ExatSearchForm.prototype.setCategoryMask = function(mask)
{
	this.disableControls();
	this.categoryMask = mask;
	this.initHotelCtrl();
	this.initTourOperatorCtrl();
	this.enableControls();
}

/** обработчик события onChange для single или multi select name=_FoodTypeCtrl
 */
ExatSearchForm.prototype.onFoodTypeCtrlChange = function()
{
	if(!this.form) {
		return;
	}
	var ctrl = this.form.elements[this.formId + 'FoodTypeCtrl'];
	if(!ctrl) {
		return;
	}

	var mask = 0;
	for (var o = ctrl.firstChild; o; o = o.nextSibling) {
		if (!o.selected) {
			continue;
		}
		var n = new Number(o.getAttribute('value'));
		if(n == this.ALL_FOOD_TYPES) {
			mask = this.ALL_FOOD_TYPES;
			break;
		}

		mask |= 1 << (n-1);
	}
	this.setFoodTypeMask(mask);
}


ExatSearchForm.prototype.setFoodTypeMask = function(mask)
{
	this.disableControls();
	this.foodTypeMask = mask;
	this.initHotelCtrl();
	this.initTourOperatorCtrl();
	this.enableControls();
}

/** обработчик события onChange для single select name=accommodationCtrl
 */
ExatSearchForm.prototype.onAccommodationCtrlChange = function()
{
	if(!this.form) {
		return;
	}
	var ctrl = this.form.elements[this.formId+'AccommodationCtrl'];
	if(!ctrl) {
		return;
	}

	this.disableControls();

	this.accommodationId = ctrl.value;
	this.accommodationHandSelectedId = this.accommodationId;

	this.initHotelCtrl();
	this.initTourOperatorCtrl();

	this.enableControls();
}

ExatSearchForm.prototype.onAgeCtrlChange = function()
{
	if(!this.form) {
		return;
	}
}

ExatSearchForm.prototype.onResultTypeCtrlChange = function()
{
	if(!this.form) {
		return;
	}
	var c = this.form.elements[this.formId+'ResultTypeCtrl'];
	if(!c) {
		return;
	}
	if (c.checked) {
		this.resultType = 'hotels';
	} else {
		this.resultType = 'tours';
	}
}

ExatSearchForm.prototype.onHotelCtrlChange = function()
{
	if(!this.form) {
		return;
	}
	var ctrl = this.form.elements[this.formId+'HotelCtrl'];

	var opt = ctrl.firstChild;
	if(!opt) {
		return;
	}

	this.hotelIds = [];

	if((opt.value=='' || opt.value==0)) {
		if(opt.selected) {
			//спец. значение "[все]"
			return;
		}
		else {
			opt = opt.nextSibling;
		}
	}

	for (; opt; opt = opt.nextSibling) {
		if (!opt.selected) {
			continue;
		}
		this.hotelIds[opt.value] = true;
	}
}

ExatSearchForm.prototype.onResortFilterCtrlClick = function()
{
	if(!this.form) {
		return;
	}
	var ctrl = this.form.elements[this.formId+'ResortFilterCtrl'];
	if(!ctrl) {
		return;
	}
	this.resortFilter = ctrl.checked;
}

ExatSearchForm.prototype.onTransportRequiredCtrlClick = function()
{
	if(!this.form) {
		return;
	}
	var ctrl = this.form.elements[this.formId+'TransportRequiredCtrl'];
	if(!ctrl) {
		return;
	}
	this.transportRequired = ctrl.checked;

	if(this.countryId > 0) {
		//если страна уже выбрана, то перезаполняем список курортов и т.д.
		this.disableControls();
		this.initLCDCtrl();
		this.enableControls();
	}
}

ExatSearchForm.prototype.onMinDateCtrlChange = function()
{
	if(!this.form) {
		return;
	}
	var minCtrl = this.form.elements[this.formId + 'MinDateCtrl'];
	var maxCtrl = this.form.elements[this.formId + 'MaxDateCtrl'];
	if(minCtrl) {
		this.minTimestamp = minCtrl.value;
	}

	if (minCtrl && maxCtrl && (minCtrl.value == 0 || minCtrl.value > maxCtrl.value)) {
		maxCtrl.value = minCtrl.value;
		this.maxTimestamp = this.minTimestamp;
	}
}

ExatSearchForm.prototype.onMaxDateCtrlChange = function()
{
	if(!this.form) {
		return;
	}
	var minCtrl = this.form.elements[this.formId + 'MinDateCtrl'];
	var maxCtrl = this.form.elements[this.formId + 'MaxDateCtrl'];

	if(maxCtrl) {
		this.maxTimestamp = maxCtrl.value;
	}

	if (minCtrl && maxCtrl && maxCtrl.value != 0 && minCtrl.value > maxCtrl.value) {
		minCtrl.value = maxCtrl.value;
		this.minTimestamp = this.maxTimestamp;
	}
}

ExatSearchForm.prototype.onMinNightsDurationCtrlChange = function()
{
	if(!this.form) {
		return;
	}
	var minCtrl = this.form.elements[this.formId + 'MinNightsDurationCtrl'];
	if(! minCtrl)
		minCtrl = this.form.elements[this.formId + 'MinNightsDurationCtrl'];
	var maxCtrl = this.form.elements[this.formId + 'MaxNightsDurationCtrl'];
	if(!maxCtrl)
		maxCtrl = this.form.elements[this.formId + 'MaxNightsDurationCtrl'];

	if(!minCtrl) {
		return;
	}

	this.minDuration = this.minNightsDuration = minCtrl.value;

	if(maxCtrl && (minCtrl.value == 0 || parseInt(minCtrl.value) > parseInt(maxCtrl.value))) {
		this.maxDuration = maxCtrl.value = this.maxNightsDuration = this.minNightsDuration;
	}
}

ExatSearchForm.prototype.onMinDurationCtrlChange = function()
{
	if(!this.form) {
		return;
	}
	var minCtrl = this.form.elements[this.formId + 'MinDurationCtrl'];
	if(! minCtrl)
		minCtrl = this.form.elements[this.formId + 'MinDurationCtrl'];
	var maxCtrl = this.form.elements[this.formId + 'MaxDurationCtrl'];
	if(!maxCtrl)
		maxCtrl = this.form.elements[this.formId + 'MaxDurationCtrl'];

	if(!minCtrl) {
		return;
	}

	this.minNightsDuration = this.minDuration = minCtrl.value;
	if(maxCtrl && (minCtrl.value == 0 || parseInt(minCtrl.value) > parseInt(maxCtrl.value))) {
		this.maxNightsDuration = maxCtrl.value = this.maxDuration = this.minDuration;
	}
}

ExatSearchForm.prototype.onMaxNightsDurationCtrlChange = function()
{
	if(!this.form) {
		return;
	}
	var minCtrl = this.form.elements[this.formId + 'MinNightsDurationCtrl'];
	var maxCtrl = this.form.elements[this.formId + 'MaxNightsDurationCtrl'];
	if(!maxCtrl) {
		return;
	}

	this.maxDuration = this.maxNightsDuration = maxCtrl.value;

	if (minCtrl && maxCtrl.value!=0 && parseInt(minCtrl.value) > parseInt(maxCtrl.value)) {
		this.minDuration = minCtrl.value = this.minNightsDuration = this.maxNightsDuration;
	}
}

ExatSearchForm.prototype.onMaxDurationCtrlChange = function()
{
	if(!this.form) {
		return;
	}
	var minCtrl = this.form.elements[this.formId + 'MinDurationCtrl'];
	var maxCtrl = this.form.elements[this.formId + 'MaxDurationCtrl'];
	if(!maxCtrl) {
		return;
	}

	this.maxNightsDuration = this.maxDuration = maxCtrl.value;

	if (minCtrl && maxCtrl.value!=0 && parseInt(minCtrl.value) > parseInt(maxCtrl.value)) {
		this.minNightsDuration = minCtrl.value = this.minDuration = this.maxDuration;
	}
}

ExatSearchForm.prototype.onMinAmountCtrlChange = function()
{
	if(!this.form) {
		return;
	}
	var ctrl = this.form.elements[this.formId + 'MinAmountCtrl'];
	this.minAmount = ctrl.value;
}

ExatSearchForm.prototype.onMaxAmountCtrlChange = function()
{
	if(!this.form) {
		return;
	}
	var ctrl = this.form.elements[this.formId + 'MaxAmountCtrl'];
	this.maxAmount = ctrl.value;
}

ExatSearchForm.prototype.onCurrencyCtrlChange = function()
{
	if(!this.form) {
		return;
	}
	var ctrl = this.form.elements[this.formId + 'CurrencyCtrl'];
	this.currencyId = ctrl.value;
}

ExatSearchForm.prototype.onServiceCtrlChange = function()
{
	if(!this.form) {
		return;
	}
	var ctrl = this.form.elements[this.formId+'ServiceCtrl'];
	if(!ctrl) {
		throw new Error("Can't find element with id="+this.formId + "ServiceCtrl");
		return;
	}

	if(!ctrl.options.length) {
		return;
	}
	var opt = ctrl.options[0];

	this.serviceIds = [];

	if((opt.value=='' || opt.value==0)) {
		if(opt.selected) {
			//спец. значение "[все]"
			return;
		}
	}

	for (var i=1; i<ctrl.options.length; ++i) {
		if (!ctrl.options[i].selected) {
			continue;
		}
		this.serviceIds[ctrl.options[i].value] = true;
	}
}

ExatSearchForm.prototype.onTourOperatorCtrlChange = function()
{
	if(!this.form) {
		return;
	}
	var ctrl = this.form.elements[this.formId+'TourOperatorCtrl'];

	var opt = ctrl.firstChild;
	if(!opt) {
		return;
	}

	this.tourOperatorIds = [];

	if((opt.value=='' || opt.value==0)) {
		if(opt.selected) {
			//спец. значение "[все]"
			return;
		}
		else {
			opt = opt.nextSibling;
		}
	}

	for (; opt; opt = opt.nextSibling) {
		if (!opt.selected) {
			continue;
		}
		this.tourOperatorIds[opt.value] = true;
	}
}


ExatSearchForm.prototype.onLimitCtrlChange = function()
{
	if(!this.form) {
		return;
	}
	var ctrl = this.form.elements[this.formId+'LimitCtrl'];

	var opt = ctrl.firstChild;
	if(!opt) {
		return;
	}

	for (; opt; opt = opt.nextSibling) {
		if (opt.selected) {
			this.limit = opt.value;
			break;
		}
	}
}


ExatSearchForm.prototype.onShowTechInfoCtrlClick = function()
{
	if(!this.form) {
		return;
	}
	var ctrl = this.form.elements[this.formId + 'ShowTechInfoCtrl'];
	var c = this.form.elements[this.formId + 'ShowTourOperatorCtrl'];
	var s = ctrl.checked;

	c.checked  = s;
	c.disabled = s;
}

ExatSearchForm.prototype.onShowTourOperatorCtrlClick = function()
{
	if(!this.form) {
		return;
	}
	var c = this.form.elements[this.formId + 'ShowTourOperatorCtrl'];
}

ExatSearchForm.prototype.onIncludeStopCtrlClick = function()
{
	if(!this.form) {
		return;
	}
	var c = this.form.elements[this.formId + 'IncludeStopCtrl'];
	this.includeStop = c.checked ? 1 : 0;
}

ExatSearchForm.prototype.clearControls = function()
{
	for (var i = 0; i < this.controls.length; i++) {
		var c = this.form.elements[this.formId + this.controls[i].name];

		if(c) {
			if (c.nodeName == 'SELECT') {
				if (c.id && c.id == this.form.id + 'CountryFilterCtrl') {
					continue;
				}
				exatClearCtrl(c);

				for (var o = c.firstChild; o; o = o.nextSibling) {
					exatUnselectChild(o);
				}
			}
			else if (c.nodeName == 'INPUT') {
				var t = c.getAttribute('type');

				if (t == 'text') {
					c.value = '';
				}
			}
		}
	}
}

/** Отображение сообщения об ошибке в случае отсутствии обязательных параметров
 * @return true если ok, false если есть ошибки
 */
ExatSearchForm.prototype.checkParameters = function()
{
	var c;

	if(!Number(this.countryId)) {
		alert('Выберите cтрану');
		return false;
	}

	if (Number(this.minTimestamp) && Number(this.maxTimestamp) && Number(this.minTimestamp) > Number(this.maxTimestamp)) {
		alert('Начальная дата больше конечной');
		return false;
	}

	if (Number(this.maxNightsDuration) && Number(this.minNightsDuration) > Number(this.maxNightsDuration)) {
		alert('Задан некорректный диапазон количества ночей');
		return false;
	}

	if (Number(this.maxDuration) && Number(this.minDuration) > Number(this.maxDuration)) {
		alert('Задан некорректный диапазон количества дней');
		return false;
	}

	c = this.form.elements[this.formId+'TourOperatorCtrl'];

	if (c && c.length == 0) {
		var s = 'Список туроператоров пуст. Это означает, что среди туроператоров, обслуживающих маршрут, нет' +
				' ни одного из предпочитаемых Вами. Попробуйте настроить список предпочтительных туроператоров' +
				' при помощи ссылки "настроить список" над списком туроператоров или изменить маршрут.';
		alert(s);
		return false;
	}

	c = this.form.elements[this.formId+'AgeCtrl'];
	if (c && c.value.length > 0) {
		var ageS = c.value;
		var ageL = ageS.length;

		var ageN = 1;
		var age1 = '';
		var age2 = '';
		var sep  = 0;

		for (var i = 0; i < ageL; i++) {
			var ch = ageS.charAt(i);

			if (ch >= '0' && ch <= '9') {
				if (sep && age1.length > 0) {
					ageN++;
					age1 += ',';
					age2  = '';
					sep   = 0;
				}

				age1 += ch;
				age2 += ch;

				if (age2 > 25) {
					alert('Возраст ребенка должен быть до 25 лет включительно.');
					c.focus();
					return false;
				}
			}
			else {
				sep = 1;
			}
		}
		this.ages = age1;
		var chnum = this.getChildren();

		if(chnum > 0 && ageN > chnum) {
			alert('Введено больше возрастов, чем выбрано детей.\nУдалите лишние возрасты.');
			c.focus();
			return false;
		}
	}
	return true;
}

/** Поиск по коду тура
 * @access public
 */
ExatSearchForm.prototype.searchTpid = function(val, newWindow)
{
	if (val.length) {
		var url = '/touronline/tpid_search.php?tpid=' + val;

		var st = this.form.elements[this.formId + "ShowTechInfoCtrl"];
		var so = this.form.elements[this.formId + "ShowTourOperatorCtrl"];

		if (st && st.checked) {
			url += '&show_tech_info=1';
		} if (so && so.checked) {
			url += '&show_operator=1';
		}

		exatShowWindow(url, 700, 500);
	} else {
		alert('Укажите код тура');
	}
}

/** показать сообщение о предупреждении (нефатальной ошибке), если оно не пустое
 * @access protected
 */
ExatSearchForm.prototype.reportWarning = function(msg)
{
	if(this.params.alertLocks)
		return;
	if (msg != '') {
		this.showMessage('Предупреждение : ' + msg);
	} else {
		this.showMessage('Неизвестная ошибка');
	}
}

/** показать сообщение о фатальной ошибке, если оно не пустое
 * @access protected
 */
ExatSearchForm.prototype.reportError = function(msg)
{
	if(this.params.alertLocks)
		return;
	if (msg != '') {
		this.showMessage('Фатальная ошибка : ' + msg);
	} else {
		this.showMessage('Неизвестная фатальная ошибка');
	}
}

/** показать сообщение, если оно не пустое
 * @access protected
 */
ExatSearchForm.prototype.showMessage = function(msg)
{
	if(msg) {
		alert(msg);
		return true;
	}
	else {
		return false;
	}
}

ExatSearchForm.prototype.getChildren = function()
{
	var children = new Array(0,0);
	var accom = this.ACC_VAL[this.accommodationId];
	if (accom != Number(accom)) children = accom.split('_');
	return Number(children[1]);
}

/* глобальные утилитарные функции */

function exatGenRandomStr(strlen)
{
	str = '';
	for (i = 0; i < strlen; i++) {
		str += String.fromCharCode(Math.random()*25 + 97);
	}
	return str;
}

function exatShowWindow(url, width, height)
{
	size = '';

	if(width && height) {
		size = ',width=' + width + ',height=' + height;
	}

	var strInitParam='directories=no,status=yes,scrollbars=yes,resizable=yes,menubar=no,toolbar=no';


	exat_wndname     = exatGenRandomStr(10);
	var description = window.open('', exat_wndname, strInitParam+size);

	description.document.write('Пожалуйста, подождите. Идет загрузка...');

	if (url) {
		description.document.location=url;
	}
	description.focus();

	return description;
}
// возвращена функция с оригинальным названием для совместимости
// by Eduard Pakaln
function w(url, width, height)
{
	return exatShowWindow(url, width, height);
}

function exatGetNiceDate(dateObj)
{
	dateObj = new Date(dateObj);

	var daysOfWeek = new Array('вс', 'пн', 'вт', 'ср', 'чт', 'пт', 'сб');
	var months     = new Array('янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек');
	var day        = dateObj.getDate();

	return daysOfWeek[dateObj.getDay()] + ' ' + (day < 10 ? '0' : '') + day.toString() + ' ' + months[dateObj.getMonth()];
}

/** Упаковка-распаковка строк
 */
function str2code(str_in) {
	var tmp="";
	var i;
	var tmp_c="";
	str_in=str_in.toString();
	for(i = 0; i < str_in.length; i++) {
		tmp_c = str_in.charCodeAt(i) - 23;
		tmp += ''+(tmp_c<10 ? '0'+tmp_c : tmp_c);
	}
	var substr_len=14, out="", len_bit_tmp=0;
	while(tmp!=''){
		len_bit_tmp=tmp.length<substr_len ? tmp.length : substr_len;
		out+='-'+parseInt(tmp.substring(0, len_bit_tmp)).toString(36);
		tmp=tmp.substring(len_bit_tmp);
	}
	out='5v'+out.substring(1);
	return out;
}

// reconvert for future
function code2str(num_in) {
	var str_out = "";
	for(i = 0; i < num_in.length; i += 2) {
		num_in2 = parseInt(num_in.substr(i,[2])) + 23;
		num_in2 = unescape('%' + num_in2.toString(16));
		str_out += num_in2;
	}
	return str_out;
}


/** Преобразование кол-ва миллисекунд с 01.01.1970 в строку 'DD.MM.YYYY'
 */
function exatFromTime(time)
{
	var dateObj = new Date();
	dateObj.setTime(time);

	var day = dateObj.getDate();
	var mon = dateObj.getMonth() + 1;
	var year = dateObj.getFullYear();

	return (day < 10 ? '0' : '') + day.toString() + '.' + (mon < 10 ? '0' : '') + mon.toString() + '.' + year.toString();
}

/** Преобразование значения 'DD.MM.YYYY' в кол-во миллисекунд с 01.01.1970
 * @return кол-во миллисекунд с 01.01.1970 либо null, если ошибка в формате.
 */
function exatToTime(dd_mm_yyyy)
{
	var d = dd_mm_yyyy.split(".");

	if (d.length != 3) {
		return null;
	}

	if ((d[0] > 31) || (d[1] > 12) || (d[2].length !== 4)) {
		return null;
	}

	res = new Date(d[2], d[1] - 1, d[0])

	return res.getTime();
}


/** Преобразование значения 'DD.MM.YYYY' элемента управления ctrl
 *   в кол-во миллисекунд с 1 января 1970 года
 */
function exatCheckDate(ctrl)
{
	if (ctrl && ctrl.value.length) {
		var res = exatToTime(ctrl.value);

		if (res==null) {
			ctrl.focus();
			return false;
		}
		else {
			return res;
		}
	}

	return 0;
}


/**
 * Получение значения элемента типа select. Если установлено свойство multiple и выбраны несколько элементов списка, возвращается массив значений
 *
 * @access global
 * @param element
 * @return mixed
 */
function exatGetSelectValue(el)
{
	if (!el.nodeName || el.nodeName != 'SELECT') {
		return;
	}
	if (!el.multiple) {
		return el.value;
	}
	var result = [];
	for (var i = 0; i < el.options.length; i++) {
		if (!!el.options[i].selected) {
			result.push(el.options[i].value);
		}
	}
	if (!result.length) {
		return;
	}
	if (result.length == 1) {
		return result[0];
	}
	return result;
}


/**
 * Получение значения установлено/сброшено объекта. Объект может быть input(checkbox, hidden, text)
 * Сделано на случай когда на сайте некоторые компоненты делают скрытыми
 *
 * @access global
 * @param obj
 * @return bool or null on error
 */
function exatGetCheckedValue(obj)
{
	var checkedValue;

	if(obj.nodeName == 'INPUT'){
		switch (obj.type) {
			case 'text':
			case 'hidden':
				checkedValue = obj.value;
				break;
			case 'checkbox':
				checkedValue = obj.checked;
				break;
			default:
				checkedValue = null;
		}
	} else {
		checkedValue = null;
	}

	return checkedValue;
}


/**
 * Установка значения установлено/сброшено объекта. Объект может быть input(checkbox, hidden, text)
 * Сделано на случай когда на сайте некоторые компоненты делают скрытыми
 *
 * @access global
 * @param obj
 * @param value
 * @return bool
 */
function exatSetCheckedValue(obj, value)
{
	if (obj.nodeName == 'INPUT') {
		switch (obj.type) {
			case 'text':
			case 'hidden':
				obj.value = value;
				ret = true;
				break;
			case 'checkbox':
				obj.checked = value ? true : false;
				ret = true;
				break;
			default:
				ret  = false;
		}
	} else {
		ret = false;
	}

	return ret;
}

/**
* Возвращает числовые имена свойств или значения свойств объекта в виде строки через запятую
*
* @param useValues если false, то возвращает имена свойств, иначе, если это массив, то значения
*/
function exatJoinNumbers(obj, useValues) {
     var res = [];
     for (var prop in obj) {
          if (obj.hasOwnProperty(prop)) {
               if (useValues     && (typeof(obj[prop]) != 'boolean') && (obj[prop] == Number(obj[prop]))){
                    res.push(obj[prop]);
               } else if (prop == Number(prop)) {
                    res.push(prop);
               }
          }
     }
     return res.join(',');
}

function exatCreateGroupElement(l)
{
	var g = document.createElement('optgroup');
	g.setAttribute('label', l);
	return g;
}

function exatCreateOptionElement(v, n)
{
	var o = document.createElement('option');
	var t = document.createTextNode(n);

	o.setAttribute('value', v);
	o.appendChild(t);

	return o;
}

function exatClearCtrl(c)
{
	// чтобы очистка поменьше тормозила и визуально не выбирала элементы,
	// сначала выберем первый элемент, а затем удалим всё с конца

	if(c && c.firstChild) {
		if(c.nodeName=='SELECT') {
			/* FIX for Opera
			 * операция делает выбранные не существующее пустое поле
			 * c.selectedIndex=-1; //чтобы в multiselect сбросить выделение совсем
			 */
		}
		else {
			c.firstChild.setAttribute('selected', true);
		}
		do {
			c.removeChild(c.lastChild);
		}
		while(c.lastChild);
	}
}

/** Кроссбраузерный выбор опции в селекте
 */
function exatSelectChild(chd) {
	chd.setAttribute('selected', true);//для IE, в FF не работает
	if(!chd.selected) {
		chd.selected = true;//работает только в FF, в IE вызывает ошибку
	}
}

function exatUnselectChild(chd) {
	chd.setAttribute('selected', false);//для IE, в FF не работает
	if(chd.selected) {
		chd.selected = false;//работает только в FF, в IE вызывает ошибку
	}
}

//глобальный реестр поисковых форм на странице. Заполняется конструктором.
if(typeof(exatForms)=='undefined') {
	exatForms = [];
}

// функция для парсинга параметров GET
function getSearchParams(){
	var tmp = new Array();		// два вспомагательных
	var tmp2 = new Array();		// массива
	var param = new Array();

	var get = location.search;	// строка GET запроса
	if(get != '')
	{
		tmp = (get.substr(1)).split('&');	// разделяем переменные
		for(var i=0; i < tmp.length; i++)
		{
			tmp2 = tmp[i].split('=');		// массив param будет содержать
			param[tmp2[0]] = tmp2[1];		// пары ключ(имя переменной)->значение
		}
	}
	return param;
	
}

//
// find browser inner dimensions
//var width = 0, height = 0;
function getWindowDimensions(){
  var width = 0, height = 0;
  if(window.innerWidth){
    width = window.innerWidth;
    height = window.innerHeight;
  }
  else if(document.documentElement && document.documentElement.clientWidth){
    width = document.documentElement.clientWidth;
    height = document.documentElement.clientHeight;
  }
  else if(document.body && document.body.clientWidth){
    width = document.body.clientWidth;
    height = document.body.clientHeight;
  }
	return {'width':width, 'height':height};
}
// find browser inner dimensions End
