/*
 *
 *  Ajax Autofomplete for Prototype, version 1.0.1
 *  (c) 2008 Tomas Kirda
 *
 *  Ajax Autofomplete for Prototype is freely distributable under the terms of an MIT-style license.
 *  For details, see the web site: http://www.devbridge.com/projects/autocomplete/
 *
 */

var Autocomplete = function(el, options) {
this.ctry = $('ctl00_ContentPlaceHolder1_Drp_CountryList');
    this.el = $(el);
    this.id = this.el.identify();
    this.el.setAttribute('autocomplete', 'off');
    this.suggestions = [];
    this.data = [];
    this.badQueries = [];
    this.selectedIndex = -1;
    this.currentValue = this.el.value;
    this.currentCountryCode = this.ctry[this.ctry.selectedIndex].value;
    this.intervalId = 0;
    this.cachedResponse = [];
    this.instanceId = null;
    this.onChangeInterval = null;
    this.ignoreValueChange = false;
    this.serviceUrl = options.serviceUrl;
    this.options = {
        autoSubmit: false,
        minChars: 1,
        maxHeight: 300,
        deferRequestBy: 0,
        width: 0
    };
    if (options) { Object.extend(this.options, options); }
    if (Autocomplete.isDomLoaded) {
        this.initialize();
    } else {
        Event.observe(document, 'dom:loaded', this.initialize.bind(this), false);
    }
};

Autocomplete.instances = [];
Autocomplete.isDomLoaded = false;

Autocomplete.getInstance = function(id){
  var instances = Autocomplete.instances;
  var i = instances.length;
  while(i--){ if(instances[i].id === id){ return instances[i]; }}
};

Autocomplete.highlight = function(value, re){
  return value.replace(re, function(match){ return '<strong>' + match + '<\/strong>' });
};

