/**
* Форма поиска
*
* @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
 * @constructor
 * @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 -- показывать только подкурорты страны первого уровня, напр. Болгария / Банско)
 *
 *   datepicker - необязательный параметр, используется как массив параметров для datepicker.
 *      Возможные параметры массивы datepicker описаны ниже:
 *   	numMonths  - количество месяцев отображаемых в календаре (datepicker). Если параметр не указан, то количесво месяцев = 2
 *
 *
 * @param host - необязательный параметр, указывающий имя HTTP-хоста, с которого будут подгружаться данные.
 *   По умолчанию равен "http://exat.ru"
 * @param params - необязательный параметр (ассоциативный массив).
 *   params[newWindowParams] - свойства нового окна (2-ой аргумент метода window.open)
 *     По умолчанию равен "resizable=yes, scrollbars=yes"
 *   params[alertLocks] - блокировка уведомлений об ошибках
 *   params[loadHotelData] - обновлять даты отправления, длительности и типы питания при выборе отеля?
 *   params[foodDependsOnHotel] - если приводимо к true, то список типов питания зависит от выбранных отелей
 *                                иначе список отелей зависит от выбранного питания. По умолчанию false.
 *   params[filtertourOperatorIds] — коды туроператоров, которые будут доступны в форме.
 *                             По умолчанию - все "предпочтительные" туроператоры.
 */
var allCountryText;
function ExatSearchForm(formId, clientId, defaults, host, params)
{
	this.clientId = clientId;
	this.formId = formId;
	this.host = (typeof(host)=='undefined') ? "http://exat.ru" : host;
	
	//предусмотрим вариант отсутствия аргумента defaults совсем
	this.defaults = (typeof(defaults)=='undefined' || defaults==null) ? {} : defaults;
	
	// устанавливаем параметры по умолчанию
	this.params = (typeof(params)!='object') ? {} : params; // список параметров должен быть объектом
	(typeof(this.params.newWindowParams)=='undefined') && (this.params.newWindowParams = 'resizable=yes, scrollbars=yes');
	(typeof(this.params.maxHotelsNumber)=='undefined') && (this.params.maxHotelsNumber=1);
	// загружать ли данные об отеле?
	(typeof(this.params.loadHotelData)=='undefined') && (this.params.loadHotelData = false);
	// контроллер типов питания зависит от выбранного отеля?
	(typeof(this.params.foodDependsOnHotel)=='undefined') && (this.params.foodDependsOnHotel = false);
	// добавлять страны без перелета к городу по умолчанию
	(typeof(this.params.mergeNullDepartureWithDefault)=='undefined') && (this.params.mergeNullDepartureWithDefault = false);
	(typeof(this.params.filterTourOperatorIds)=='undefined') && (this.params.filterTourOperatorIds = null);
	
	// питание зависит от отеля, если только данные о нем мы можем получить
	this.params.foodDependsOnHotel = (this.params.foodDependsOnHotel && this.params.loadHotelData);
	
/* Appart/1 */
	this.appartTourTypeId=8192;
/* Appart/0 */

/* Adventures/1 */
	/// XXX: путешествия/приключения временно(?) отображать для всех городов отправления
	this.adventureTourTypeId=4096;
	this.adventureWOTrip = false;
/* Adventures/0 */
	
	window.exatForms[formId] = this;

	// условия для проверки данных перед сабмитом
	this.submitConditions   = {hotelsAvailable: true};

	// константы
	this.ONE_HOUR_MS	= 1000 * 3600; //количество миллисекунд в часе
	this.ONE_DAY_MS = 1000 * 3600 * 24; //количество миллисекунд в сутках
	this.DEF_HOURS  = 4;
	this.MAX_TOUR_DAYS     = 22; // максимальное количество дней для генерации из суточных цен
	
	/* id стран с евро валютой
	 * При отсутствие на форме селекта с выбором валюты
	 */
	this.DefaultCurrency = new Array ('1000575','1005212','1000537','1000011','1000008','6002438','1001585','(1000009','1000315','1000606','1001653','1001794','1001784','1000657','1005561','1001637','1007871','1001154','1002697','1000313','1000455','1000935','1000774','1000002','1000742','1000744','1000611','1001152','1001712','1002249','1000820');


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

	//константы для определения события, предшедствовавшего вызову метода
	this.EVENT_default    = 0;
	this.EVENT_fillResort = 1;
	this.EVENT_fillHotel  = 2;
	
	this.DEPARTURE_DATA__PLACE_TOUR_TYPE__INDEX = 3;

	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()
	this.hotelData        = {};   //ассоциативный массив: код отеля => словарь данных

	/* Идентификаторы элементов управления внутри формы,
	 * которыми умеет манипулировать 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:'HotelsFoodTypeCtrl', 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 = ''; //список предпочтительных туроператоров, действующий, когда выбран пункт "все"
	this.hotelDataSemaphore = 0; //семафор для загрузки данных по отелям

	var htmlDefaults=window[this.formId + 'Defaults'];
	if(htmlDefaults)
		this.defaults=htmlDefaults;
	
	if(this.defaults.minNightsDuration==null)
		if(this.defaults.minDuration==null)
			this.defaults.minNightsDuration = 0;
		else
			this.defaults.minNightsDuration = this.defaults.minDuration;
	if(this.defaults.maxNightsDuration==null)
		if(this.defaults.maxDuration==null)
			this.defaults.maxNightsDuration = 0;
		else
			this.defaults.maxNightsDuration = this.defaults.maxDuration;
	
	// Если параметр datepicker отсутствует совсем
	if((this.defaults.datepicker == 'undefined') || (this.defaults.datepicker == null))
	{
	  this.defaults.datepicker = {};
	  if((this.defaults.datepicker.numMonths == 'undefined') ||(this.defaults.datepicker.numMonths == null)){
	    this.defaults.datepicker.numMonths = 2;
	  }
	}
	if(this.defaults.minDuration==null)       this.defaults.minDuration = 0;
	if(this.defaults.maxDuration==null)       this.defaults.maxDuration = 0;

	if(this.defaults.departureId==null)       this.defaults.departureId = 64;/* Москва */
	if(this.defaults.countryId==null)         this.defaults.countryId = 0; 
	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 = 0;
	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';
	if(this.defaults.tourOperatorIds == null) this.defaults.tourOperatorIds = this.params.filterTourOperatorIds;

	if (this.defaults.departureId == 1)       this.defaults.transportRequired = 0;

	//загрузка дополнительных скриптов в конце конструктора инициализации, иначе 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
		+((this.defaults.onlyHotel)?'&onlyHotel='+this.defaults.onlyHotel:'')
		+ '&showTourCount='
	  + this.defaults.showTourCount
		+ (this.clientId ? '&client_id=' + this.clientId : '')
		+ ((this.params.last24)?'&last=24':'')
		+ ((this.params.filterTourOperatorIds?('&tourOperatorIds='+this.params.filterTourOperatorIds):''))
	);
}


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).' +
				' В случае повторного появления ошибки ' +
				'обратитесь в службу технической поддержки');
		}
		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('resortIds');
	for(var i=0; i<ids.length; ++i) {
// 		this.resortIds[Number(ids[i])] = true; // id курорта может начинаться с нуля
		if (Number(ids[i]) > 0) {
			this.resortIds[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*this.ONE_HOUR_MS*2;
//window.status ='2-'+this.minTimestamp;
	}
	
	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.numMonths   = this.defaults.datepicker.numMonths;
	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.hotelsFoodTypeMask = this.foodTypeMask;

	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.initResortCtrl();
	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;
	}
	
	
	if (this.form.elements[this.formId + 'MinDateCtrl']) {
		this.minTime = 1;
	} else { 
		this.minTime = 0;
	}
	if (this.form.elements[this.formId + 'MaxDateCtrl']) {
		this.maxTime = 1;
	} else { 
		this.maxTime = 0;
	}
	
	this.formInitAutoAppend();
	
	this.redrawDepartureCtrl();
	this.redrawTourTypeCtrl();
	this.redrawCountryFilterCtrl();
	this.redrawCountryCtrl();
	this.redrawTransportRequiredCtrl();
	this.redrawResortCtrl();
	this.redrawResortFilterCtrl();
	this.redrawLCDCtrl();
	this.redrawCategoryCtrl();
	this.redrawFoodTypeCtrl();
	this.redrawHotelsFoodTypeCtrl();
	this.redrawAccommodationCtrl();
	this.redrawHotelCtrl();
	this.redrawCurrencyCtrl();
	this.redrawServicesCtrl();
	this.redrawTourOperatorCtrl();
	this.redrawLimitCtrl();
	this.redrawResultTypeCtrl();

}

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
}

/**
 * Зависимость пункта отправления "Без перелета" и чекбокса "Без перелета"
 **/
/**
 * селект -> чекбокс 
 **/
