﻿/**
* необходимо подключить библиотеку JsHttpRequest
*
* @author Nikolay Eryomin <nikolay.eryomin@gmail.com>
*/

// функция для назначения нескольких обработчиков для одного события
function _addEventListener(element, event_name, observer, capturing) {
  if (element.addEventListener)  // the DOM2, W3C way
    element.addEventListener(event_name, observer, capturing);
  else if (element.attachEvent)  // the IE way
    element.attachEvent("on" + event_name, observer);
}

var ua = navigator.userAgent.toLowerCase(); 
//isMozilla = (typeof document.implementation != 'undefined') && (typeof document.implementation.createDocument != 'undefined') && (typeof HTMLDocument!='undefined'); 
//isIE = window.ActiveXObject ? true : false; 
isFirefox = (ua.indexOf("firefox")!=-1); 
//isSafari = (ua.indexOf("Browser.isSafari")!=-1); 
//isOpera = (typeof window.opera != 'undefined');

/**
*коструктор сласса StreetAutocomplete
*
*inputFieldId - id поля ввода
*resultBlockId - id блока резултатов
*numResult - количество выводимых результатов
*/
function StreetAutocomplete(inputFieldId, resultBlockId, resultFieldId) {
  this.timeout = 500;
  this.urlRequest = '/myhome_ajax.asp';
  this.urlAddAddress = 'myselect.asp?act=new';
  this.urlStreet = '/houses.asp?street=';
  this.numResult = 100;
  this.timeoutRequest = null;
  this.inputFieldId = inputFieldId;
  this.resultBlockId = resultBlockId;
  this.resultFieldId = resultFieldId;
  this.inputField = document.getElementById(inputFieldId);
  if (resultFieldId)
    this.resultField = document.getElementById(resultFieldId);
  this.streetAutocompleteResult = document.getElementById(resultBlockId);
  this.streetAutocompleteResult.className += " streetAutocompleteResult";
  this.resultHandler = this.showResult;

  this.timeoutRequest = null;
  this.lastRequest = "";

  this.selectItem = -1;
  this.setEvents();
  this.mouseOut = true;
  this.showAddStreet = true;
  this.onClickRedirect = true;

  this.result = null;
}

//поределение обработчиков событий
StreetAutocomplete.prototype.setEvents = function() {
  var self = this;
  _addEventListener(this.inputField, "focus", function() { self.startUpload.call(self); });
  _addEventListener(this.inputField, "blur", function() { if (self.mouseOut) self.hideAutocompleteResultBlock.call(self); });
  _addEventListener(this.inputField, "keyup", function(evn) {
    self.startUpload.call(self);
    if (!isFirefox && !isOpera) self.keyPress(evn);
  });
  _addEventListener(this.inputField, "keypress", function(evn) {
  if (isMozilla || isOpera) self.keyPress(evn)
}
  );

  _addEventListener(this.streetAutocompleteResult, "mouseover", function() { self.mouseOut = false; });
  _addEventListener(this.streetAutocompleteResult, "mouseout", function() { self.mouseOut = true; });
}

StreetAutocomplete.prototype.keyPress = function(evn) {
    if (this.result != null && this.result.length > 0) {
        if (evn.keyCode == 40) { //down
            if (this.selectItem > -2 && this.selectItem < (this.result.length - 1))
                this.selectItem++;
            else if (this.showAddStreet)
                this.selectItem = -2;
        }
        else if (evn.keyCode == 38) { //Up
            if (this.selectItem > 0)
                this.selectItem--;
            else if (this.showAddStreet && this.selectItem == -2)
                this.selectItem = this.result.length - 1;
        }
        else if (evn.keyCode == 13) { //enter
            this.onClickToItem(this.selectItem);
        }
        else
            return;

        height = 0; //this.result
        for (var i = 0; i < this.result.length; i++) {
            resultElement = this.getResultItemById(this.result[i].street_id);
            height += resultElement.offsetHeight;
            if (this.selectItem == i) {
                resultElement.className = "select";
                if (height > this.streetAutocompleteResult.offsetHeight)
                    this.streetAutocompleteResult.scrollTop = height - 50;
                else
                    this.streetAutocompleteResult.scrollTop = 0;
            }
            else {
                resultElement.className = "";
            }
        }
        
        if (this.showAddStreet) {
            resultElement = this.getResultItemById(-2);
            if (this.selectItem == -2) {
                resultElement.className = "select";
                if (height > this.streetAutocompleteResult.offsetHeight)
                    this.streetAutocompleteResult.scrollTop = height - 50;
                else
                    this.streetAutocompleteResult.scrollTop = 0;
            }
            else
                resultElement.className = "";
        }

    }
}

