jQuery.fn.highlight = function(term) {
  this.each(function() {    
    $(this).html($(this).html().replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "<strong>$1</strong>"));
  });
  return this;
}

jQuery.fn.autocomplete = function(options) {

  var url = options.url;
  var label = options.label || function(result) {
    return result.label;
  };
  var onSelect = options.onSelect;
  var cancelSearch = options.cancelSearch || function() {
    return false;
  };
  var cancelMessage = options.cancelMessage;
  var divClass = options.divClass || 'autocomplete';
  var extraParams = options.extraParams || function() {
    return '';
  };
  var adviceMessage = options.adviceMessage;
  var noResultsMessage = options.noResultsMessage || 'No results';
  var selectFirst = options.selectFirst || false;
  var submitOnEnter = options.submitOnEnter || false;
  var createTag = options.createTag || function() {
    return false;
  };
  //autoFill mustMatch formatResult?


  var timeout;

  this.each(function() {    
    var input = this;    
    var div = $(input).after('<div></div>').next()[0];
    var span = $(div).append('<span></span>').find(':last')[0];
    var list = $(div).append('<ul></ul>').find(':last')[0];

    $(input).keydown(function(e) {
      var li = $('li.selected', list)[0];
      switch(e.which) {
        case 38: //up
          if($(div).is(':visible')) {
            $(li).removeClass('selected');
            $(li).prev().addClass('selected');
          }
          break;

        case 40 : //down
          if($(div).is(':visible')) {            
            if(li) {              
              if(li != $('li:last',list)[0]) {
                $(li).removeClass('selected');
                $(li).next().addClass('selected');
              }
            } else {
              $('li:first', list).addClass('selected');
            }
          } else {
            $(input).trigger('search');            
          }
          break;

        case 37: //left          
        case 39: //right
          break;

        case 27: //esc
          $(div).trigger('disappear');
          break;

        case 9: //tab
          break;

        case 13: //enter         
          if($(div).is(':visible')) {            
            if(li) {
              onSelect($(li).data('result'));
              $(div).trigger('disappear');
            } else {
            // run function to send new tag
            createTag();    
          }
            if(!submitOnEnter)
              e.preventDefault();
          } 
          break;

        default:
          clearTimeout(timeout);
          timeout = setTimeout(function() { 
            $(input).trigger('search');
          }, 150);
      }
    });

    $(input).bind('search', function() {
      if(cancelSearch()) {
        if(input.value.length == 0) {
          $(list).hide();
          $(span).text(cancelMessage).show();
          $(div).trigger('appear');
        } else {
          $(div).trigger('disappear');
        }
      } else {
        if(input.value.length > 0) {          
          $.getJSON(url+'?q='+input.value+'&'+extraParams(),
            function(results) {
              $(span).hide();              
              $(list).empty().show();
              if(results.length > 0) {
                $.each(results, function(i,result){
                  var li = $(list).append('<li>'+label(result)+'</li>').find(':last');
                  $(li).highlight(input.value);
                  $(li).data('result',result);
                  $(li).mouseover(function() {
                    $('li',list).removeClass('selected');
                    $(li).addClass('selected');
                  }).click(function() {
                    onSelect($(li).data('result'));
                    $(div).trigger('disappear');
                  });
                });
                if(selectFirst)
                  $('li:first',list).addClass('selected');                                
              } else {
                $(list).hide();
                $(span).text(noResultsMessage).show();
              }
              $(div).trigger('appear');
            });
        } else {
          if(adviceMessage) {
            $(list).hide();
            $(span).text(adviceMessage).show();
            $(div).trigger('appear');
          } else {
            $(div).trigger('disappear');
          }
        }
      }
    });

    $(div).addClass(divClass).css({
      position: 'absolute',
      borderWidth: 1,
      zIndex: 999999,
      'border-width': '0 1px 1px 1px',
      'border-color': '#ADB3B6',
      'border-style': 'solid',
      'border-top': '2px solid #B9DBEF'
    }).hide().bind('appear', function() {
      $(div).fadeIn('fast').css({
        top: $(input).position().top + input.offsetHeight,
        left: $(input).position().left -6,
        width: $(input).outerWidth() + 10
      });
    }).bind('disappear', function() {
      $(div).fadeOut('fast');
    });
    
    $(input).bind('focus click',function() {
      if (!input.title || ($(input).val() != input.title)) {
        $(input).trigger('search');
      } else {
        $(div).trigger('appear');
      }
    }).blur(function() { 
      $(div).trigger('disappear');
    }).attr('autocomplete','off');
    
  });
  return this;
}

