﻿var Class = {
  create: function() {
    return function() {
      this.initialize.apply(this, arguments);
    }
  }
}

var MenuPosition = 
{
    top: 0,
    bottom: 1
};

var SuggestKeyHandler = Class.create();

SuggestKeyHandler.prototype = 
{
    initialize: function(textSuggest)
    {
        this.textSuggest = textSuggest;
        this.control = this.textSuggest.control;
        this.addHandlers();
    },
    addHandlers: function()
    {
        Event.observe(this.control, "keyup", this.keyUpHandler.bindAsEventListener(this));
        Event.observe(this.control, "keydown", this.keyDownHandler.bindAsEventListener(this));
        Event.observe(this.control, "blur", this.blurHandler.bindAsEventListener(this));
        Event.observe(this.control, "focus", this.focusHandler.bindAsEventListener(this));

//        if(this.textSuggest.browser.isOpera)
//            Event.observe(this.control, "keypress", this.keyUpHandler.bindAsEventListener(this));
		if(Prototype.Browser.Opera)
		{
			Event.observe(this.control, "keypress", this.keyUpHandler.bindAsEventListener(this));
		}
    },
    keyDownHandler: function(evt)
    {
        if(evt.keyCode == Event.KEY_UP)
        {
            this.textSuggest.moveSelectionUp();
            window.setTimeout(this.moveCaretToEnd.bind(this), 1);
        }
        else if(evt.keyCode == Event.KEY_DOWN)
        {
            this.textSuggest.moveSelectionDown();
        }
    },
    keyUpHandler: function(evt)
    {
//        if(this.control.value.length == 0 
//            && !this.textSuggest.browser.isOpera)
//            this.textSuggest.hide();
        if(this.control.value.length == 0 
            && !Prototype.Browser.Opera)
            this.textSuggest.hide();
            
        if(!this.isSpecialKey(evt))
            this.textSuggest.handleInput();
    },
    blurHandler: function(evt)
    {
		this.textSuggest.isFocused = false;
		
        if(this.textSuggest.isVisible)
            this.textSuggest.setSelectedValue();
        this.textSuggest.hide();
    },
    focusHandler: function(evt)
    {
		this.textSuggest.isFocused = true;
    },
    isSpecialKey: function(evt)
    {
        var code = evt.keyCode;
        if(code == Event.KEY_UP || code == Event.KEY_DOWN)
            return true;
        else if(code == Event.KEY_RETURN)
        {
            this.textSuggest.setSelectedValue();
            return true;
        }
        return false;
    },
    moveCaretToEnd: function()
    {
        var pos = this.control.value.length;
        if(this.control.setSelectionRange)
            this.control.setSelectionRange(pos, pos);
        else if(this.control.createTextRange)
        {
            var range = this.control.createTextRange();
            range.moveStart("character", pos);
            range.collapse();
            range.select();
        }
    }
};