StreetAutocomplete.prototype.getResultItemById = function(id) {
    if (id == -2 && this.showAddStreet)
        return document.getElementById(this.resultBlockId + '_addStreet');
    else
        return document.getElementById(this.resultBlockId + '_street_id_' + id);
}

//установка таймаута до начала загрузки
StreetAutocomplete.prototype.startUpload = function() {
    if (this.lastRequest != this.getQuery()) {
        if (this.resultField)
            this.resultField.value = "";
        clearTimeout(this.timeoutRequest);
        var self = this;
        this.timeoutRequest = setTimeout(
        function() {
            self.getStreets(self.resultHandler);
        }
        , self.timeout);
    }
}

//получение строки запроса
StreetAutocomplete.prototype.getQuery = function() {
  return this.inputField.value;
}

/**
*функция получения списка улиц
*
*handler - функция обработки резулбтатов
*/
StreetAutocomplete.prototype.getStreets = function(handler) {
  clearTimeout(this.timeoutRequest);
  var query = this.getQuery();
  var req = new JsHttpRequest();
  var self = this;
  req.onreadystatechange = function() {
    if (req.readyState == 4) {
      self.lastRequest = query;
      handler.call(self, req.responseJS);
    }
  }
  req.caching = true;
  req.open("GET", this.urlRequest, true);
  req.send({ q: query, num: this.numResult });
}

/**
*функция вывода результатов
*
*result - список улиц
*/
StreetAutocomplete.prototype.showResult = function(result) {
    this.selectItem = -1;
    var output = '<ul>';
    for (i = 0; i < result.length; i++) {
        result[i].resultFieldId = this.resultBlockId + "_street_id_" + result[i].street_id;
        output += '<li id="' + result[i].resultFieldId + '">' + result[i].country_name + ', ' + result[i].city_name + ', ' + result[i].street_name + '</li>';
    }
    this.result = result;

    if (this.showAddStreet)
        output += '<li id="' + this.resultBlockId + '_addStreet" name="addStreet" style="margin-top: 20px;">Добавить новый адрес</li>';
    output += '</ul>';
    this.streetAutocompleteResult.innerHTML = output;
    this.showAutocompleteResultBlock();

    if (this.streetAutocompleteResult.childNodes.length > 0) {
        liList = this.streetAutocompleteResult.childNodes[0].childNodes;

        var self = this;
        for (var i = 0; i < liList.length; i++) {
            liList[i].onmouseover = function() {
                this.className = "select";
            }
            liList[i].onmouseout = function() {
                this.className = "";
            }
            liList[i].onclick = function() {
                self.onClickToItem(this.id);
            }
        }
    }
}

//сделать блок результатов видимым
StreetAutocomplete.prototype.showAutocompleteResultBlock = function() {
  this.streetAutocompleteResult.style.width = (this.inputField.offsetWidth - 2)  + "px";
  var match = this.streetAutocompleteResult.className.search(/visible/g);

  if (match == -1)
    this.streetAutocompleteResult.className += " visible";
}

//скрыть блок результатов
StreetAutocomplete.prototype.hideAutocompleteResultBlock = function() {
  className = this.streetAutocompleteResult.className;
  this.streetAutocompleteResult.className = className.replace(/visible/g, "");
}

/**
*обработчик onClick элемента списка улиц
*
*element - li элемент
*/
StreetAutocomplete.prototype.goToStreet = function(street_id) {
    if (!isNaN(street_id)) {
        document.location = this.urlStreet + street_id;
    }
}

StreetAutocomplete.prototype.onClickToItem = function(item_id) {
    if (item_id == (this.resultBlockId + '_addStreet') || item_id == -2) {
        document.location = this.urlAddAddress;
        return;
    }

    if (isNaN(item_id)) {
        for (i = 0; i < this.result.length; i++) {
            if (this.result[i].resultFieldId == item_id) {
                item_id = i;
                break;
            }
        }
    }
    selectedItem = this.result[item_id];
    if (selectedItem) {
        element = this.getResultItemById(selectedItem.street_id);
        if (element.textContent != undefined)
            this.inputField.value = element.textContent;
        else
            this.inputField.value = element.innerText;

        this.lastRequest = this.inputField.value;

        if (this.resultField)
            this.resultField.value = selectedItem.street_id;

        if (this.onClickRedirect)
            this.goToStreet(selectedItem.street_id);

        this.hideAutocompleteResultBlock();
    }
}