;(function(jQuery) {
    jQuery.fn.extend({
        autocomplete: function(urlOrData, options) {
            var isUrl = typeof urlOrData == "string";
            options = jQuery.extend({}, {
                url: isUrl ? urlOrData : null,
                data: isUrl ? null : urlOrData,
                delay: 10,
                max: 5
            }, options);
            
            return this.each(function() {
                
                 // create the div for the results
                 var div    = document.createElement('div');         
                 jQuery(this).attr('autocomplete', 'off');
                 div.id     = this.id+'_autocomplete';
                 var position = jQuery(this).position();
                 var offset = jQuery(this).offset();
                                           
                 jQuery(div).css({
                     'display'    : 'none',
                     'position'   : 'absolute',
                     'height'     : '200px', 
                     'left'       : offset.left,     
                     'top'        : offset.top + jQuery(this).outerHeight(),
                     'width'      : jQuery(this).innerWidth(),                     
                     'max-width'  : jQuery(this).innerWidth(),                     
                     'overflow-y' : 'scroll',
                     'overflow-x' : 'hidden',
                     'text-align' : 'left',
                     'z-index'    : 99999                     
                 });
                 
                 jQuery(div).addClass('ac_results');
                 $(div).appendTo(document.body);
                 
                 // create the loading div
                 var div    = document.createElement('div');         
                 div.id     = this.id+'_loading';
                 jQuery(div).css({
                     'position'   : 'absolute',                     
                     'display'    : 'none',
                     'height'     : '20px',
                     'left'       : offset.left,     
                     'top'        : offset.top + jQuery(this).outerHeight(),
                     'width'      : jQuery(this).outerWidth(), 
                     'text-align' : 'left',
                     'z-index'    : 99999                     
                 });
                 jQuery(div).html('VorschlÃ¤ge...');
                 $(div).appendTo(document.body);        
                          
                 ac  = new Autocomplete(this.id, {format: 'json', url: options.url, fastSelect: options.fastSelect});
            });
        },
        autocompleteResult: function(handler) {
            return this.bind("autocompleteresult", handler);
        },
        autocompleteResultReady: function(handler) {
            return this.bind("autocompleteresultready", handler);
        }
    });
})(jQuery);


function Autocomplete(textFieldId, options) {
    var me = this;    
    this.id = textFieldId;
    this.caller = function(){me._defaultCaller()};
    //this.callback = function(data){me._defaultCallback(data)}; 
    this.textfield = jQuery('#'+this.id);     
    this.initialText = this.textfield.val(); 
    this.resultContainer = jQuery('#'+this.id+'_autocomplete');
            
    this.format = typeof options.format != 'undefined' ? options.format : 'html';    
    this.minLength = typeof options.minLength != 'undefined' ? options.minLength : 3;
    this.url = typeof options.url != 'undefined' ? options.url : '/autocomplete';
    this.fastSelect = typeof options.fastSelect != 'undefined' ? options.fastSelect : false;
       
    this.textfield.keyup(function(event){me._keyHandler(event)});
    this.textfield.keypress(function(event){if(event.keyCode == 13) {return false;}});        
    this.textfield.focus(function(){this.value = ''});                    
    this.textfield.blur(function(){if(this.value == ''){this.value = me.initialText}});
    this.textfield.autocomplete = 'false';
    
    $(window).resize(function(){
        me._hideAndClear();
    });

    
    var pasteEvent = ((jQuery.browser.opera || (jQuery.browser.mozilla && parseFloat(jQuery.browser.version.substr(0,3)) < 1.9 ))? 'input': 'paste');
    jQuery(this.textfield).bind(pasteEvent, function(event){var self = me; var e = event; setTimeout(function(){self._keyHandler(e)}, 1)});        
    jQuery(document).click(function(evt){me._trackActiveElement(evt)});
}

Autocomplete.prototype.running = false;
Autocomplete.prototype.caller = false;
Autocomplete.prototype.callback = false;
Autocomplete.prototype.selectCallback = null;
Autocomplete.prototype.textfield = null;
Autocomplete.prototype.resultContainer = null;
Autocomplete.prototype.timer = null;
Autocomplete.prototype.method = 'get';
Autocomplete.prototype.format = 'html';
Autocomplete.prototype.url = '/robots.php';
Autocomplete.prototype.visible = false;
Autocomplete.prototype.selectedResult = '';
Autocomplete.prototype.selectedIndex = 0;
Autocomplete.prototype.data = null;
Autocomplete.prototype.initialText = null;
Autocomplete.prototype.minLength = 3;
Autocomplete.prototype.fastSelect = false;

Autocomplete.prototype._trackActiveElement = function(evt) {    
    if(!jQuery(evt.target).hasClass('directsearch_li') && !jQuery(evt.target).hasClass('directsearch_ul')) { 
        this.resultContainer.hide();
        this.visible = false;   
        if (typeof this.dropdownHide == 'function') {
            this.dropdownHide();
        } 
    }
}