ExatSearchForm.prototype.Departure2TransportReq = function(){
	this.transportRequired = this.departureId!=1

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

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

/**
 *  чекбокс -> селект
 **/
ExatSearchForm.prototype.TransportReq2Departure=function(){
	var transportReq=this.form.elements[this.formId +'TransportRequiredCtrl'].checked;
	//смена в селекте места отправления
	if(transportReq){// выбрать прежний город
		if (!this.departurePrevId || this.departurePrevId == 1) {// если последний город не известен
			this.departurePrevId=this.defaultDepartureId;// то установить дефолтный
		}
		this.departureId=this.departurePrevId;// установить предыдущий город текущим
	}else{// выбрать "без перелета"
		this.departurePrevId=this.departureId;// запомнить последний город
		this.departureId=1;// установить городом отправления "без перелета"
	}
	var c = this.form.elements[this.formId +'DepartureCtrl'];
	for(var i=0;i<c.options.length;i++){
		if(c.options[i].value==this.departureId){
			exatSelectChild(c.options[i]);
// 			break;
		} else {
			exatUnselectChild(c.options[i]);
		}
	}
	this.setDepartureId(this.departureId);
	this.redrawDepartureCtrl();
	this.redrawTransportRequiredCtrl();
}

/** Подготовить массив данных поискового запроса клиентской версии
 * Каждый элемент массива - пара (имя, строка)
 * В строке может быть несколько значений через запятую
 * Можно вызывать для самостоятельной отправки запроса, не через функцию 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]
	];
	
	var ElementCtrl = 0;
	var minCtrl = this.form.elements[this.formId + 'MinDateCtrl'];
	var maxCtrl = this.form.elements[this.formId + 'MaxDateCtrl'];

	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 || Object.isEmpty(this.resortIds)) {
		q.push(['placeGroupId[]', this.countryId]);
		q.push(['placeItemId[]', this.countryId]); 
	} else if(!this.isAppartTourTypeMask()) {
		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.isAppartTourTypeMask()) {
		var resortStr = exatJoinNrefs(this.resortIds, /*isArray=*/ false);
		if(resortStr.length) {
			q.push(['placeIds[]', resortStr ]);
		}
		else {
			q.push(['placeIds[]', '0000000' ]);
		}
	}

	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(minCtrl) {
	  if( minCtrl.type == "text" ) 
	  {
	    ElementCtrl = "input";
	  }
	  if( minCtrl.type == "select-one"  )
	  {
	    ElementCtrl = "select";
	  }
	}
	
	if(maxCtrl) {
	  if( maxCtrl.type == "text" ) 
	  {
	    ElementCtrl = "input";
	  }
	  if( maxCtrl.type == "select-one"  )
	  {
	    ElementCtrl = "select";
	  }
	}
	
	if(ElementCtrl == "select"){
	  if(this.minTimestamp > 0) {
		  q.push(['minDate', exatFromTime(this.minTimestamp)]);
	  }
	  
	  if(this.maxTimestamp > 0) {
		  q.push(['maxDate', exatFromTime(this.maxTimestamp)]);
	  }
	}
	
	if(ElementCtrl == "input"){
	  if((this.minTime == 1) && (minCtrl.value != 0) && (minCtrl.value != "Все") && (minCtrl.value != "")){
		  q.push(['minDate', exatChangeTime(this.minTimestamp,"-",".")]);
	  }

	  if((this.maxTime == 1) && (maxCtrl.value != 0) && (maxCtrl.value != "Все") && (maxCtrl.value != "")){
		  q.push(['maxDate', exatChangeTime(this.maxTimestamp,"-",".")]);
	  }
	}
	*/
	if ((typeof(this.minTimestamp) == 'number') || (parseInt(this.minTimestamp) == this.minTimestamp)) {
		if (this.minTimestamp > 0) {
			q.push(['minDate', exatFromTime(this.minTimestamp)]);
		}
	} else if (typeof(this.minTimestamp) == 'string') {
		if (this.minTimestamp.search('[.]') > -1) {
			q.push(['minDate', exatChangeTime(this.minTimestamp,"-",".")]);
		}
	}
	if ((typeof(this.maxTimestamp) == 'number') || (parseInt(this.maxTimestamp) == this.maxTimestamp)) {
		if (this.maxTimestamp > 0) {
			q.push(['maxDate', exatFromTime(this.maxTimestamp)]);
		}
	} else if (typeof(this.maxTimestamp) == 'string') {
		if (this.maxTimestamp.search('[.]') > -1) {
			q.push(['maxDate', exatChangeTime(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]);
	}
	/* Appart/1 */
	if(this.isAppartTourTypeMask()){
		var hotels = exatJoinNrefs(this.hotelIds, false);
	} else {
	/* Appart/0 */
		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.tourOperatorDefIds && this.tourOperatorDefIds.length) {
		// 	список туроператоров по умолчанию
		var str = exatJoinNumbers(this.tourOperatorDefIds, /*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;
	}
	var isPost = this.isAppartTourTypeMask();
	var holder=window.document.location.protocol+'//'+window.document.location.hostname+'/';
	this.form.action = (customAction ? customAction : this.getSubmitPrefix())
		+ this.getSubmitSuffix((isPost)?[]:this.getSubmitData())
		+ (typeof(this.showTechInfoRequired) != 'undefined' && this.showTechInfoRequired ? '&show_tech_info=on' : '')
		+'&holder='+str2code(holder) //escape(window.document.location)
		+ ((this.params.last24)?'&last=24':'')
	;
	if(openNewWindow) {
		var wnd  = window.open('', this.nextNewWindowName, this.params['newWindowParams']); 
	
		wnd.document.write('Пожалуйста, подождите. Идет поиск туров...');
		wnd.focus();
		this.form.method='post';
		this.form.target = this.nextNewWindowName;
		this.nextNewWindowName = this.generateNewWindowName();
	}
	if (isPost) {
		var submitData = this.getSubmitData();
		var sumbitDataContainer = document.createElement('span');
		this.form.appendChild(sumbitDataContainer);
		for (var i in submitData) {
			var e = document.createElement('input');
			e.setAttribute('type', 'hidden');
			e.setAttribute('name', submitData[i][0]);
			e.setAttribute('value', submitData[i][1]);
			sumbitDataContainer.appendChild(e);
		}
	
	}
	this.form.submit();
	if (isPost && sumbitDataContainer) {
		this.form.removeChild(sumbitDataContainer);
	}
}

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 : '')
		+ ((this.params.last24)?'&last=24':'')
		+ ((this.params.filterTourOperatorIds?('&tourOperatorIds='+this.params.filterTourOperatorIds):''))
	);
}

/**
 * Асинхронная загрузка словарей по отелям
 */
ExatSearchForm.prototype.asyncLoadHotel = function (id) {
	this.hotelDataSemaphore++; // увеличиваем счетчик загружаемых данных
	if (this.hotelLoadingStart) this.hotelLoadingStart(id); // оповещаем о начале загрузки данных об отеле
	this.loadScript(this.host + '/touronline/?jsapp=getjs&ver=4&file=data-'
		+ this.departureId + '-' + this.countryId + '-' + id
		+ '&form_id=' + this.formId
		+ '&showTourCount=' + this.showTourCount
		+ (this.clientId ? '&client_id=' + this.clientId : '')
		+ ((this.params.last24)?'&last=24':'')
		+ ((this.params.filterTourOperatorIds?('&tourOperatorIds='+this.params.filterTourOperatorIds):''))
	);
}

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

	this.enableControls();

}

ExatSearchForm.prototype.fillHotel = function () {
	if (--this.hotelDataSemaphore <= 0) { // дожидаемся загрузки данных по всем выбранным отелям
		this.initHotelsFoodTypeCtrl(this.EVENT_fillHotel);
		this.initAccommodationCtrl(this.EVENT_fillHotel);
		this.initLCDCtrl(this.EVENT_fillHotel);
		this.initTourOperatorCtrl(this.EVENT_fillHotel);
		var m = document.getElementById(this.formId + 'HotelMessage');
		if (m) {
			m.innerHTML = '';
			if (this.checkHotelDataOnlyStop(new OrderedObjectIterator(this.hotelIds))) {
				m.innerHTML = '<span style="color:red">Для выбранного отеля доступны только стопы.</span>'
			}
		}
		if (this.hotelLoadingCompleteAll) this.hotelLoadingCompleteAll();
	}
}

/** Заполнение данных, привязанных к текущим выбранным точке отправления и стране
 * @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;
}

ExatSearchForm.prototype.setHotelParam = function(departureId, hotelId, propName, propVal) {
	var id = 'x' + departureId + '-' + hotelId;
	if (!this.hotelData[id]) {
		this.hotelData[id] = [];
	}
	this.hotelData[id][propName] = propVal;
}

ExatSearchForm.prototype.setHotelData = function(hotelId, data) {
	this.hotelData[hotelId] = data;
}

/** Получить данные свойства, учитывая выбранную точку отправления и страну
 * @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;//но не будем дожидаться загрузки
	}

	if ((propName == 'resorts') || (propName == 'apart_resorts')) {
		// эмуляция старых свойств, для совместимости со сторонним кодом
		return this.resortData[id][propName+'_ordered'].object();
	}
	return this.resortData[id][propName];
}


ExatSearchForm.prototype.prepareHotelData = function(ids) {
	//if (ids.length > this.params.maxHotelsNumber) return; // не загружаем больше указанного количества отелей
	if (this.isAppartTourTypeMask()) return; // для апартаментов информацию не загружаем
	this.hotelDataSemaphore++; //блокируем перезаполнение форм пока не загрузим и не обработаем все данные
	if ((ids instanceof Array)&&(ids.length <= this.params.maxHotelsNumber)){
		for (var i in ids) {
			if (Number(ids[i]) <= 0) {
				continue;
			}
			var id = 'x' + this.departureId + '-' + ids[i];
			if (typeof(this.hotelData[id])=='undefined') {
				this.asyncLoadHotel(ids[i]);
			}
		}
	}
	this.fillHotel();
}

ExatSearchForm.prototype.getHotelDataById = function(hotelId, propName, _default) {
	var id = 'x' + this.departureId + '-' + hotelId;
	if (typeof(this.hotelData[id]) == 'undefined') {
		return (typeof(_default)=="undefined")?null:_default;
	}
	return this.hotelData[id][propName];
}

ExatSearchForm.prototype.checkHotelDataOnlyStop = function(hotelIds) {
	if (hotelIds.keys().length > this.params.maxHotelsNumber) {
		return false;
	}
	var onlyStop = (hotelIds.keys().length > 0);
	for (var hotel = hotelIds.first(); hotelIds.valid(); hotel = hotelIds.next()) {
		if (Number(hotel) <= 0) {
			// по фортунам и апартаментам нет статистики
			onlyStop = false;
			break;
		}
		if (this.getHotelDataById(hotel, 'tourOperators') != '') {
			onlyStop = false;
			break
		}
	}
	return onlyStop;
}

ExatSearchForm.prototype.getHotelData = function (propName, eventType) {
	var hotelIds = new OrderedObjectIterator(this.hotelIds);
	eventType |= 0;
	if (
		   (this.hotelIds.length == 0)
		|| ((this.hotelIds[0]) && (
			(propName=='accommodations') || (propName=='tourOperators'))
		)		// для "фортуны" не кешируются размещения/операторы.
		|| (hotelIds.keys().length > this.params.maxHotelsNumber)
		|| (eventType != this.EVENT_fillHotel)
		//|| (eventType == this.EVENT_default)
		|| this.isAppartTourTypeMask()
		|| this.checkHotelDataOnlyStop(hotelIds)
	) {
	// в некоторых случаях(не выбраны отели, выбрано много отелей, заполняются курорты) 
	// отдаем суммарную информацию информацию по курорту
		if (propName == 'foodTypeMask') {
			var mask = 0;
			var resortMasks = new OrderedObjectIterator(this.getResortData('foodTypes'));
			for (var m=resortMasks.first(); resortMasks.valid(); m=resortMasks.next()) {
				mask |= resortMasks.item(m);
			}
			return mask;
		} 
		if (propName == 'accommodations') {
			var mask = 0;
			var resortMasks = new OrderedObjectIterator(this.getResortData('accommodations'));
			for (var m=resortMasks.first(); resortMasks.valid(); m=resortMasks.next()) {
				mask |= resortMasks.item(m);
			}
			return mask;
		}
		if (propName == 'tourOperators') {
			return false
		}
		return this.getResortData(propName);
	}
	if (propName == 'lcd') {
		var result = {};
		for (var hotel = hotelIds.first(); hotelIds.valid(); hotel = hotelIds.next()) {
			var tmp = this.getHotelDataById(hotel, 'lcd');
			if (tmp) {
				result[hotel] = tmp;
			}
		}
		return result;
	 }
	if ((propName == 'foodTypeMask')||(propName == 'accommodations')) {
		var result = 0;
		for (var hotel = hotelIds.first(); hotelIds.valid(); hotel = hotelIds.next()) {
			result |= this.getHotelDataById(hotel, propName, 0);
		}
		return result;
	}
	if (propName == 'tourOperators') {
		var result = {};
		for (var hotel = hotelIds.first(); hotelIds.valid(); hotel = hotelIds.next()) {
			operators = this.getHotelDataById(hotel, propName)
			if (operators) {
				operators = String(operators).split(',');
				for (var oid in operators) {
					result[operators[oid]] = 1;
				}
			}
		}
		result = new OrderedObjectIterator(result);
		return result.keys();
	}
	return this.getHotelDataById(hotelIds.first(), propName);
}

/** Возвратить строку символов с объёдинёнными битами дат/длительностей по курортам
 * В каждом символе используется только шесть бит
 * @param indx 0=даты, 1=длительности
 * @return строка с символами с установленными битами
 */
ExatSearchForm.prototype.getString6 = function(indx, eventType) 
{
	/* Appart/1 */
	if(this.isAppartTourTypeMask()){
		var res='';
		if(!indx){
		// date
			var pos = String.fromCharCode(63+ 127);
			for(var i=0; i<30; i++)
				res+=pos;
		}else{
		// duration
			var durations=[124,127,7,8,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
			for(var i=0; i<durations.length; i++)
				res+=String.fromCharCode(63+ durations[i]);
		}
		return res;
	}
	/* Appart/0 */

	/*
	if (this.hotelIds.length && this.params.loadHotelData && (this.hotelDataSemaphore <= 0)) {
	// this.hotelIds.length	&& this.params.loadHotelData	- вызов произошел из fillHotel или fillResort
	// this.hotelDataSemaphore <= 0							- при инициализации формы могут быть выбраны отели
	// 														  если семафор == 0 функции prepareHoteData и fillHotel
	// 														  не были выбраны или завершили свое выполнение
	*/
	if ((eventType|0) == this.EVENT_fillHotel) {
		var r = this.getHotelData('lcd', eventType);
	} else {
		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(
			   this.isAppartTourTypeMask() 
			|| allResorts 
			|| this.hotelIds[resortId]
			|| 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;
}

ExatSearchForm.prototype.redrawDepartureCtrl = function () {}

ExatSearchForm.prototype.initDepartureCtrl = function() {
	this.fillDepartureCtrl();
	this.redrawDepartureCtrl();
}

/** Заполнить список значений single select "точка отправления" и выбрать одно
 * в соответствии с this.departureId
 * @access protected
 */
ExatSearchForm.prototype.fillDepartureCtrl = 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');
		}
		if (i == 1) { // выделение "без перелета"
			o.style.fontWeight = "bold";
		}
		c.appendChild(o);
	}

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

ExatSearchForm.prototype.redrawTourTypeCtrl = function () {}

ExatSearchForm.prototype.initTourTypeCtrl = function() {
	this.fillTourTypeCtrl();
	this.redrawTourTypeCtrl();
}

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

	if(!c) {
		return 1;
	}

	exatClearCtrl(c);

	//битовая маска доступных типов туров в текущей точке отправления
	var availableTourTypes = this.departureData[this.departureId][1];
/* Adventures/1 */
	if ((this.adventureWOTrip) && (this.departureId==1)) {
		this.departureId = this.adventureWOTrip;
	}
	if (availableTourTypes & this.adventureTourTypeId) {
		this.adventureWOTrip = false;
	} else {
		availableTourTypes |= this.adventureTourTypeId; /// XXX: временно(?) добавляем путешествия/приключения
		this.adventureWOTrip = 1;
	}
/* Adventures/0 */
	var allSelected = true;
	var o = null;

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

	c.appendChild(firstElement);
/*Appart/1*/
	if(this.tourTypeData[this.appartTourTypeId]){
		o = exatCreateOptionElement(this.appartTourTypeId, this.tourTypeData[this.appartTourTypeId]);
		if (!(this.appartTourTypeId & this.tourTypeMask)) {
			this.tourTypeMask &= ~this.appartTourTypeId;
			allSelected = false;
		}
		c.appendChild(o);
//#exatSelectChild(o);
	}
/*Appart/0*/


	//в tourTypeId установлен всегда только один бит
	for(var tourTypeId in this.tourTypeData) {
		if (tourTypeId!=Number(tourTypeId) 
			|| !(tourTypeId & availableTourTypes)
			|| this.appartTourTypeId == tourTypeId /* Appart */
		) {
			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);
	}
}

ExatSearchForm.prototype.redrawCountryFilterCtrl = function () {}

ExatSearchForm.prototype.initCountryFilterCtrl = function() {
	this.fillCountryFilterCtrl();
	this.redrawCountryFilterCtrl();
}

/** Заполнить список значений для select "группа стран"
 * @access protected
 */
ExatSearchForm.prototype.fillCountryFilterCtrl = 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;
				}
			}
		}
	}
}

