﻿function PostAddressClass() {

	var _this = this;

	this.host = "";
	this.key = null;
	this.version = null;

	this.regionId = "@empty";
	this.districtId = "@empty";
	this.settlementId = "@empty";
	this.settlementName = "";
	this.settlementTypeId = "@empty";
	this.streetTypeId = "@empty";
	this.onDictionariesUpdated = null;

	var _getPostIndex = null;

	var _getSelectedRegionId = null;
	var _selectRegionById = null;
	var _setFocusToRegionSelector = null;
	var _fillRegionsList = null;

	var _getSelectedDistrictId = null;
	var _selectDistrictById = null;
	var _setFocusToDistrictSelector = null;
	var _fillDistrictsList = null;

	var _getSelectedSettlementId = null;
	var _selectSettlementById = null;
	var _setFocusToSettlementSelector = null;
	var _fillSettlementsList = null;
	var _switchSettlementInputTypeToSelector = null;
	var _switchSettlementInputTypeToManual = null;

	var _setFocusToHouse = null;

	var _initialized = false;
	var _updating = false;

	///////////////////
	// Private methods
	///////////////////

	function _startsWith(str, s) {
		return typeof(str) === 'string' && str.indexOf(s) === 0;
	};

	function _isEmpty(str) {
		return str == null || _startsWith(str, "@empty");
	};

	function _isDelimiter(str) {
		return str == null || _startsWith(str, "@delimiter");
	};

	function _isEmptyOrDelimiter(str) {
		return _isEmpty(str) || _isDelimiter(str);
	};

	function _isOther(str) {
		return str == null || _startsWith(str, "@other");
	};

	function _isEmptyOrDelimiterOrOther(str) {
		return _isEmpty(str) || _isDelimiter(str) || _isOther(str);
	};

	function _isEmptyOrOther(str) {
		return _isEmpty(str) || _isOther(str);
	};

	function _initPostIndex() {
		if (_postIndexInput != null) {
			_getPostIndex = function () {
				return _postIndexInput.val();
			};

			_trackTextInputChanges(_postIndexInput, function () {
				_this.onPostIndexChanged();
			});
		}
	};

	function _initRegion() {
		if (_regionSelector != null) {
			_getSelectedRegionId = function () {
				return _regionSelector.val();
			};

			_selectRegionById = function (regionId) {
				_setSelectedItem(_regionSelector, regionId);
			};

			_setFocusToRegionSelector = function () {
				_regionSelector.focus();
			};

			_fillRegionsList = function (options) {
				_fillSelect(_regionSelector, options);
			};

			_regionSelector.bind("change", function (e, isFake) {
				if (!isFake && !_updating)
					_this.onRegionChanged();
				return false;
			});
		}
	};

	function _initDistrict() {
		if (_districtSelector != null) {
			_getSelectedDistrictId = function () {
				return _districtSelector.val();
			};

			_selectDistrictById = function (districtId) {
				_setSelectedItem(_districtSelector, districtId);
			};

			_setFocusToDistrictSelector = function () {
				_districtSelector.focus();
			};

			_fillDistrictsList = function (options) {
				_fillSelect(_districtSelector, options);
			};

			_districtSelector.bind("change", function (e, isFake) {
				if (!isFake && !_updating)
					_this.onDistrictChanged();
				return false;
			});
		}
	};

	function _initSettlement() {
		if (_settlementSelector != null) {
			_getSelectedSettlementId = function () {
				return _settlementSelector.val();
			};

			_getSelectedSettlementTypeId = function () {
				return _settlementTypeSelector.val();
			};


			_selectSettlementById = function (settlementId) {
				_setSelectedItem(_settlementSelector, settlementId);
			};

			_setFocusToSettlementSelector = function () {
				_settlementSelector.focus();
			};

			_fillSettlementsList = function (options) {
				_fillSelect(_settlementSelector, options);
			};

			_switchSettlementInputTypeToSelector = function () {
				_setSelectedItem(_settlementSelector, "@empty");
				_settlementTextBox.val("");
				_setSelectedItem(_settlementTypeSelector, "@empty");
				_settlementSelectorPanel.show();
				_settlementTextBoxPanel.hide();
			};

			_switchSettlementInputTypeToManual = function () {
				_settlementSelectorPanel.hide();
				_settlementTextBox.val("");
				_settlementTextBoxPanel.show();
			};

			_settlementSelector.bind("change", function (e, isFake) {
				if (!isFake && !_updating)
					_this.onSettlementChanged();
				return false;
			});

			_settlementEnterModeSwitch.bind("click", function () {
				_switchSettlementInputTypeToSelector();
				return false;
			});

			_trackTextInputChanges(_settlementTextBox, function () {
				_this.onSettlementChangedByHand();
			});

			_settlementTextBox.result(function (e, item) {
				_loadDictionariesBySettlementId(item.value);
			});
		}
		_switchSettlementInputTypeToSelector();
	};

	function _initStreet() {
		if (_streetTextBox != null) {

			_setFocusToStreetTextBox = function () {
				_streetTextBox.focus();
			};

			_trackTextInputChanges(_streetTextBox, function () {
				_this.onStreetChanged();
			});

			_streetTextBox.result(function (e, item) {
				_setSelectedItem(_streetTypeSelector, item.type);
				_streetTextBox.val(item.name);
			});
		}
	};

	function _initHouse() {
		if (_houseInput != null) {
		    _setFocusToHouse = function() {
		        _houseInput.focus();
		    };
		}
	};

	function _fillSelect(select, data) {
		select.empty();

		$.each(data, function (index, domObject) {
			var option = $("<option></option>").attr("value", domObject.value).text(domObject.text);
			if (!domObject.selectable)
				option.attr("disabled", "disabled");
			select.append(option);
		});
	};

	function _setSelectedItem(select, selectedItem) {
		try {
			select.val(selectedItem);
			select.trigger("change", true);
		} catch (ex) {
			setTimeout("$('#" + select.attr('id') + "').val('" + selectedItem + "')", 1);
		}
	};

	function _trackTextInputChanges(input, handler) {
		input.bind("keyup", function () {
			if ($(this).val() != $(this).attr("lastValue")) {
				handler();
				$(this).attr("lastValue", $(this).val());
			}
			return false;
		});
		input.each(function () {
			$(this).attr("lastValue", $(this).val());
		});
		window.setInterval(function () {
			input.each(function () {
				if ($(this).val() != $(this).attr("lastValue")) {
					handler();
					$(this).attr("lastValue", $(this).val());
				}
			});
		}, 500);
	};

	function _rebindAll(data) {
		_fillRegionsList(data["regions"]);
		_selectRegionById(data["selectedRegion"]);

		_fillDistrictsList(data["districts"]);
		_selectDistrictById(data["selectedDistrict"]);

		_switchSettlementInputTypeToSelector();

		_fillSettlementsList(data["settlements"]);
		_selectSettlementById(data["selectedSettlement"]);

		if (data["street"] != null) {
			_streetTextBox.val(data["street"]);
			_setSelectedItem(_streetTypeSelector, data["selectedStreetType"]);
		}

		if (!_initialized) {
			_initialized = true;

			_selectSettlementById(_this.settlementId);

			if (_isOther(_this.settlementId)) {
				_switchSettlementInputTypeToManual();
				_settlementTextBox.val(_this.settlementName);
			}

			if (data["settlementTypes"] != null) {
				_fillSelect(_settlementTypeSelector, data["settlementTypes"]);
				_setSelectedItem(_settlementTypeSelector, _this.settlementTypeId);
			}

			if (data["streetTypes"] != null) {
				_fillSelect(_streetTypeSelector, data["streetTypes"]);
				_setSelectedItem(_streetTypeSelector, _this.streetTypeId);
			}
		}

		if (_this.onDictionariesUpdated != null)
			onDictionariesUpdated();

		_updating = false;
	};

	function _getDict(url) {
		if (!_updating) {
			_updating = true;
			jQuery.itcJsonp({
				url: _this.host + url,
				success: _rebindAll
			});
		}
	};

	function _loadDictionaries() {
		_getDict("/v1/postaddress/getdictionaries");
	};

	function _loadDictionariesBy(by, val) {
		_getDict("/v1/postaddress/getdictionaries/" + by + "/" + val);
	};

	function _loadDictionariesByPostIndex(postIndex) {
		_loadDictionariesBy("bypostindex", postIndex);
	};

	function _loadDictionariesByRegionId(regionId) {
		_loadDictionariesBy("byregion", regionId);
	};

	function _loadDictionariesByDistrictId(districtId) {
		_loadDictionariesBy("bydistrict", districtId);
	};

	function _loadDictionariesBySettlementId(settlementId) {
		_loadDictionariesBy("bysettlement", settlementId);
	};

	function _getSettlementAutoCompleteList(settlement) {
		settlement = settlement.substr(0, 50);
		var url = _this.host + "/v1/postaddress/autocomplete/settlements";
		if (!_isEmptyOrDelimiter(_getSelectedDistrictId())) {
			url = url + "?districtId=" + _getSelectedDistrictId();
		} else {
			url = url + "?regionId=" + _getSelectedRegionId();
		}
		url = url + "&postIndex=" + _getPostIndex();
		url = url + "&searchValue=" + escape(settlement);
		jQuery.itcJsonp({
			url: url,
			success: function (data) {
				_settlementTextBox.autocomplete(data, {
					formatItem: function (item) {
						return item.text;
					},
					width: 200
				});
			}
		});
	};

	function _getStreetAutoCompleteList(street) {
		street = street.substr(0, 50);
		var url = _this.host + "/v1/postaddress/autocomplete/streets";
		var settlementId = _getSelectedSettlementId();
		var districtId = _getSelectedDistrictId();
		var regionId = _getSelectedRegionId();
		if (!_isEmptyOrDelimiterOrOther(settlementId)) {
			url = url + "?settlementId=" + settlementId;
		} else {
			if (!_isEmptyOrDelimiter(districtId)) {
				url = url + "?districtId=" + districtId;
			} else if (!_isEmptyOrDelimiter(regionId)) {
				url = url + "?regionId=" + regionId;
			} else
				return;
			if ($.trim(_settlementTextBox.val()) === "" || _isEmptyOrDelimiter(_getSelectedSettlementTypeId()))
				return;
			url = url + "&settlementName=" + escape(_settlementTextBox.val());
			url = url + "&settlementTypeId=" + _getSelectedSettlementTypeId();
		}
		url = url + "&postIndex=" + _getPostIndex();
		url = url + "&searchValue=" + escape(street);
		jQuery.itcJsonp({
			url: url,
			success: function (data) {
				_streetTextBox.autocomplete(data, {
					formatItem: function (item) {
						return item.text;
					},
					width: 200
				});
			}
		});
	};

	///////////////////
	// Public methods
	///////////////////
	this.init = function () {
		_initialized = false;

		_initPostIndex();
		_initRegion();
		_initDistrict();
		_initSettlement();
		_initStreet();
		_initHouse();

		if (!_isEmptyOrDelimiterOrOther(_this.settlementId))
			_loadDictionariesBySettlementId(_this.settlementId);
		else if (!_isEmptyOrDelimiter(_this.districtId))
			_loadDictionariesByDistrictId(_this.districtId);
		else if (!_isEmptyOrDelimiter(_this.regionId))
			_loadDictionariesByRegionId(_this.regionId);
		else
			_loadDictionaries();
	};

	var _postIndexInput = null;
	this.bindPostIndexInput = function (postIndexInput) {
		_postIndexInput = $(postIndexInput);
	};

	this.bindGetPostIndexFunction = function (getPostIndex) {
		_getPostIndex = $(getPostIndex);
	};

	var _regionSelector = null;
	this.bindRegion = function (regionSelector) {
		_regionSelector = $(regionSelector);
	};

	var _districtSelector = null;
	this.bindDistrict = function (districtSelector) {
		_districtSelector = $(districtSelector);
	};

	var _settlementSelector = null;
	var _settlementTextBox = null;
	var _settlementTypeSelector = null;
	var _settlementSelectorPanel = null;
	var _settlementTextBoxPanel = null;
	var _settlementEnterModeSwitch = null;
	this.bindSettlement = function (settlementSelectorPanel, settlementSelector, settlementTextBoxPanel, settlementTextBox, settlementTypeSelector, settlementEnterModeSwitch) {
		_settlementSelectorPanel = $(settlementSelectorPanel);
		_settlementSelector = $(settlementSelector);
		_settlementTextBoxPanel = $(settlementTextBoxPanel);
		_settlementTextBox = $(settlementTextBox);
		_settlementTypeSelector = $(settlementTypeSelector);
		_settlementEnterModeSwitch = $(settlementEnterModeSwitch);
	};

	var _streetTextBox = null;
	var _streetTypeSelector = null;
	this.bindStreet = function (streetTextBox, streetTypeSelector) {
		_streetTextBox = $(streetTextBox);
		_streetTypeSelector = $(streetTypeSelector);
	};

	var _houseInput = null;
	this.bindHouse = function (houseInput) {
		_houseInput = $(houseInput);
	};

	// Уведомление об изменении почтового индекса – должен вызываться, чтобы уведомить JavaScript почтового адреса об изменении почтового индекса,
	// если не зарегистрировано поле почтового индекса или его значение изменяется программно.
	this.onPostIndexChanged = function () {
		var postIndex = _getPostIndex();
		postIndex = $.trim(postIndex);
		var selectedRegionId = _getSelectedRegionId();
		if (postIndex.toString().length === 6 && selectedRegionId != null && selectedRegionId.indexOf("@") === 0)
			_loadDictionariesByPostIndex(postIndex);
	};

	// Уведомление об изменении региона – должен вызываться, чтобы уведомить JavaScript почтового адреса об изменении региона,
	// если не зарегистрирован select выбора региона или его значение изменяется программно.
	this.onRegionChanged = function () {
		_switchSettlementInputTypeToSelector();
		if (!_isEmptyOrDelimiter(_getSelectedRegionId()))
			_loadDictionariesByRegionId(_getSelectedRegionId());
		else
			_loadDictionaries();
	};

	// Уведомление об изменении района – должен вызываться, чтобы уведомить JavaScript почтового адреса об изменении района,
	// если не зарегистрирован select выбора района или его значение изменяется программно.
	this.onDistrictChanged = function () {
		_switchSettlementInputTypeToSelector();
		if (!_isEmptyOrDelimiter(_getSelectedDistrictId()))
			_loadDictionariesByDistrictId(_getSelectedDistrictId());
		else
			_loadDictionariesByRegionId(_getSelectedRegionId());
	};

	// Уведомление об изменении выбранного в списке населённого пункта – должен вызываться, чтобы уведомить JavaScript почтового адреса
	// об изменении населённого пункта, выбираемого из списка, если не зарегистрирован select выбора населённого пункта или его значение изменяется программно.
	this.onSettlementChanged = function () {
		var selectedSettlementId = _getSelectedSettlementId();
		if (_isOther(selectedSettlementId)) {
			_switchSettlementInputTypeToManual();
		} else if (!_isEmptyOrDelimiter(selectedSettlementId)) {
			_loadDictionariesBySettlementId(selectedSettlementId);
		}
	};

	// Уведомление об изменении названия населённого пункта, вводимого вручную – должен вызываться, чтобы уведомить JavaScript почтового адреса
	// об изменении названия населённого пункта, вводимого вручную, если не зарегистрировано поле названия населённого пункта, вводимого вручную,
	// или его значение изменяется программно.
	this.onSettlementChangedByHand = function () {
		var selectedSettlement = _settlementTextBox.val();
		if (selectedSettlement.length == 3) {
			_getSettlementAutoCompleteList(selectedSettlement);
		}
	},

	this.onStreetChanged = function () {
		var selectedStreet = _streetTextBox.val();
		if (selectedStreet.length == 3) {
			_getStreetAutoCompleteList(selectedStreet);
		}
	};
}

var PostAddress = new PostAddressClass();