var TextSuggest = Class.create();
TextSuggest.prototype =
{
    initialize: function(control, idControl, ddlCity, ddlHouse, trHouseId, defaultInputCssClass, request, options, additionalOptions) {
        this.control = $(control);
        this.idControl = $(idControl);
        this.ddlCity = $(ddlCity);
        this.ddlHouse = $(ddlHouse);
        this.trHouseId = trHouseId;
        this.defaultInputCssClass = defaultInputCssClass;
        this.handlerUrl = request.url;
        this.handlerParams = request.params;
        this.suggestions = [];
        this.isVisible = false;
        //this.browser = new Browser();
        this.setOptions(options);
        this.lastRequest = "";
        this.selectedIndex = -1;
        this.selectedValue = null;
        this.orientation = MenuPosition.bottom;
        this.hasPendingRequest = false;
        this.hasActiveRequest = false;
        this.valueCache = this.control.value;
        this.requestTimeout = 0;
        this.equalValue = null;
        this.obj = null;
        this.isFocused = false;

        this.control.form.onsubmit = this.submitHandler.bindAsEventListener(this);
        this.suggestionsMenu = this.createMenu();
        this.eventHandler = new SuggestKeyHandler(this);

        this.OnSendRequest = null;
        this.OnStreetSelected = null;

        if (additionalOptions != null) {
            this.OnSendRequest = (additionalOptions.RequestSendHandler != null) ?
					additionalOptions.RequestSendHandler : null;
            this.OnStreetSelected = (additionalOptions.StreetSelectedHandler != null) ?
					additionalOptions.StreetSelectedHandler : null;
        }

        //        if(this.browser.isIE)
        //            this.control.autocomplete = "off";
        if (Prototype.Browser.IE) {
            this.control.autocomplete = "off";
        }
    },
    submitHandler: function(evt) {

        if (this.isVisible && this.selectedIndex != -1) {
            Event.stop(evt);
            return false;
        }

        if (this.isFocused == true) {
            return false;
        }

        return true;
    },
    setOptions: function(options) {
        this.options =
        {
            menuCssClass: "suggestionsMenu",
            menuItemCssClass: "suggestionItem",
            matchTextWidth: true,
            selectedItemCssClass: "suggestionItem_Selected",
            itemCount: 20,
            selectCallback: null
        };
        Object.extend(this.options, options || {});
    },
    createMenu: function() {
        this.obj = document.createElement("div");
        this.obj.className = this.options.menuCssClass;

        // настраиваем другие свойства...
        if (this.options.matchTextWidth)
            this.obj.style.width = Element.getWidth(this.control) + "px";

        this.obj.style.position = "absolute";
        this.obj.style.display = "none";
        this.obj.style.zIndex = "110";

        //$("street").insert({ top: this.obj });

        document.body.appendChild(this.obj);

        return this.obj;
    },
    show: function() {
        if (this.suggestionsMenu != null) {
            this.offset = Position.cumulativeOffset(this.control);
            this.obj.style.left = this.offset[0] + "px";
            this.obj.style.top = (this.offset[1] + Element.getHeight(this.control)) + "px";
            this.suggestionsMenu.style.display = "block";
        }
        this.isVisible = true;
    },
    hide: function() {
        if (this.suggestionsMenu != null)
            this.suggestionsMenu.style.display = "none";

        this.selectedIndex = -1;
        this.isVisible = false;
    },
    handleInput: function() {
        var previous = this.lastRequest;
        var request = this.control.value;

        this.lastRequest = this.valueCache = request;

        if (this.lastRequest.length < 2) {
            this.hide();
            if (this.OnStreetSelected != null) {
                this.OnStreetSelected();
            }

            this.idControl.value = "-100";

            //скрываем контрол выбора домов
            $(this.trHouseId).style.display = "none";
            //очищаем список домов
            this.ddlHouse.length = 0;
            this.ddlHouse.insert('<option value="-100">---Выберите дом из списка---</option>', "bottom");

            return;
        }

        if ((this.lastRequest.length == 0) ||
			(previous.length < this.lastRequest.length)) {
            this.idControl.value = "-100";
            //this.control.className = this.defaultInputCssClass;

            //скрываем контрол выбора домов
            $(this.trHouseId).hide();
            //очищаем список домов
            this.ddlHouse.length = 0;
            this.ddlHouse.insert('<option value="-100">---Выберите дом из списка---</option>', "bottom");
        }

        if (this.lastRequest == "") {
            // вариант 1 - пустое поле
            this.hide();
        }
        else if (this.lastRequest == previous) {
            // вариант 2 - ничего не поменялось
            return;
        }
        else if (previous.length > this.lastRequest.length) {
            window.clearTimeout(this.requestTimeout);
            this.requestTimeout = window.setTimeout(this.beginRequest.bind(this), 100);
        }
        else
            this.queryProcessData();

        // window.status = "Ввод текста...";
    },
    getEqualValue: function(value) {
        for (var i = 0; i < this.suggestions.length; i++) {
            if (this.suggestions[i]["value"].toLowerCase() ==
                value.toLowerCase())
                return this.suggestions[i];
        }
        return null;
    },
    queryProcessData: function() {
        window.clearTimeout(this.requestTimeout);

        var filtered = [];
        for (var i = 0; i < this.suggestions.length; i++) {
            if (this.suggestions[i]["value"].toLowerCase().indexOf(this.lastRequest.toLowerCase()) == 0)
                filtered.push(this.suggestions[i]);
        }
        this.suggestions = filtered;
        if (this.suggestions.length < 3)
            this.requestTimeout = window.setTimeout(this.beginRequest.bind(this), 350);
        else
            this.refresh();
    },
    refresh: function() {
        window.status = "";
        this.show();
        this.selectedIndex = -1;
        this.selectedValue = null;
        this.suggestionsMenu.innerHTML = "";

        if (this.suggestions.length < 1) {
            this.hide();
            if (this.options.noMatchCallback != null)
                this.options.noMatchCallback.call(this, this);

            if (this.OnSendRequest != null) {
                this.OnSendRequest();
            }

            return;
        }
        for (var i = 0; i < this.suggestions.length; i++) {
            var item = document.createElement("div");
            item.className = this.options.menuItemCssClass;
            item.onmouseover = this.onItemMouseOver.bindAsEventListener(this, i);
            item.onclick = this.onItemClick.bindAsEventListener(this, i);

            item.innerHTML += this.suggestions[i]["value"];

            this.suggestionsMenu.appendChild(item);
        }

        if (this.OnStreetSelected != null) {
            this.OnStreetSelected();
        }
    },
    onItemMouseOver: function(evt, index) {
        var elem = Event.element(evt);
        if (elem == null)
            return;

        this.updateSelection(index);
    },
    onItemClick: function(evt, index) {
        var elem = Event.element(evt);
        if (elem == null)
            return;

        this.selectedIndex = index;
        this.updateSelection(index);
        this.setSelectedValue();
    },
    updateSelection: function(index) {
        for (var i = 0; i <
            this.suggestionsMenu.childNodes.length; i++) {
            this.suggestionsMenu.childNodes[i].className =
                this.options.menuItemCssClass;
        }
        this.selectedIndex = index;
        if (index > -1)
            this.suggestionsMenu.childNodes[index].className =
                this.options.selectedItemCssClass;
    },
    setSelectedValue: function() {
        if (this.selectedIndex > -1) {
            this.control.value = this.suggestions[this.selectedIndex]["value"].replace("<b>", "").replace("</b>", "");
            //this.control.className += " suggestionsInput";

            this.selectedValue = this.suggestions[this.selectedIndex];
            this.idControl.value = this.suggestions[this.selectedIndex]["id"];

            SelectPlace2('form', new Array(this.ddlHouse.id), 'StreetId', this.idControl, new Array(), new Array(this.trHouseId), false, new Array(), new Array());
        }

        this.hide();
        this.control.focus();

        if (this.options.selectCallback != null)
            this.options.selectCallback.call(this, this, this.selectedValue);
    },
    moveSelectionUp: function() {
        if (this.selectedIndex > -1)
            this.selectedIndex--;
        this.updateSelection(this.selectedIndex);
    },
    moveSelectionDown: function() {
        if (this.selectedIndex <
            this.suggestions.length - 1)
            this.selectedIndex++;
        this.updateSelection(this.selectedIndex);
    },
    beginRequest: function() {
        if (this.hasActiveRequest) {
            this.hasPendingRequest = true;
            window.status = "Ожидание окончания ввода...";
            return;
        }

        var params = this.handlerParams;
        if (params.length > 0)
            params += "&";

        params += "id=" + this.ddlCity.value;
        params += "&Query=" + this.lastRequest +
                  "&Count=" + this.options.itemCount;

        var args = {
            method: "post",
            parameters: params,
            onSuccess: this.endRequest.bind(this),
            onFailure: this.onError.bind(this)
        };
        this.hasActiveRequest = true;
        window.status = "Обработка запроса...";

        var ar = new Ajax.Request(this.handlerUrl, args);
    },
    onError: function(request, headers) {
        this.hasActiveRequest = false;
        this.hasPendingRequest = false;
    },
    endRequest: function(request, headers) {
        try {
            var json = request.responseText;
            var obj = {};
            eval('obj=' + json);

            this.suggestions = obj;

        }
        catch (e) {
            this.suggestions = [];
        }
        this.refresh();

        if (this.suggestions.length > 0) {
            this.selectedIndex = 0;
            this.updateSelection(this.selectedIndex);
        }

        this.hasActiveRequest = false;
        if (this.hasPendingRequest) {
            this.hasPendingRequest = false;
            this.lastRequest = this.control.value;
            this.requestTimeout = window.setTimeout(this.beginRequest.bind(this), 200);
        }
    }
};