ExatSearchForm.prototype.redrawCountryCtrl = function () {}

ExatSearchForm.prototype.initCountryCtrl = function() {
	this.fillCountryCtrl();
	this.redrawCountryCtrl();
}

/** Заполнить список значений для single select "страна" и выбрать одно значение
 * в соответствии с this.countryId
 * @access protected
 */
ExatSearchForm.prototype.fillCountryCtrl = function()
{
/* Adventures/1 */
	if (this.adventureWOTrip > 1) {
		this.departureId = this.adventureWOTrip
	}
	if (
		(this.adventureWOTrip)
		&& (this.departureId > 1)
		&& (this.tourTypeMask == this.adventureTourTypeId)
	) {
		this.adventureWOTrip = this.departureId;
		this.departureId = 1;
	}
/* Adventures/0 */
	this.isSetDepartureToBezpereleta = false;
	var bezpereleta={};
	var c = this.form.elements[this.formId + 'CountryCtrl'];
	if(!c) {
		return;
	}
	exatClearCtrl(c);

	var f = false;

	// формируем список стран доступных из выбранного города
	if(!this.params.mergeNullDepartureWithDefault || (this.departureId!=this.defaultDepartureId) ) {
		var availableCountryIds = this.departureData[this.departureId][2];
	} else {
		var availableCountryIds 	= {};
		if(this.departureData[64])
			availableCountryIds     = this.departureData[64][2];
		var availableCountryIds2 	= {};
		if(this.departureData[1])
			availableCountryIds2	= this.departureData[1][2];

		 eval("var aa={'"+availableCountryIds.join("':1,'")+"':1}");

		 var ss='';
		 for (var i=0;i<availableCountryIds2.length;i++) {
			 if (typeof(aa[availableCountryIds2[i]])=='undefined')  {
				bezpereleta[availableCountryIds2[i]]=1;           
				ss+=','+availableCountryIds2[i];    
			}
		} 
	   var availableCountryIds = mergebyname(availableCountryIds,availableCountryIds2,this.countryData);
	}
	
	// список стран и их id, которые доступны из выбранного города и с турами выбранного типа
	var selectOptions = [];

	c.appendChild(exatCreateOptionElement(0, allCountryText?allCountryText:'выберите страну'));
	for (var i = 0; i <availableCountryIds.length; ++i) {
		var countryId = availableCountryIds[i];
		if (
			 !(this.countryData[countryId] 
			&& this.departureData[this.departureId][this.DEPARTURE_DATA__PLACE_TOUR_TYPE__INDEX][countryId] & this.tourTypeMask)
		) {
			if (
				   this.params.mergeNullDepartureWithDefault 
				&& (this.departureId==this.defaultDepartureId) 
				&& (this.departureData[1][this.DEPARTURE_DATA__PLACE_TOUR_TYPE__INDEX][countryId] & this.tourTypeMask)
			) {
				// оставляем страну в списке, 
				// но туры указанного типа только без перелета
				bezpereleta[countryId] = 1;
			} else {
				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;
			}
		}
		
		selectOptions.push({name:this.countryData[countryId][0]+(bezpereleta[countryId]?' (Без перелета)':''), id:countryId});
/*
		var o = exatCreateOptionElement(countryId, this.countryData[countryId][0]);
		
		if(countryId == this.countryId)
		{
			f = true;
			o.setAttribute('selected', 'selected');
		}

		c.appendChild(o);
*/
	}
	
	// сброс контроллера типов туров
	// в случае отсутствия стран с выбранным типом туров
	if (!selectOptions.length && (this.tourTypeMask != this.ALL_TOUR_TYPES)) {
		this.tourTypeMask = this.ALL_TOUR_TYPES;
		this.initTourTypeCtrl();
		this.initCountryCtrl();
	} else {
		for (var i=0; i<selectOptions.length; i++) {
			var o = exatCreateOptionElement(selectOptions[i]['id'], selectOptions[i]['name']);
			o.setAttribute('key',bezpereleta[selectOptions[i]['id']]?"1":"0");
			if(selectOptions[i]['id'] == this.countryId)
			{
				f = true;
				o.setAttribute('selected', 'selected');
			}
			c.appendChild(o);
		}
		//
		
		if (!f) {
			this.countryId = 0;
		}
	}

	//this.resortIds = [];
}