Autocomplete.prototype._keyHandler = function(event) {
    var keycode;    
    
    if (event.type == 'paste' || event.type == 'input') {
        keycode = null;
    } else {
        keycode = event.keyCode;
    }

    var me = this;
    switch (keycode){
        case 13: { // return
            if (this.selectedResult != '') {
                this._handleSelection();
            }
        }
        case 38: { // up
            if (this.visible != true || this.selectedResult == '') {
                return;
            }
            this.selectedResult.removeClass('ac_hl');                
            if (this.selectedResult.prev().length != 0) {
                this.selectedResult = this.selectedResult.prev();    
                this.selectedIndex--;
            } else {
                this.selectedResult = jQuery('.'+this.id+'_li:last');
                this.selectedIndex = this.data.length;
            }
            this.selectedResult.addClass('ac_hl'); 
            if (this.selectedResult.attr('offsetTop') < this.resultContainer.attr('scrollTop')) {            
                this.resultContainer.attr('scrollTop', this.resultContainer.attr('scrollTop') - this.selectedResult.attr('scrollHeight'));
            } else if (this.selectedResult.attr('offsetTop') >= this.resultContainer.attr('scrollHeight') - this.selectedResult.attr('scrollHeight')) {
                this.resultContainer.attr('scrollTop', this.resultContainer.attr('scrollHeight'));
            }
            break;            
        }
        case 40: { // down
            if (this.visible != true) {
                return;
            }
                       
            if (this.selectedResult == '') {
                this.selectedResult = jQuery('.'+this.id+'_li:first');                
                this.selectedIndex = 0;
            } else {
                this.selectedResult.removeClass('ac_hl');                
                if (this.selectedResult.next().length != 0) {
                    this.selectedResult = this.selectedResult.next();    
                    this.selectedIndex++;
                } else {
                    this.selectedResult = jQuery('.'+this.id+'_li:first');
                    this.selectedIndex = 0;
                }                
            }   
            
                        
            this.selectedResult.addClass('ac_hl'); 
            if (this.selectedResult.attr('offsetTop') + this.selectedResult.attr('offsetHeight')  > this.resultContainer.attr('offsetHeight')) {            
                this.resultContainer.attr('scrollTop', this.resultContainer.attr('scrollTop') + this.selectedResult.attr('scrollHeight'));
            } if (this.selectedResult.attr('offsetTop') <= this.selectedResult.attr('scrollHeight')) {
                this.resultContainer.attr('scrollTop', 0);
            } 
            break;           
        }        
        default: {                          
            if(this.textfield.val().length < this.minLength) {
                this._hideAndClear();
                return;
            }
            if (this.running == true) {
                return;
            }
            if (this.timer != null) {
                clearTimeout(this.timer);
            }                                            
            this.timer = setTimeout(this.caller, 500);
        }
    }
}

Autocomplete.prototype._handleSelection = function(event) {    
    this.resultContainer.hide();
    if (typeof this.dropdownHide == 'function') {       
        this.dropdownHide();
    }
    this.visible = false;  
    this.selectedResult = '';
    this.textfield.val(this.data[this.selectedIndex].value);
    jQuery('#'+this.id+'_selected').val(this.data[this.selectedIndex].id);     
    $(this.textfield).trigger("autocompleteresult", this.data[this.selectedIndex], this.data);        
}

Autocomplete.prototype._defaultCaller = function() {
    var me = this;
    if (this.method == 'get') {        
        jQuery.get(this.url, {query: this.textfield.val()}, function(data){me._defaultCallback(data)}, this.format);                
    } else {
        jQuery.post();
    }
}

Autocomplete.prototype._hideAndClear = function() {
    //jQuery('#'+this.id+'_loading').hide();
    this.resultContainer.hide(); 
    this.resultContainer.attr('scrollTop', 0);
    this.running = false; 
    this.visible = false;
    if (typeof this.dropdownHide == 'function') {
        this.dropdownHide();
    }
    return;
}

Autocomplete.prototype._defaultCallback = function(data) {    
    var me = this;
    this.running = true;
    
    if (data.results.length == 0) {
        this._hideAndClear();
        return;
    }
    
    if (this.format == 'json') {                
        var result = document.createElement('ul');
        $(result).css({                     
                     'display'    : 'block'                                          
        });
        var a  = null, li = null;
        
        jQuery.each(data.results, function(i,item){
            li           = document.createElement('li');                      
            $(li).css({                     
                     'float'    : 'none'                                         
            });
            $(li).addClass(me.id+'_li');
            var selectedIndex = i;
            
            a           = document.createElement('a');
                        
            a.innerHTML = item.text.replace(new RegExp('('+me.textfield.val()+')', "ig"), '<b>$1</b>');
            a.href      = 'javascript:void(0)';            
            li.onclick   = function(event){me.selectedIndex = selectedIndex; me._handleSelection(event)};  
            
            jQuery(li).append(a);
            jQuery(result).append(li);                        
        });   
        this.data = data.results;
        if ($(this.data).length == 1 && this.fastSelect == true) {            
            this._hideAndClear();                        
            $(this.textfield).trigger("autocompleteresult", this.data[0]);
            return;
        }
    }
    
    if (typeof this.resultReady == 'function') {
        if (this.resultReady(this.data) == false) {
            this.running = false;
            this.visible = false;
            //jQuery('#'+this.id+'_loading').hide();
            return;
        };
    }
    
    var offset = this.textfield.offset();
    
    this.resultContainer.css({                     
         'left'       : offset.left,     
         'top'        : offset.top + this.textfield.outerHeight()
    });
    

    this.resultContainer.attr('scrollTop', 0);
    this.resultContainer.html(result);
    //jQuery('#'+this.id+'_loading').hide();
    if (typeof this.dropdownShow == 'function') {
        this.dropdownShow();
    }
    this.resultContainer.show(); 
    this.running = false; 
    this.visible = true;      
}