Autocomplete.prototype = {

    killerFn: null,

    initialize: function() {
        this.killerFn = function(e) {
            if (!$(Event.element(e)).up('.autocomplete')) {
                this.killSuggestions();
                this.disableKillerFn();
            }
        } .bindAsEventListener(this);

        if (!this.options.width) { this.options.width = this.el.getWidth(); }

        var div = new Element('div', { style: 'position:absolute;' });
        div.update('<div class="autocomplete-w1"><div class="autocomplete-w1"><div class="autocomplete" id="Autocomplete_' + this.id + '" style="display:none; width:' + this.options.width + 'px;"></div></div></div>');
        document.body.appendChild(div);

        this.mainContainerId = div.identify();
        this.container = $('Autocomplete_' + this.id);
        this.fixPosition();

        Event.observe(this.el, 'keydown', this.onKeyPress.bind(this));
        Event.observe(this.el, 'keyup', this.onKeyUp.bind(this));
        Event.observe(this.el, 'blur', this.enableKillerFn.bind(this));
        Event.observe(this.el, 'focus', this.fixPosition.bind(this));
        this.container.setStyle({ maxHeight: this.options.maxHeight + 'px' });
        this.instanceId = Autocomplete.instances.push(this) - 1;
    },

    fixPosition: function() {
        var offset = this.el.cumulativeOffset();
        $(this.mainContainerId).setStyle({ top: (offset.top + this.el.getHeight()) + 'px', left: offset.left + 'px' });
    },

    enableKillerFn: function() {
        Event.observe(document.body, 'click', this.killerFn);
    },

    disableKillerFn: function() {
        Event.stopObserving(document.body, 'click', this.killerFn);
    },

    killSuggestions: function() {
        this.stopKillSuggestions();
        this.intervalId = window.setInterval(function() { this.hide(); this.stopKillSuggestions(); } .bind(this), 300);
    },

    stopKillSuggestions: function() {
        window.clearInterval(this.intervalId);
    },

    onKeyPress: function(e) {
        if (!this.enabled) { return; }
        // return will exit the function
        // and event will not fire
        switch (e.keyCode) {
            case Event.KEY_ESC:
                this.el.value = this.currentValue;
                this.hide();
                break;
            case Event.KEY_TAB:
            case Event.KEY_RETURN:
                if (this.selectedIndex === -1) {
                    this.hide();
                    return;
                }
                this.select(this.selectedIndex);
                if (e.keyCode === Event.KEY_TAB) { return; }
                break;
            case Event.KEY_UP:
                this.moveUp();
                break;
            case Event.KEY_DOWN:
                this.moveDown();
                break;
            default:
                return;
        }
        Event.stop(e);
    },

    onKeyUp: function(e) {
        switch (e.keyCode) {
            case Event.KEY_UP:
            case Event.KEY_DOWN:
                return;
        }
        clearInterval(this.onChangeInterval);
        if (this.currentValue !== this.el.value) {
            if (this.deferRequestBy > 0) {
                // Defer lookup in case when value changes very quickly:
                this.onChangeInterval = setInterval((function() {
                    this.onValueChange();
                }).bind(this), this.deferRequestBy);
            } else {
                this.onValueChange();
            }
        }
    },

    onValueChange: function() {
        clearInterval(this.onChangeInterval);
        
        this.currentValue = this.el.value;
        this.currentCountryCode = this.ctry[this.ctry.selectedIndex].value;
        this.selectedIndex = -1;
        if (this.ignoreValueChange) {
            this.ignoreValueChange = false;
            return;
        }
        if (this.currentValue === '' || this.currentValue.length < this.options.minChars) {
            this.hide();
        } else {
        this.el.setAttribute("class", "busy");
            this.getSuggestions();
        }
    },

    getSuggestions: function() {
        var cr = this.cachedResponse[this.currentValue];
        if (cr && Object.isArray(cr.suggestions)) {
            this.suggestions = cr.suggestions;
            this.data = cr.data;
            this.suggest();
        } else if (!this.isBadQuery(this.currentValue)) {
            new Ajax.Request(this.serviceUrl, {
                parameters: { query: this.currentValue, ctry: this.currentCountryCode },
                onComplete: this.processResponse.bind(this),
                method: 'get'
            });
        }
    },

    isBadQuery: function(q) {
        var i = this.badQueries.length;
        while (i--) {
            if (q.indexOf(this.badQueries[i]) === 0) { return true; }
        }
        return false;
    },

    hide: function() {
        this.enabled = false;
        this.selectedIndex = -1;
        this.container.hide();
        this.el.setAttribute("class", "form");
    },

    suggest: function() {
    this.el.setAttribute("class", "form");
        if (this.suggestions.length === 0) {
            this.hide();
            return;
        }
        var content = [];
        var re = new RegExp('\\b' + this.currentValue.match(/\w+/g).join('|\\b'), 'gi');
        this.suggestions.each(function(value, i) {
            content.push((this.selectedIndex === i ? '<div class="selected"' : '<div'), ' title="', value, '" onclick="Autocomplete.instances[', this.instanceId, '].select(', i, ');" onmouseover="Autocomplete.instances[', this.instanceId, '].activate(', i, ');">', Autocomplete.highlight(value, re), '</div>');
        } .bind(this));
        this.enabled = true;
        this.container.update(content.join('')).show();
    },

    processResponse: function(xhr) {
        var response;
        try {
            response = xhr.responseText.evalJSON();
            if (!Object.isArray(response.data)) { response.data = []; }
        } catch (err) { return; }
        this.suggestions = response.suggestions;
        this.data = response.data;
        this.cachedResponse[response.query] = response.suggestions;
        if (response.suggestions.length === 0) { this.badQueries.push(response.query); }
        if (response.query === this.currentValue) { this.suggest(); }
    },

    activate: function(index) {
        var divs = this.container.childNodes;
        var activeItem;
        // Clear previous selection:
        if (this.selectedIndex !== -1 && divs.length > this.selectedIndex) {
            divs[this.selectedIndex].className = '';
        }
        this.selectedIndex = index;
        if (this.selectedIndex !== -1 && divs.length > this.selectedIndex) {
            activeItem = divs[this.selectedIndex]
            activeItem.className = 'selected';
        }
        return activeItem;
    },

    deactivate: function(div, index) {
        div.className = '';
        if (this.selectedIndex === index) { this.selectedIndex = -1; }
    },

    select: function(i) {
        var selectedValue = this.suggestions[i];
        if (selectedValue) {
            this.el.value = selectedValue;
            if (this.options.autoSubmit && this.el.form) {
                this.el.form.submit();
            }
            this.ignoreValueChange = true;
            this.hide();
            this.onSelect(i);
        }
    },

    moveUp: function() {
        if (this.selectedIndex === -1) { return; }
        if (this.selectedIndex === 0) {
            this.container.childNodes[0].className = '';
            this.selectedIndex = -1;
            this.el.value = this.currentValue;
            return;
        }
        this.adjustScroll(this.selectedIndex - 1);
    },

    moveDown: function() {
        if (this.selectedIndex === (this.suggestions.length - 1)) { return; }
        this.adjustScroll(this.selectedIndex + 1);
    },

    adjustScroll: function(i) {
        var container = this.container;
        var activeItem = this.activate(i);
        var offsetTop = activeItem.offsetTop;
        var upperBound = container.scrollTop;
        var lowerBound = upperBound + this.options.maxHeight - 25;
        if (offsetTop < upperBound) {
            container.scrollTop = offsetTop;
        } else if (offsetTop > lowerBound) {
            container.scrollTop = offsetTop - this.options.maxHeight + 25;
        }
        this.el.value = this.suggestions[i];
    },

    onSelect: function(i) {
        (this.options.onSelect || Prototype.emptyFunction)(this.suggestions[i], this.data[i]);
    }

};

Event.observe(document, 'dom:loaded', function(){ Autocomplete.isDomLoaded = true; }, false);