ExatSearchForm.prototype.redrawTransportRequiredCtrl = function () {}

ExatSearchForm.prototype.initTransportRequiredCtrl = function() {
	this.fillTransportRequiredCtrl();
	this.redrawTransportRequiredCtrl();
}

/** Установить значение checkbox "только с включённым перелётом"
 * в соответствии с this.transportRequired, поменяв перед этим при необходимости
 * значение  и this.transportRequired в соответствии с  this.countryIncTrans
 * @access protected
 */
ExatSearchForm.prototype.fillTransportRequiredCtrl = 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
			|| (this.departureId && this.departureId!= 1)
			|| (this.defaults.departureId && this.defaults.departureId!= 1)
		);
// 	}

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

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

ExatSearchForm.prototype.redrawResortCtrl = function () {}

ExatSearchForm.prototype.initResortCtrl = function() {
	this.fillResortCtrl();
	this.redrawResortCtrl();
}

/** Заполнить список значений single/multi select "курорты" и выбрать одно
 * или несколько значений в соответствии с массивом this.resortIds
 * @access protected
 */
ExatSearchForm.prototype.fillResortCtrl = 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;
	
	if(this.isAppartTourTypeMask()){
		var resortData = this.getResortData('apart_resorts');
		var resortIterator = this.getResortData('apart_resorts_ordered');
	} else {
		var resortData = this.getResortData('resorts');
		var resortIterator = this.getResortData('resorts_ordered');
	}
	if (!resortData) {
		return 0;
	}
	

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

	c.appendChild(firstElement);
	
	var filled = false;

	while(resortIterator.valid()) {
		var resortId = resortIterator.next();
		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";
		}
	} resortIterator.rewind();
	//удалим из 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;
}

ExatSearchForm.prototype.redrawResortFilterCtrl = function () {}

ExatSearchForm.prototype.initResortFilterCtrl = function() {
	this.fillResortFilterCtrl();
	this.redrawResortFilterCtrl();
}

/** Установить значение checkbox "туры только в выбранные курорты"
 * в соответствии с this.resortFilter
 * @access protected
 */
ExatSearchForm.prototype.fillResortFilterCtrl = 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;
	}
}

ExatSearchForm.prototype.redrawDurationsCtrl = function () {
}

ExatSearchForm.prototype.redrawDatesCtrl = function () {
}

ExatSearchForm.prototype.redrawLCDCtrl = function () {
	this.redrawDatesCtrl();
	this.redrawDurationsCtrl();
}

ExatSearchForm.prototype.initLCDCtrl = function(eventType) {
	this.fillLCDCtrl(eventType);
	this.redrawLCDCtrl();
}

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

	var symb;
	var tmpDate;
	var val, name;
	var enabledDays = new Array();
	var ElementCtrl = 0;

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

	// Даты
	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);
	}

	/* Выбор элемента для заполнения датами
	 * В зависимости какой элемент на форме (select, input) */
	if (cl) {
		if ( cl.type == "text" ) {
			ElementCtrl = "input";
		}
		if ( cl.type == "select-one"  ) {
			ElementCtrl = "select";
		}
	}
	
	if (ch) {
		if ( ch.type == "text" ) {
			ElementCtrl = "input";
		}
		if ( ch.type == "select-one" ) {
			ElementCtrl = "select";
		}
	}
	
	if (cl) {
		if (ElementCtrl == "select") {
			exatClearCtrl(cl);
			oCl = exatCreateOptionElement(0, '[все]');
			cl.appendChild(oCl);
		}
	  
		if (ElementCtrl == "input") {
			cl.value = 'Все';
			jQuery('#' + this.formId + 'MinDateCtrl').datepicker('destroy');
		}
	}
	if (ch) {
		if (ElementCtrl == "select") {
			exatClearCtrl(ch);
			oCh = exatCreateOptionElement(0, '[все]');
			ch.appendChild(oCh);
		}

		if (ElementCtrl == "input") {
			ch.value = 'Все';
			jQuery('#' + this.formId + 'MaxDateCtrl').datepicker('destroy');
		}
	}

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

	ddstr  = this.getString6(0, eventType);
	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 = this.exatGetDate(tmpTime);
					enDays = this.exatGetChangeDate(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) {
					  if(ElementCtrl == "select"){

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

					  }
					  if(ElementCtrl == "input"){

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

						    //oCh = ch.appendChild(exatCreateOptionElement(val, name));
						    enabledDays.push(enDays);
						    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(ElementCtrl == "input"){
		/* Сравнение выбранной даты с массивом дат курорта
		* Сортировка дат по курортам */
		function enableAllTheseDays(date) { //XXX: depends on jQuery!
			var m = date.getMonth(), d = date.getDate(), y = date.getFullYear();
			if(jQuery.inArray(d + '.' + (m+1) + '.' + y,enabledDays) != -1) {
				return [true];
			}
			return [false];
		}
		enabledDays_date = []; // преобразуем строку 11.03.2011 в дату для сравнения
		for (var date=0; date<enabledDays.length; date++) {
			var d = enabledDays[date].split('.');
			enabledDays_date.push(new Date(d[2], d[1]-1, d[0]));
		}
		function fixMinDate(date) {
			if (enabledDays.length == 0) return null;
			var res = enabledDays_date[0];
			for (var dt in enabledDays_date) {
				if (enabledDays_date[dt].getTime() <= date.getTime()) {
					res = enabledDays_date[dt];
				} else {
					break;
				}
			}
			return res;
		}
		function fixMaxDate(_date) {
			var m = _date.getMonth(), d = _date.getDate(), y = _date.getFullYear();
			var date = new Date(y, m, d);
			if (enabledDays.length == 0) return null;
			var res = enabledDays_date[enabledDays_date.length-1];
			for (var dt = enabledDays_date.length-1; dt >= 0; dt--) {
				if (enabledDays_date[dt].getTime() >= date.getTime()) {
					res = enabledDays_date[dt];
				} else {
					//break;
				}
			}
			return res;
		}
	}
		
	if (cl) {
		if (ElementCtrl == "select") {
			loSel = loSel ? loSel : cl.firstChild;
			this.minTimestamp = loSel.value;
			exatSelectChild(loSel);
		}
	 
		if (ElementCtrl == "input") {
			jQuery.datepicker.setDefaults(jQuery.datepicker.regional['ru']);
			document.getElementById('calDisable1').style.display = "none";
			//document.getElementById('calDisable2').style.display = "none";
			jQuery('#' + this.formId + 'MinDateCtrl').datepicker({
				dateFormat: 'dd.mm.yy',
				beforeShowDay: enableAllTheseDays,
				minDate: enabledDays[0],
				maxDate: enabledDays[enabledDays.length - 1],
				numberOfMonths: this.numMonths,
				showOn: "both",
				buttonImage: "http://exat.ru/touronline/img/icons/calendarEnabled.png",
				buttonImageOnly: true
			});
			if (this.minTimestamp) { //not null
				if (typeof this.minTimestamp == 'number') { //timestamp
					jQuery('#' + this.formId + 'MinDateCtrl').datepicker('setDate', fixMinDate(new Date(this.minTimestamp)));
				} else { //formated date
					var d = this.minTimestamp.toString().split('.');
					jQuery('#' + this.formId + 'MinDateCtrl').datepicker('setDate', fixMinDate(new Date(d[2], d[1]-1, d[0])));
				}
				this.minTimestamp = jQuery('#' + this.formId + 'MinDateCtrl').val();
			}
		}
	}
	if (ch) {
		if (ElementCtrl == "select") {
			hiSel = hiSel ? hiSel : ch.firstChild;
			this.maxTimestamp = hiSel.value;
			exatSelectChild(hiSel ? hiSel : ch.firstChild);
		}
		if (ElementCtrl == "input") {
			jQuery.datepicker.setDefaults(jQuery.datepicker.regional['ru']);
			document.getElementById('calDisable2').style.display = "none";
			jQuery('#' + this.formId + 'MaxDateCtrl').datepicker({
				dateFormat: 'dd.mm.yy',
				beforeShowDay: enableAllTheseDays,
				minDate: enabledDays[0],
				maxDate: enabledDays[enabledDays.length - 1],
				numberOfMonths: this.numMonths,
				showOn: "both",
				buttonImage: "http://exat.ru/touronline/img/icons/calendarEnabled.png",
				buttonImageOnly: true
			});
			if (this.maxTimestamp) {
				if (typeof this.maxTimestamp == 'number') {
					jQuery('#' + this.formId + 'MaxDateCtrl').datepicker('setDate', fixMaxDate(new Date(this.maxTimestamp)));
				} else {
					var d = this.maxTimestamp.toString().split('.');
					jQuery('#' + this.formId + 'MaxDateCtrl').datepicker('setDate', fixMaxDate(new Date(d[2], d[1]-1, d[0])));
				}
				this.maxTimestamp = jQuery('#' + this.formId + 'MaxDateCtrl').val();
			}
		}
	}
	  
	// Продолжительности

	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, eventType);

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

	if (this.transportRequired || ((ddstr.charCodeAt(0) - 63) & 0x03) == 0) {
		//если "только с перелётом" или нет туров на 1/2 дня (т.е. суточных)
		var lcdComplete = parseInt(this.getHotelData('completed', eventType));
		var lastMinDateCtrl = false;
		
		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);
						nameNum = val;
						name = nameNum;
						nightsname=(nameNum-1);
						/*
						switch((nameNum<20 ? nameNum : nameNum%10)-1){
							case 1:
								nightsname	+= ' ночь';
								break;
							case 2:
							case 3:
							case 4:
								nightsname	+= ' ночи';
								break;
							default:
								nightsname	+= ' ночей';
						}

						switch((nameNum<20 ? nameNum : nameNum%10)){
							case 1:
								name 		+= ' день';
								break;
							case 2:
							case 3:
							case 4:
								name 		+= ' дня';
								break;
							default:
								name 		+= ' дней';
						}
						*/
						/* AI попросил убрать
						var weekName='';
						if(nameNum==8)
							nightsname=name=weekName='1 неделя';
						else if(nameNum==15)
							nightsname=name=weekName='2 недели';
						else if(nameNum==22)
							nightsname=name=weekName='3 недели';
						else if(nameNum==29)
							nightsname=name=weekName='4 недели';
						*/
						if(cnl) {
							oCnl = exatCreateOptionElement(val, nightsname);
							lastMinDateCtrl = oCnl
							if(this.minNightsDuration > 0 && val <= this.minNightsDuration) {
								lonSel = oCnl;
							}
							cnl.appendChild(oCnl);
							/*
							if(weekName){
								oCnl = exatCreateOptionElement(val, weekName);
								cnl.appendChild(oCnl);
							}
							*/
						}
						
						if(cnh) {
							oCnh = exatCreateOptionElement(val, nightsname);
							if(this.maxNightsDuration > 0 && !hinSel && val >= this.maxNightsDuration) {
								hinSel = oCnh;
							}
							cnh.appendChild(oCnh);
							/*
							if(weekName){
								oCnh = exatCreateOptionElement(val, weekName);
								cnh.appendChild(oCnh);
							}
							*/
						}
						if(cl) {
							oCl = exatCreateOptionElement(val, name);
							lastMinDateCtrl = oCl
							if(this.minDuration > 0 && val <= this.minDuration) {
								loSel = oCl;
							}
							cl.appendChild(oCl);
							/*
							if(weekName){
								oCl = exatCreateOptionElement(val, weekName);
								cl.appendChild(oCl);
							}
							*/
						}
						
						if(ch) {
							oCh = exatCreateOptionElement(val, name);
							if(this.maxDuration > 0 && !hiSel && val >= this.maxDuration) {
								hiSel = oCh;
							}
							ch.appendChild(oCh);
							/*
							if(weekName){
								oCh = exatCreateOptionElement(val, weekName);
								ch.appendChild(oCh);
							}
							*/
						}
					}
				}
			}
		}
		//
		if (!lcdComplete && lastMinDateCtrl) {
			// информация по выбранным параметрам не полная и возможно отображены не все размещения
			///lastMinDateCtrl.innerHTML += ' и более'; //переделано на два запроса к мемсечу
			// отмечаем, что данная опция содержит в себе все последущие длительности, чтобы например
			// при выборе этого значения сбрасывать максимальную длительность в значение [все]
			lastMinDateCtrl.setAttribute('data-and-more', 1);
		}
	}
	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);
	}
	//var enabledDays = [];
	return true;
}

