/*
 *
 *  Ajax Autocomplete for Prototype, version 1.0.4
 *  (c) 2010 Tomas Kirda
 *
 *  Ajax Autocomplete 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(id, el, service, options){
    this.el = $(el);
    this.id = this.el.identify();
    this.el.setAttribute('autocomplete','off');
    this.result = [];
    this.badQueries = [];
    this.selectedIndex = -1;
    this.currentValue = this.el.value;
    this.intervalId = 0;
    this.cachedResponse = [];
    this.instanceId = null;
    this.onChangeInterval = null;
    this.ignoreValueChange = false;
    this.serviceUrl = options.serviceUrl;
    this.tileId = id;
    this.service = service;
    this.options = {
        autoSubmit:false,
        minChars:3,
        maxHeight:300,
        deferRequestBy:0,
        width:0,
        container:null
    };
    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 '<span class="matched">' + match + '</span>'
    });
};

Autocomplete.prototype = {

    killerFn: null,

    initialize: function() {
        var me = this;
        this.killerFn = function(e) {
            if (!$(Event.element(e)).up('.autocomplete')) {
                me.killSuggestions();
                me.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-w2"><div class="autocomplete" id="Autocomplete_' + this.id + '" style="display:none; width:' + this.options.width + 'px;"></div></div></div>');

        this.options.container = $(this.options.container);
        if (this.options.container) {
            this.options.container.appendChild(div);
            this.fixPosition = function() { };
        } else {
            document.body.appendChild(div);
        }

        this.mainContainerId = div.identify();
        this.container = $('Autocomplete_' + this.id);
        this.fixPosition();
    
        Event.observe(this.el, window.opera ? 'keypress':'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'
        });
        this.el.select();
    },

    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.options.deferRequestBy > 0) {
                // Defer lookup in case when value changes very quickly:
                this.onChangeInterval = setInterval((function() {
                    this.onValueChange();
                }).bind(this), this.options.deferRequestBy);
            } else {
                this.onValueChange();
            }
        }
    },

    onValueChange: function() {
        clearInterval(this.onChangeInterval);
        this.currentValue = this.el.value;
        this.selectedIndex = -1;
        if (this.ignoreValueChange) {
            this.ignoreValueChange = false;
            return;
        }
        if (this.currentValue === '' || this.currentValue.length < this.options.minChars) {
            this.hide();
        } else {
            this.getSuggestions();
        }
    },

    getSuggestions: function() {
        var cr = this.cachedResponse[this.currentValue];
        if (cr && Object.isArray(cr.suggestions)) {
            this.result = cr.result;
            this.suggest();
        } else if (!this.isBadQuery(this.currentValue)) {
            new Ajax.Request(this.serviceUrl, {
                parameters: {
                    service: this.service,
                    response: 'json',
                    needle: this.currentValue
                },
                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();
    },

    suggest: function() {
        if (this.result.length === 0) {
            this.hide();
            return;
        }
        var content = [];
        var re = new RegExp('\\b' + this.currentValue.match(/\w+/g).join('|\\b'), 'gi');
        content.push('<table cellpadding="0" cellspacing="0">');
        this.result.each(function(value, i) {
            content.push((this.selectedIndex === i ? '<tr class="selected"' : '<tr')); 
            content.push(' onclick="Autocomplete.instances[', this.instanceId, '].select(', i, ');"'); 
            content.push('onmouseover="Autocomplete.instances[',this.instanceId,'].activate(', i, ');"'); 
            content.push('><td>', value.code, '</td>');
            if(value.parent){
                content.push('<td>', Autocomplete.highlight(value.name, re), '</td>');
                content.push('<td>', value.parent, '</td>');
            } else {
                content.push('<td colspan="2">', Autocomplete.highlight(value.name, re), '</td>');
            }
            
            content.push('</tr>');
        } .bind(this));
        this.enabled = true;
        this.container.update(content.join('')).show();
    },

    processResponse: function(xhr) {
        var response;
        try {
            response = xhr.responseText.evalJSON();
        } catch (err) {
            return;
        }
        this.cachedResponse[response.suggestions] = response;
        if (response.result.length === 0) {
            this.badQueries.push(response.suggestions);
        }
        if (response.suggestions === this.currentValue) {
            this.result = response.result;
            this.suggest(); 
        }
    },

    activate: function(index) {
        var divs = this.container.select('tr');
        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.result[i];
        if (selectedValue) {
            this.el.value = selectedValue.name;
            if (this.options.autoSubmit && this.el.form) {
                this.fetchSaleryResult(this.el.value);
            }
            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.result.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.result[i]);
    },
    
    updateResultTile: function(xhr){
        resultTile = $('result_'+this.tileId);
        resultTile.update(xhr.responseText);
        this.hide();
        this.attachTooltip('paygrade-link');
    },
    
    attachTooltip: function (linkClassName){
        $$("a."+linkClassName).each(function(el){
            var target = el.up('tr').next('.paygrade');
            target.hide();
            new Tooltip(el, target, {
                mouseFollow: false
            });
            
        });
    },
    
    fetchSaleryResult: function(needle){
        if(needle==undefined){
            needle = this.el.value;
        }else {
            this.el.value = needle.toString();
        }
        new Ajax.Request(this.serviceUrl, {
            parameters: {
                service: this.service,
                response: 'html',
                needle: needle
            },
            onComplete: this.updateResultTile.bind(this),
            method: 'get'
        });       
    },
    
    test: function(e){
        alert($('result_'+this.tileId).innerHTML);
    }

};

Event.observe(document, 'dom:loaded', function(){
    Autocomplete.isDomLoaded = true;
}, false);

// Tooltip1 Class
var Tooltip = Class.create();
Tooltip.prototype = {
    initialize: function(el, target, options) {
        this.el = $(el);
        this.target = $(target);
        
        this.showEvent = this.show.bindAsEventListener(this);
        this.hideEvent = this.tooltipOut.bindAsEventListener(this);

        Event.observe(this.el, "click", this.showEvent );
        Event.observe(this.el, "mouseout", this.hideEvent );
        this.options = {
            appearDuration: .25, // Default appear duration in sec
            hideDuration: .25 // Default disappear duration in sec
        };
        
        this.tooltipActive = false;
        
    },
    
    tooltipOut: function(e){
        if(e.relatedTarget.up('.tooltip') == undefined && e.relatedTarget != this.tooltip){
            this.hide(e);
        }
        
    },
    show: function(e) {
        if(!this.tooltipActive){
            this.xCord = Event.pointerX(e);
            this.yCord = Event.pointerY(e); 
            var content = [];
            
            $$('div.paygrade').each(function(el){
                el.hide();
            });
        
            this.tooltip = new Element("div", {
                className: "paygrade tooltip"
            });
            this.tooltip.insert( new Element("div", {
                className: 'tile-top'
            }));
            this.tooltip.insert( new Element("div", {
                className: 'tile-content'
            }).insert(this.target.innerHTML));
            this.tooltip.insert( new Element("div", {
                className: 'tile-bottom'
            }));

            this.tooltip.style.width = '300px';
            //this.tooltip.style.height = this.target.getHeight()+'px';
            var t = this.el.cumulativeOffset();
            this.tooltip.style.left = t[0] - 150 + "px";
            this.tooltip.style.top = t[1] + this.el.getHeight() + "px";
            this.tooltip.style.position = 'absolute';
        
            this.tooltipOutEvent = this.tooltipOut.bindAsEventListener(this);
            Event.observe(this.tooltip, "mouseout", this.tooltipOutEvent );            
        
            this.tooltipActive = true;
            (document.body).insert(this.tooltip);
        } else {
            this.hide(e);
        }
        Event.stop(e);
    },
    hide: function(e) {
        
        // if(e.relatedTarget.up('.'+this.tooltip.className) == undefined && e.relatedTarget != this.tooltip){
        new Effect.Fade(this.tooltip, {
            duration: this.options.hideDuration, 
            afterFinish: function() {
                Element.remove(this.tooltip)
                this.tooltipActive = false;
            }.bind(this)
        });
    // }
    }
};
