var JSPrototypeAutocomplete = Class.create({

    initialize: function(inputElement, autocompleteContainer, autocompleteElement, url) {
        this.inputElement = $(inputElement);
        this.autocompleteContainer = $(autocompleteContainer);
        this.autocompleteElement = autocompleteElement;
        this.url = url;

        this.index = 0; // не выделен ни один элемент

        this.inputElement.setAttribute('autocomplete', 'off');

        var co = this.inputElement.cumulativeOffset();
        this.autocompleteContainer.absolutize();

        this.autocompleteContainer.style.top = (co[1] + this.inputElement.getHeight() + 3) + 'px';
        this.autocompleteContainer.style.left = co[0] + 'px';
        this.autocompleteContainer.style.width = this.inputElement.getWidth() + 'px';
        this.autocompleteContainer.style.height = 'auto';

        this.autocompleteContainer.hide();

        Event.observe(this.inputElement, 'keyup', this.onKeyUp.bindAsEventListener(this));
        Event.observe(this.inputElement, 'keydown', this.onKeyDown.bindAsEventListener(this));
        Event.observe(document, 'click', this.onClick.bindAsEventListener(this));
        Event.observe(this.inputElement, 'blur', this.onBlur.bindAsEventListener(this));
    },

    onKeyDown: function (event) {
        if (event.keyCode == Event.KEY_UP) {
            this.index--;
            if (this.index < 0) {
                this.index = 0;
            }
            this._markSelected();

            Event.stop(event);
        }
        if (event.keyCode == Event.KEY_DOWN) {
            this.index++;
            var size = $$(this.autocompleteElement).size();
            if (this.index > size) {
                this.index = size;
            }
            this._markSelected();

            Event.stop(event);
        }
        if (event.keyCode == Event.KEY_TAB || event.keyCode == Event.KEY_ESC) {
            event.autocompleteContainer.hide();
        }
    },

    _markSelected: function() {
        var index = this.index - 1;
        var inputElement = this.inputElement;
        $$(this.autocompleteElement).each(function (link, i) {
            if (i == index) {
                link.addClassName('selected');
                inputElement.value = link.rel;
            } else {
                link.removeClassName('selected');
            }
        });
    },

    onKeyUp: function (event) {
        var inputElement = this.inputElement;
        var autocompleteContainer = this.autocompleteContainer;
        var autocompleteElement = this.autocompleteElement;
        var parentThis = this;

        Event.stop(event);

        if (event.keyCode == Event.KEY_UP || event.keyCode == Event.KEY_DOWN) {
            return;
        }

        var q = inputElement.getValue();
        if (q) {
            new Ajax.Request(this.url, {
                method: 'get',
                parameters: {
                'name' : q
                },
                onSuccess: function(transport) {
                    if (transport.responseText.trim()) {
                        autocompleteContainer.update(transport.responseText);
                        autocompleteContainer.show();

                        parentThis.index = 0;

                        // инициируем ссылки
                        $$(autocompleteElement).each(function (link) {
                            $(link).observe('click', function (linkClickEvent) {
                                inputElement.value = link.rel;

                                // прячем выпадающий список
                                if ($(link).rev == 'close') {
                                    autocompleteContainer.update('');
                                    autocompleteContainer.hide();
                                } else {
                                    parentThis.onKeyUp(event);
                                }

                                // если у ссылки rev=next - значит выполнить автопереход
                                if ($(link).rev != 'next') {
                                    Event.stop(linkClickEvent);
                                }
                            });
                        });
                    } else {
                        autocompleteContainer.update('');
                        autocompleteContainer.hide();
                    }
                }
            });
        } else {
            autocompleteContainer.update('');
            autocompleteContainer.hide();
        }
    },

    onClick: function (event) {
        this._clicker(
        event,
        this.autocompleteContainer,
        this.inputElement
        );
    },

    onBlur: function (event) {
        this.autocompleteContainer.hide();
    },

    // @todo: moves to js library near prototype?
    _clicker: function (event, clickBlock, clickLink) {
        if (!clickBlock) {
            return false;
        }
        var el = Event.element(event);
        if ((el != clickLink) && clickBlock.visible()) {
            if (!this._isParent(el, clickBlock)) {
                clickBlock.hide();
            }
        }
    },

    _isParent: function (child, parent) {
        if (!child || !parent) {
            return false;
        }
        while (true) {
            if (child == parent) {
                return true;
            }
            if (child.parentElement) {
                child = child.parentElement;
            } else if (child.parentNode) {
                child = child.parentNode;
            } else {
                return false;
            }
        }
    }

});