ExatSearchForm.prototype.redrawCategoryCtrl = function () {}

ExatSearchForm.prototype.initCategoryCtrl = function() {
	this.fillCategoryCtrl();
	this.redrawCategoryCtrl();
}

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

	exatClearCtrl(c);
	
	/* массив доступных категорий отелей для курорта */
	var cat_id = new Array();
	
	/* получение категорий отелей для страны */
	var prefix = '';
	if(this.isAppartTourTypeMask()){
		var prefix ='apart_';
	}
	var availableHotels = this.getResortData(prefix+'hotels');
	if (!availableHotels) {
		return;
	}
	
	var availableResorts = this.getResortData(prefix+'resorts');
	var str_len = 0;
	var id_resort = 0;
	var len = 0;
	var mass = new Array();

	/* получение id курорта */
	for(var resortId in this.resortIds) {
		if(resortId != Number(resortId)) { 
			continue;
		}
		str_len = availableResorts[resortId][4].length - 7;
		/* id курорта */
		id_resort = availableResorts[resortId][4].substr(str_len, str_len );
	}
	
	/* получение id отелей и взаимосвязь с  id курортов  */
	for (var i =0; i < availableHotels.length; ++i) {
	  
		var item = availableHotels[i];
		var countCat = false;
		var show_category = false;
		if( id_resort == 0 )
		{
		  cat_id.push(item[2]);
		}

		if(id_resort != 0){
		var availableResorts2 = this.getResortData(prefix+'resorts');
			var hotelPlace = item[6];
			
			len = availableResorts2[hotelPlace][4].length  / 7;
			for( var t = 0; t < len; t++)
			{
			      var lenght_s = (t * 7);
			      if(t != 0){
				var str1 = availableResorts2[hotelPlace][4].substr(lenght_s,7);
			      /* местоположение отеля ( id курорта) */
			      mass.push(str1);
				
			      }
			}

		}

		/* просмотр взаимосвязи курорта и категории отелей.
		* Отбор.
		* у курорта могут быть потомки: Страна - Испания. Курорт 1 -
		* Гран Канария. Курорт 2 - Лас Пальмас и т.д
		* Вложеность может быть очень большая.
		*/
		for(var r = 0; r <= mass.length; r++)
		{
			if(id_resort == mass[r])
			{
				show_category = true;
			}
		}
// 		if(mass.length > 3){
// 		  for(var r = mass.length - 2; r <= mass.length; r++)
// 		  {
// 		    if(id_resort == mass[r])
// 		    {
// 		      show_category = true;
// 		    }
// 		  }
// 		}else{
// 		  for(var r = mass.length - 2; r <= mass.length; r++)
// 		  {
// 		    if(id_resort == mass[r])
// 		    {
// 		      show_category = true;
// 		    }
// 		  }
// 		}
		
		/* Заполнение массива с категориями отелей
		 * Взависимости от взамосвязи.*/
		if(show_category){
		    if( cat_id.length == 0 )
		    {
			cat_id.push(item[2]);
		    }else{
			for( var j = 0; j < cat_id.length; j++ )
			{
			    if( item[2] == cat_id[j] )
			    {
			      countCat = true;
			    } 
			}
			
			/* если категория отеля используеться */
			if( !countCat )
			    {
			      /* добавляем категорию */
			      cat_id.push(item[2]);
			      countCat = false;
			    }
			
		    }
		}
		/* обнуление массива */
		mass = [];
		show_category = false;
	}

	
	var CAT_TEXT    = this.CAT_TEXT.concat();
	var CAT_NEW_VAL = this.CAT_NEW_VAL.concat();

	if (this.isAppartTourTypeMask()) {
		CAT_TEXT.splice(6,2);
		CAT_NEW_VAL.splice(6,2);
	}
	
	var catAvailableMask = 0;
	for (var i in cat_id) {
		catAvailableMask |= 1<<cat_id[i];
	}

	firstElement = exatCreateOptionElement(CAT_NEW_VAL[0], CAT_TEXT[0]);
	if(this.categoryMask==this.ALL_CATEGORIES || (this.categoryMask & catAvailableMask)==0) {
	// выбрано спецзначеие [все], либо выбранные категории в курорте отсутствуют
		this.categoryMask = this.ALL_CATEGORIES;
		exatSelectChild(firstElement);
	}

	c.appendChild(firstElement);

	var mask = 0;
	var mask_cat = false;

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

		var vals = 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];
			}
			
			/* Перебераем все существующие категории. 
			 * Сравниваем с категориями по курорту. 
			 */
			for( var l = 0; l < cat_id.length; l++ )
			{
			    if( vals[j] == cat_id[l] )
			    {
				mask_cat = true;
			    }
			}
		}
		
		/* добавляем категорию отеля (отображение) */
		if( mask_cat ){
		    c.appendChild(element);
		}
		mask_cat = false;

	}
	/* обнуление массива */
	cat_id = [];
}

ExatSearchForm.prototype.redrawFoodTypeCtrl = function () {}

ExatSearchForm.prototype.initFoodTypeCtrl = function() {
	this.fillFoodTypeCtrl();
	this.redrawFoodTypeCtrl();
}

/** Заполнить список значений single/multi select "типы питания",
 * в соответствии с this.foodTypeMask и доступными типами питания
 * @access protected
 */
ExatSearchForm.prototype.fillFoodTypeCtrl = function()
{
	if (this.params.foodDependsOnHotel) return;
	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;
	}
	
	var firstElementText = '[все]';
	if (this.isAppartTourTypeMask()) {
		firstElementText = '[нет]';
	}
	var firstElement = exatCreateOptionElement(this.ALL_FOOD_TYPES, firstElementText);
	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) || newMask == 0) {
	// выбраны все типы, либо выбранные типы отфильтрованы, сбрасываем на спецзначение [все]
		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;
}

