(function($) {
  $.browser.win = /win/i.test(navigator.userAgent.toLowerCase());
  
  $.fn.decorateSearchInput = function() {
    return this.each(function() {
      var searchField = $(this),
          standIn     = null,
          options     = arguments[0] || {},
          results     = options.results     || 0,
          placeholder = options.placeholder || searchField.attr('placeholder'),
          autosave    = options.autosave    || '';

      if ($.browser.safari) {
        if ($.browser.win)
          searchField.addClass('not-round');

        if (!searchField.attr('type'))
          searchField.attr('type', 'search');  
        
        if (!searchField.attr('results'))
          searchField.attr('results', results);
        
        if (null != placeholder)
          searchField.attr('placeholder', placeholder).attr('autosave', autosave);
        
        return;
      }
      
      //prevent browser from doing its own autocomplete, threw odd xul
      //error on reset sometimes, although this feels a little
      //heavy handed
      searchField.attr('autocomplete', 'off');

      //replace the field with a standin while we create the wrapper
      //we can't lose the reference to this field as other objects may
      //have already registered listeners on this field
      standIn = document.createElement('input');
      searchField.get(0).parentNode.replaceChild(standIn, searchField.get(0));

      var left    = $('<span />').addClass('left'),
          right   = $('<span />').addClass('right'),
          reset   = $('<div />').addClass('reset'),
          wrapper = $('<div />').addClass('search-wrapper');

      var alreadyHasPlaceholder = searchField.val() == placeholder;
      var isEmpty = searchField.val() == placeholder.length == 0;

      if (alreadyHasPlaceholder || isEmpty) {
        searchField.val(placeholder);
        wrapper.addClass('blurred').addClass('empty');
      }

      wrapper.append(left).append(searchField)
             .append(right).append(reset);
    
      searchField.focus(function() {
        var blurred = wrapper.hasClass('blurred');

        //need to check for flag AND placeholder lest somebody need to
        //search for the placeholder text itself
        if (searchField.val() == placeholder && blurred)
          searchField.val('');

        wrapper.removeClass('blurred');
      });

      searchField.blur(function() {
        if (searchField.val().length < 1) {
          wrapper.addClass('empty');
          searchField.val(placeholder);
        }

        wrapper.addClass('blurred');
      });

      searchField.keydown(function() {
        if (searchField.val().length >= 0)
          wrapper.removeClass('empty');
      });

      var resetField = function() {
        return (function(evt) {
          var escaped = false;

          if (evt.type == 'keydown') {
            if (evt.keyCode != 27)
              return; //if it's not escape ignore it
            escaped = true;
          }

          searchField.blur(); //can't change value while in field
          searchField.val('');
          wrapper.addClass('empty');
          searchField.focus();
        });
      }
    
      reset.mousedown(resetField());
      searchField.keydown(resetField());

      if (standIn)
        standIn.parentNode.replaceChild(wrapper.get(0), standIn);
    });
  };
})(jQuery);