ExatSearchForm.prototype.redrawHotelsFoodTypeCtrl = function () {}

ExatSearchForm.prototype.initHotelsFoodTypeCtrl = function(eventType) {
	this.fillHotelsFoodTypeCtrl(eventType);
	this.redrawHotelsFoodTypeCtrl();
}

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

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

	exatClearCtrl(c);
	
	var firstElementText = '[все]';
	if (this.isAppartTourTypeMask()) {
		firstElementText = '[не предусмотрено]';
	}
	var firstElement = exatCreateOptionElement(this.ALL_FOOD_TYPES, firstElementText);
	c.appendChild(firstElement);

	//собираем маску доступных типов питания в зависимости от выбранных типов туров
	var m = this.getHotelData('foodTypeMask', eventType);

	//ограничиваем маску только питанием, доступным в выбранных курортах
	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) || newMask == 0) {
	// выбраны все типы, либо выбранные типы отфильтрованы, сбрасываем на спецзначение [все]
		exatSelectChild(c.firstChild);
		newMask = this.ALL_FOOD_TYPES;
	}	
	else {
		var i = 0;
		for (o = c.firstChild; o; o=o.nextSibling) {
			if(newMask & (1 << (o.getAttribute('value')-1) )) {
				exatSelectChild(o);
				if (selectedCount == 1) {
					c.selectedIndex = i; // fix for select-one in webkit
				}
			}
			i++;
		}
	}
	this.foodTypeMask = newMask;
}

ExatSearchForm.prototype.redrawAccommodationCtrl = function () {}

ExatSearchForm.prototype.initAccommodationCtrl = function(eventType) {
	this.fillAccommodationCtrl(eventType);
	this.redrawAccommodationCtrl();
}

/** Заполнить список значений single select "размещение",
 * в соответствии с this.accommodationId и доступными размещениями
 * @access protected
 */
ExatSearchForm.prototype.fillAccommodationCtrl = function(eventType)
{
	eventType |= 0; // cast to integer
	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);

	/* Appart/1 */
	// для Интерхома собвстенные размещения 1-50
	if(this.isAppartTourTypeMask()){
		var isSelected=false;
		var valueDefault=2;
		for(var i=1; i<=50; i++){
			o = exatCreateOptionElement(i, i+' взр');
			if(this.accommodationHandSelectedId==i ) {
				o.setAttribute("selected","selected");
				this.accommodationId = i;
				isSelected=true;
			}else if(i==valueDefault){ //DBL
				var oDefault=o;
			}
			c.appendChild(o);
		}
		if(!isSelected){
			oDefault.setAttribute("selected","selected");
			this.accommodationId = valueDefault;
		}
		return;
	}
	/* Appart/0 */

	if (eventType == this.EVENT_fillHotel) {
		m = this.getHotelData('accommodations', eventType);
	} else {
		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;
	}
	if (m==0) {
		o = exatCreateOptionElement(this.ACC_VAL[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;
		}
	}
}

ExatSearchForm.prototype.redrawHotelCtrl = function () {}

ExatSearchForm.prototype.initHotelCtrl = function() {
	this.fillHotelCtrl();
	this.redrawHotelCtrl();
}

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

	if(!c) {
		return;
	}

	exatClearCtrl(c);
	var prefix = '';
	if(this.isAppartTourTypeMask()){
		var prefix ='apart_';
	}
	var availableHotels = this.getResortData(prefix+'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('', (this.isAppartTourTypeMask()?'[все апартаменты]':'[все отели]'));
	c.appendChild(firstElement);

	// для других типов туров (не апартаменты)  показывать значение [все апартаменты], если текущая страна имеет апартаменты
	if(!this.isAppartTourTypeMask()
		&& this.countryData[this.countryId][1] & this.appartTourTypeId
	){
		var secondElement = exatCreateOptionElement(-1*this.appartTourTypeId, '[только апартаменты]');
		c.appendChild(secondElement);
	}
	
	
	var allResortsSelected = true;
	for(var resortId in this.resortIds) {
		if(resortId != Number(resortId)) { 
			continue;
		}
		allResortsSelected = false;
		break;
	}
	
	var strHotelIds = ",";
	for (var i in this.hotelIds) { 
		if (this.hotelIds[i]) {
			strHotelIds += i+',';
		}
	}
	var unnamedGroup = {'empty': true, 'stars':null, 'nrefs':[]} // [апартаменты без названия] группируются по количеству звезд
	var o;
	var hasHotels = allResortsSelected;
	for (var i =0; i < availableHotels.length; ++i) {
		var item = availableHotels[i];
		
		if (!((1 << item[2]) & cm)) {
			continue;
		}

		if(this.isAppartTourTypeMask()){
			// ?
		} else {
			if (!(item[3] & tm) || !(item[4] & fm) || !(item[5] & am)) {
				continue;
			}
		}
		
		// если выбран конкретный курорт или курорты, проверить, находится ли отель в нем или в одном из его подкурортов
		if (!allResortsSelected && !this.resortIds[item[6]]) {
			var availableResorts = this.getResortData(prefix+'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 ((!this.isAppartTourTypeMask()) && (isNaN(val))) {//фортуна
			if (!f) {
				f = true;
				val = 0;
				o = exatCreateOptionElement(val, "[фортуна]");
			}
			else {
				continue;
			}
		} else if ((this.isAppartTourTypeMask()) && item[1] == Number(item[1])) { // без названия, только количество звезд
			// [апартменты без названия] отсортированы по количеству звезд
			if ((!unnamedGroup.empty) && (unnamedGroup.stars != item[1])) {
				// выводим группу, создаем новую
				c.appendChild(exatCreateOptionElement(unnamedGroup.nrefs.join(','), '[апартаменты без названия]'+((unnamedGroup.stars>0)?(' '+unnamedGroup.stars+'*'):'')));
				hasHotels = true;
				unnamedGroup.nrefs = [];
			}
			// добавляем апартаменты в текущую группу
			unnamedGroup.empty  = false;
			unnamedGroup.stars  = item[1];
			unnamedGroup.nrefs.push(item[0]);
		} else {
			if (!unnamedGroup.empty) {
				// показываем группу, далее апартаменты идут с названиями
				c.appendChild(exatCreateOptionElement(unnamedGroup.nrefs.join(','), '[апартаменты без названия]'+((unnamedGroup.stars>0)?(' '+unnamedGroup.stars+'*'):'')));
				hasHotels = true;
				unnamedGroup.nrefs = [];
				unnamedGroup.empty = true;
			}
			o = exatCreateOptionElement(val, item[1]);
		}
		if (o) {
			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);
			hasHotels = true;
		}
	}
		if ((!unnamedGroup.empty) && (unnamedGroup.stars != item[1])) {
			c.appendChild(exatCreateOptionElement(unnamedGroup.nrefs.join(','), '[апартаменты без названия]'+((unnamedGroup.stars>0)?(' '+unnamedGroup.stars+'*'):'')));
			hasHotels = true;
		}

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

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

	if (!hasHotels) { //не показано ни одного отеля
		if (this.isAppartTourTypeMask()) {
			firstElement.innerHTML = '[нет апартаментов выбранной категории]';
		} else {
			firstElement.innerHTML = '[нет отелей выбранной категории]';
		}
		this.submitConditions.hotelsAvailable = false;
	} else {
		this.submitConditions.hotelsAvailable = true;
	}
	if (this.params.loadHotelData) {
		var ids = new OrderedObjectIterator(this.hotelIds)
		this.prepareHotelData(ids.keys())
	}
}

ExatSearchForm.prototype.redrawCurrencyCtrl = function () {}

ExatSearchForm.prototype.initCurrencyCtrl = function() {
	this.fillCurrencyCtrl();
	this.redrawCurrencyCtrl();
}

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

	  for(var i=0; i<this.DefaultCurrency.length; i++)
	  {
	    if(this.countryId == '1002249')
	    {
	      countryRussia = true;
	      break;
	    }
	    if(this.countryId == this.DefaultCurrency[i])
	    {
	      countryAll = true;
	      break;
	    }
	  }
	  if(countryAll){this.currencyId = 2;}else{this.currencyId = 1;}
	  if(countryRussia){this.currencyId = 3;}
	  return;
	}

	exatClearCtrl(c);
	
	var o;
	var prefCur;
	//alert(this.countryId);
	
	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);
}

ExatSearchForm.prototype.redrawServicesCtrl = function () {}

ExatSearchForm.prototype.initServicesCtrl = function() {
	this.fillServicesCtrl();
	this.redrawServicesCtrl();
}

/** Заполнить список значений multi select "услуги",
 * и выбрать некоторые в соответствии с this.serviceIds
 * @access protected
 */
ExatSearchForm.prototype.fillServicesCtrl = 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);
	}
}

ExatSearchForm.prototype.redrawTourOperatorCtrl = function () {}

ExatSearchForm.prototype.initTourOperatorCtrl = function(event) {
	this.fillTourOperatorCtrl(event);
	this.redrawTourOperatorCtrl();
}

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

	var prevTo = new Array();
	var allTourOperatorsSelected = true;
	var availableTourOperators = this.getResortData('tourOperators');
	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);

	var resortIds = new OrderedObjectIterator(this.resortIds);
	resortIds = resortIds.keys();
	var hotelOperators = this.getHotelData('tourOperators', (this.hotelIds.length)?this.EVENT_fillHotel:this.EVENT_fillResort);
	for (var i = 0; i < availableTourOperators.length; ++i) {
		var item = availableTourOperators[i];
		var toId = item[0];

		if (resortIds.length) {
			if (!hasCommonElement(resortIds, item[4])) {
				continue;
			}
		}

		if (hotelOperators && hotelOperators.length>0) {
			if (!hasCommonElement([item[0]],    hotelOperators)) {
				/*                id оператора, [операторы, доступные для отеля] */
				continue;
			}
		}

		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;
}

ExatSearchForm.prototype.redrawLimitCtrl = function () {}

ExatSearchForm.prototype.initLimitCtrl = function() {
	this.fillLimitCtrl();
	this.redrawLimitCtrl();
}

/** Заполнить список значений single select "размер страницы"
 * и выбрать пункт, соответствующий this.limit
 * @access protected
 */
ExatSearchForm.prototype.fillLimitCtrl = 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.redrawResultTypeCtrl = function () {}

ExatSearchForm.prototype.initResultTypeCtrl = function() {
	this.fillResultTypeCtrl();
	this.redrawResultTypeCtrl();
}

ExatSearchForm.prototype.fillResultTypeCtrl = 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;
						}
					}
				}
			}
			*/
		}
	}
	if(this.isAppartTourTypeMask())
		this.disableSubControls();
	else{
		var elIncludeStopCtrl=this.form.elements[this.formId + 'IncludeStopCtrl'];
		if(elIncludeStopCtrl) elIncludeStopCtrl.disabled=false;
		var elShowTechInfoCtrl=this.form.elements[this.formId + 'ShowTechInfoCtrl'];
		if(elShowTechInfoCtrl){ 
			elShowTechInfoCtrl.disabled=false;
			if(elShowTechInfoCtrl.checked!=true){
				var elShowTourOperatorCtrl=this.form.elements[this.formId + 'ShowTourOperatorCtrl'];
				if(elShowTourOperatorCtrl)
					elShowTourOperatorCtrl.disabled=false;
			}
		}

	}
}

/** Проверка, что текущий тип тура апартаменты
 * @access protected
 */
ExatSearchForm.prototype.isAppartTourTypeMask = function()
{
	return this.appartTourTypeId == this.tourTypeMask;
}


/** Отключить все элементы управления формы
 * @access protected
 */
ExatSearchForm.prototype.disableControls = function(controls)
{
	if ((typeof(opera) != 'undefined') && opera && opera.version && ( (opera.version().slice(0,4) == '11.5') || (opera.version().slice(0,4) == '11.6') )) {
		// bug with opera 11.5* on Windows: drop down list stay opened.
		return;
	}
	if(controls == undefined)
		controls = this.controls;
	for (var i = 0; i < controls.length; i++) {
		var ctrl = this.form.elements[this.formId + 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;
	}
	var departureId = c.value;
	if (
		window.navigator 
		&& window.navigator.mozIsLocallyAvailable /* firefox */ 
		&& document.getElementsByClassName('exatDepartureCtrl_ui') /* jquery-ui multiselect */
	) {
		// patch for jquery-ui multiselect  and FF
		// c.value is not value of selected element
		for (var i=0; i<c.options.length; i++) {
			if (c.options[i].selected) {
				departureId = c.options[i].value;
				break;
			}
		}
	}
	this.setDepartureId(departureId);
	this.Departure2TransportReq();
}

ExatSearchForm.prototype.setDepartureId = function(departureId)
{
	this.disableControls();
	this.departureId = departureId;
/* Adventures/1 */
	if (departureId == 1) {
		// для пункта отправления "Без перелета"
		// глупо добавлять к каждой стране " (без перелета)"
		this.adventureWOTrip = false;
	}
/* Adventures/0 */
	this.resetTourOperatorEvent = true;
	this.initTourTypeCtrl();
	this.countryFilter = 0;
	this.initCountryCtrl();
	this.initCountryFilterCtrl();
	if(this.initResortCtrl() == -1) {
		this.initForm();
		return;
	}
	this.initCategoryCtrl();
	this.initFoodTypeCtrl();
	this.initHotelCtrl();
	this.initAccommodationCtrl();
	this.initHotelsFoodTypeCtrl();
	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;
	var doClear=false;
	for (var o = ctrl.firstChild; o; o = o.nextSibling) {
		if (!o.selected) {
			continue;
		}
		if(doClear){
			o.selected=false;
			continue;
		}
		if(o.getAttribute('value')==this.appartTourTypeId) {
			mask = this.appartTourTypeId;
			doClear=true;
			continue;
		}
		if(o.getAttribute('value')=='0') {
			mask = this.ALL_TOUR_TYPES;
			doClear=true;
			continue;
		}
		mask |= o.getAttribute('value');
	}
	this.setTourTypeMask(mask);
	this.initLCDCtrl();
}

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.initHotelCtrl();
	this.initAccommodationCtrl();
	this.initHotelsFoodTypeCtrl();
	this.initTourOperatorCtrl();

	this.resetTourOperatorEvent = false; 

	this.enableControls();

}

ExatSearchForm.prototype.disableSubControls = function()
{
	var controls = [
//		{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:'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:'ResultTypeCtrl', onchange:1},
		{name:'ShowTechInfoCtrl', onchange:1},
		{name:'IncludeStopCtrl', onchange:1}
	];
	this.disableControls(controls);
}

/** обработчик события 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;
	}
	if (this.params.mergeNullDepartureWithDefault) {
		if(c.options[c.options.selectedIndex].getAttribute('key') == '1') {
			this.isSetDepartureToBezpereleta = this.departureId;
			this.departureId = 1;
		} else if(this.isSetDepartureToBezpereleta) {
			this.departureId = this.isSetDepartureToBezpereleta;
			this.isSetDepartureToBezpereleta = false;
		}
	}
	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, departureId:this.departureId});
	}
	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();
	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;
	var prefix = (this.isAppartTourTypeMask())?'apart_':'';
	if (Object.isEmpty(resortIds)) {
		this.foodTypeRange      = this.ALL_FOOD_TYPES;
		this.accommodationRange = this.ALL_ACCOMMODATIONS;
	} else {
		var l = this.getResortData(prefix+'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.initCategoryCtrl();
	this.initFoodTypeCtrl();
	this.initHotelCtrl();
	this.initAccommodationCtrl();
	this.initHotelsFoodTypeCtrl();
	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();
}

ExatSearchForm.prototype.onFoodTypeCtrlChange = function() {
	if (this.params.loadHotelData && this.params.FoodDependsOnHotel) {
		return this.onHotelsFoodTypeCtrlChange()
	} else {
		return this.onResortFoodTypeCtrlChange()
	}
}

/** обработчик события onChange для single или multi select name=_FoodTypeCtrl
 */
ExatSearchForm.prototype.onResortFoodTypeCtrlChange = 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);
}

/** обработчик события onChange для single или multi select name=_HotelsFoodTypeCtrl
 */
ExatSearchForm.prototype.onHotelsFoodTypeCtrlChange = 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.setHotelsFoodTypeMask(mask);
}


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

ExatSearchForm.prototype.setHotelsFoodTypeMask = function(mask)
{
	this.disableControls();
	this.foodTypeMask = mask;
	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;
	}
	if (this.params.loadHotelData) {
		var hotelIds = new OrderedObjectIterator(this.hotelIds);
		this.prepareHotelData(hotelIds.keys());
		return;
		if (this.hotelIds.length && this.hotelIds.length<=this.params.maxHotelsNumber) {
			var hotelIds = new OrderedObjectIterator(this.hotelIds);
			this.prepareHotelData(hotelIds.keys());
		} else {
			this.fillResort();
		}
		var m = document.getElementById(this.formId + 'HotelMessage');
		if (m) {
			m.innerHTML = '';
		}
	}
}

ExatSearchForm.prototype.onResortFilterCtrlChange = function()
{
	this.onResortFilterCtrlClick();
}
ExatSearchForm.prototype.onResortFilterCtrlClick = function()
{
//window.status='123';
	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;
	this.TransportReq2Departure();
}

ExatSearchForm.prototype.onResultTypeCtrlClick = function () {}

ExatSearchForm.prototype.onMinDateCtrlChange = function()
{
	if(!this.form) {
		return;
	}
	var ElementCtrl = 0;
	var minCtrl = this.form.elements[this.formId + 'MinDateCtrl'];
	var maxCtrl = this.form.elements[this.formId + 'MaxDateCtrl'];
	
	if(minCtrl) {
	  if( minCtrl.type == "text" ) 
	  {
	    ElementCtrl = "input";
	  }
	  if( minCtrl.type == "select-one"  )
	  {
	    ElementCtrl = "select";
	  }
	}
	
	if(maxCtrl) {
	  if( maxCtrl.type == "text" ) 
	  {
	    ElementCtrl = "input";
	  }
	  if( maxCtrl.type == "select-one"  )
	  {
	    ElementCtrl = "select";
	  }
	}
	
	if(minCtrl)  {
		this.minTimestamp = minCtrl.value;
	}

	if (minCtrl) {
		var min = exatToTime(minCtrl.value);
	} else {
		var min = 0;
	}
	if (maxCtrl) {
		var max = exatToTime(maxCtrl.value);
	} else {
		var max = 0;
	}

	if(ElementCtrl == "input"){
	  if (minCtrl && maxCtrl && min > max)  {
		  maxCtrl.value = minCtrl.value;
		  this.maxTimestamp = this.minTimestamp;
	  }
	}
	
	if(ElementCtrl == "select"){
	  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 ElementCtrl = 0;
	var minCtrl = this.form.elements[this.formId + 'MinDateCtrl'];
	var maxCtrl = this.form.elements[this.formId + 'MaxDateCtrl'];
	
	if(minCtrl) {
	  if( minCtrl.type == "text" ) 
	  {
	    ElementCtrl = "input";
	  }
	  if( minCtrl.type == "select-one"  )
	  {
	    ElementCtrl = "select";
	  }
	}
	
	if(maxCtrl) {
	  if( maxCtrl.type == "text" ) 
	  {
	    ElementCtrl = "input";
	  }
	  if( maxCtrl.type == "select-one"  )
	  {
	    ElementCtrl = "select";
	  }
	}

	if(maxCtrl) {
		this.maxTimestamp = maxCtrl.value;
	}
	var min = exatToTime(minCtrl.value);
	var max = exatToTime(maxCtrl.value);
	
	if(ElementCtrl == "select"){
	    if (minCtrl && maxCtrl && maxCtrl.value != 0 && minCtrl.value > maxCtrl.value) {
		minCtrl.value = maxCtrl.value;
		this.minTimestamp = this.maxTimestamp;
	    }
	}
	if(ElementCtrl == "input"){
	    if (minCtrl && maxCtrl && maxCtrl.value != 0 && min > max) {
		    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 &&
		(typeof(minCtrl.options) != 'undefined') &&
		minCtrl.options[minCtrl.selectedIndex].getAttribute('data-and-more') &&
		(this.maxDuration != this.minDuration)
	) {
		this.maxDuration = maxCtrl.value = this.maxNightsDuration = 0;
	} else if (maxCtrl 
		&& (minCtrl.value == 0 // если пользователем сброшено значение ОТ то автоматически сбросит значение ДО
			|| parseInt(minCtrl.value) > parseInt(maxCtrl.value) && this.maxDuration != 0 // если значение ОТ оказалось больше ДО
			|| this.maxDuration == 0 // знеачение ДО не определено
		)
	) {
		this.maxDuration = maxCtrl.value = this.maxNightsDuration = this.minNightsDuration;
	}
	this.redrawDurationsCtrl();
}

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 &&
		(typeof(minCtrl.options) != 'undefined') &&
		minCtrl.options[minCtrl.selectedIndex].getAttribute('data-and-more') &&
		(this.maxNightsDuration != this.minNightsDuration)
	) {
		this.maxNightsDuration = maxCtrl.value = this.maxDuration = 0;
	} else if(maxCtrl && (this.maxNightsDuration != 0) && (minCtrl.value == 0 || parseInt(minCtrl.value) > parseInt(maxCtrl.value))) {
		this.maxNightsDuration = maxCtrl.value = this.maxDuration = this.minDuration;
	}
	this.redrawDurationsCtrl();
}

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;
	}
	this.redrawDurationsCtrl();
}

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;
	}
	this.redrawDurationsCtrl();
}

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");
	}
	
	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;
	}

	if (!this.submitConditions.hotelsAvailable) {
		alert('Для указанных условий поиска нет доступных отелей');
		return false;
	}

	c = this.form.elements[this.formId+'TourOperatorCtrl'];
	if (c && c.length == 0 
		&& /*Appart*/ this.tourTypeMask != this.appartTourTypeId
	) {
		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()
{
	/* Appart/1 */
	// в апартаментах размещение детей отдельно не учитывается
	if(this.isAppartTourTypeMask())
		return;
	/* Appart/0 */

	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);
}

/* возвращает дату в формате 
 * ср 02 фев */
ExatSearchForm.prototype.exatGetDate = function(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()];
}

/* возвращает дату в формате
 * 2.2.2011 
 * Используется для сортировки дат курорта (datepicker) */

ExatSearchForm.prototype.exatGetChangeDate = function(dateObj)
{
	dateObj = new Date(dateObj);

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

/* кодирование base64 */
function base64_encode( data ) {   
  
  data = escape(data);   
  var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  var o1, o2, o3, h1, h2, h3, h4, bits, i=0, enc='';
	    
  do { // pack three octets into four hexets
    o1 = data.charCodeAt(i++);
    o2 = data.charCodeAt(i++);
    o3 = data.charCodeAt(i++);
	  
    bits = o1<<16 | o2<<8 | o3;
	  
    h1 = bits>>18 & 0x3f;
    h2 = bits>>12 & 0x3f;
    h3 = bits>>6 & 0x3f;
    h4 = bits & 0x3f;
	  
    // use hexets to index into b64, and append result to encoded string
    enc += b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
  } while (i < data.length);
	  
  switch( data.length % 3 ){
    case 1:
      enc = enc.slice(0, -2) + '==';
    break;
    case 2:
      enc = enc.slice(0, -1) + '=';
    break;
  }
  return enc;
} 

/* декодирование base64 */
function base64_decode( data ) {  
  var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  var o1, o2, o3, h1, h2, h3, h4, bits, i=0, enc='';
	  
  do { 
    h1 = b64.indexOf(data.charAt(i++));
    h2 = b64.indexOf(data.charAt(i++));
    h3 = b64.indexOf(data.charAt(i++));
    h4 = b64.indexOf(data.charAt(i++));
	  
    bits = h1<<18 | h2<<12 | h3<<6 | h4;
	  
    o1 = bits>>16 & 0xff;
    o2 = bits>>8 & 0xff;
    o3 = bits & 0xff;
	  
    if (h3 == 64)      enc += String.fromCharCode(o1);
    else if (h4 == 64) enc += String.fromCharCode(o1, o2);
    else               enc += String.fromCharCode(o1, o2, o3);
  } while (i < data.length);
	  
  return unescape(enc);
}    

/** Упаковка-распаковка строк
 */
function str2code(str_in) {
	//str_in = "qwerty";
	/*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);*/
	out = base64_encode(str_in);
	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();
}

function exatChangeTime(txt,cut_str,paste_str)
{
  var f=0;
  var ht='';
  ht = ht + txt;
  f=ht.indexOf(cut_str);
    while (f!=-1){
    //цикл для вырезания всех имеющихся подстрок
      f=ht.indexOf(cut_str);
      if (f>0){
	ht = ht.substr(0,f) + paste_str + ht.substr(f+cut_str.length);
      }
    }
    return ht
}


/** Преобразование значения '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 el 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)
		return;
	else 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(',');
}

/**
* Возвращает идентификаторы отелей/апартаментов в виде строки через запятую
*
* @param useValues если false, то возвращает имена свойств, иначе, если это массив, то значения
*/
function exatJoinNrefs(obj, useValues) {
     var res = [];
     for (var prop in obj) {
          if (obj.hasOwnProperty(prop)) {
               if (useValues     && (typeof(obj[prop]) != 'boolean')){
                    res.push(obj[prop]);
               } else {
                    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 не работает
	chd.removeAttribute('selected');//для 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

//получение количества полей объекта
Object.size = function(obj) {
	var size = 0, key;
	for (key in obj) {
		if (obj.hasOwnProperty(key)) size++;
	}
	return size;
};

// является ли объект пустым
Object.isEmpty = function (obj) {
	for (var key in obj) {
		if (obj.hasOwnProperty(key)) {
			return false
		}
	}
	return true
}

/**
 * итератор объекта obj в указанном порядке order
 *
 * @costructor
 * @param obj   Object итерируемый объект
 * @param order Array  порядок итерирования
 */
function OrderedObjectIterator(obj, order) {
	if (!order) {
		order = []
		for (var i in obj) {
			if (obj.hasOwnProperty(i)) order.push(i);
		}
	}
	var current = 0;
	this.rewind = function () {
		current = 0;
	}
	this.next = function () {
		return order[current++]
	}
	this.valid = function () {
		return order.length>=current
	}
	this.item = function(index) {
		return obj[index];
	}
	this.keys = function() {
		return order;
	}
	this.object = function() {
		return obj;
	}
	this.first = function() {
		this.rewind();
		return this.next();
	}
}

/**
 * Create ordered dictionary
 * 
 * @param a array [ [key,value], ... ] (like argument of function dict() in python)
 * @returns OrderedObjectIterator
 */
function ordDict(a) {
	var obj = {};
	var order = [];
	for (var i=0; i<a.length; i++) {
		order.push(a[i][0]);
		obj[a[i][0]] = a[i][1];
	}
	return new OrderedObjectIterator(obj, order);
}

function hasCommonElement(a, b) {
	for (var i in a) {
		for (var j in b) {
			if (a[i]==b[j]) {
				return true;
			}
		}
	}
	return false;
}

function mergebyname(a1,a2,cData) {
	var n1,n2,v1,v2,i1=0,i2=0,res 		= []; 
	v1 		= (i1<a1.length)?a1[i1++]:null;
	v2 		= (i2<a2.length)?a2[i2++]:null;
	while(true) {
		if(!v1 && !v2) {
				break;  
		} else if (!v1 && v2) {
			res.push(v2);
			v2 		= (i2<a2.length)?a2[i2++]:null;
		} else if (v1 && !v2) {
			res.push(v1);
			v1 		= (i1<a1.length)?a1[i1++]:null;
		} else {
			n1=n2=0;
			if(cData[v1])
				n1 		= cData[v1][0];
			if(cData[v2])
				n2 		= cData[v2][0];
			if(n1<n2) {
				res.push(v1);
				v1 	= (i1<a1.length)?a1[i1++]:null;
			} else if (n2<n1) { 
				res.push(v2);
				v2 	= (i2<a2.length)?a2[i2++]:null;
			} else {
				res.push(v2);
				v1 	= (i1<a1.length)?a1[i1++]:null;
				v2 	= (i2<a2.length)?a2[i2++]:null;
			}
		}
	}
	return res;
}

function unique(arrayName) {
	var newArray		= new Array();
	label:for(var i=0; i<arrayName.length;i++ ) {
		for(var j=0; j<newArray.length;j++ ) {
			if(newArray[j]==arrayName[i]) 
					continue label;
		}
		newArray[newArray.length] = arrayName[i];
	}
	return newArray;
}


// DEBUGGING

/// XXX: геттер и сеттер для adventureWOTrip
// ExatSearchForm.prototype.__defineGetter__("adventureWOTrip", function(){
// 	return this.__adventureWOTrip;
// });
// ExatSearchForm.prototype.__defineSetter__("adventureWOTrip", function(val){
// 	console && console.log('set adventureWOTrip:', val);
// 	console && console.trace();
// 	this.__adventureWOTrip = val;
// });

/* end of common.js, do not remove this line */

