jQuery.fn.extend({
    autoComplete: function(args) {
        return this.each(function() {
            new jQuery.autoComplete(this, args);
        });
    },
    inlineSearch: function(args) {
      return this.each(function() {
        new $.inlineSearch(this, args);
      });
    }
});

jQuery.autoComplete = function(text, args) {
    var $text     = $(text);
    var $offset   = $text.offset();
    var pos       = { top : $offset.top + $text.outerHeight() + 1, left : $offset.left, width : $text.width(), height : $text.height() };
    var matches   = new Array();
    var current_selected = null;

    if (!args || !args.url) {
        alert('The source is required!');
        return false;
    }
    args.loaded = false;
    if (!args.adjustLeft) args.adjustLeft = 0; 
    if (!args.adjustTop) args.adjustTop = 0;
    if (!args.adjustWidth) args.adjustWidth = 0;

// Create the box
    if ($('body .auto-popup').length == 0) $('body').append('<div class="auto-popup"></div>');

    var num_suggest   = args.suggests || 3;
    var previous_word = '';
    var paging        = { max_hits: 0, current_nh: 0, max_hits : 10 };

// set autocomplete to off
    $text.attr({ autocomplete : 'off' });

    var popDown = function() {
        args.loaded = false;
        $('.auto-popup').slideUp('normal');
        $('.loading').remove(); 
        $text.stopTime('loading');
        $text.stopTime('keyup-timer');
    };

    var popUp = function(e) {
        var c = e.keyCode;
        if (c == 0) c = e.charCode;
        switch (c) {
            case 38: // Up
                e.returnValue = false;
                //if (e.preventDefault) e.preventDefault();
                break;
            case 40: // Down
                e.returnValue = false;
                //if (e.preventDefault) e.preventDefault();
                break;
            case 13: // Enter
                //selectRange();
                popDown();

                e.returnValue = false;
                //if (e.preventDefault) e.preventDefault();
                break;
            case 27: //ESC
                popDown();
                e.returnValue = false;
                //if (e.preventDefault) e.preventDefault();
                break;
            case 9: //TAB
                //selectRange();
                popDown();
                e.returnValue = false;
                //if (e.preventDefault) e.preventDefault();
                break;
            case 8: //BACKSPACE
                if ($text.val().length > 0) {
                    loadSource($text.val());
                }
                else {
                    popDown();
                }
                break;
            default: 
                if ($text.val().length >= num_suggest) {
                    loadSource($text.val());
                }
                else {
                    popDown();
                }
                break;
        }
    };

    var sourceLoading = function() {
        $('body').append('<div class="loading" style="z-index: 10000"></div>');
        $('.loading').css({ top : $offset.top + 3 + 'px', left: pos.left + pos.width - 50 + 'px', height : pos.height }).fadeIn('slow');
    };
    
    var hidePopup = function(e) {
        var popup = $('.auto-popup');
        if (popup.length == 0 || !args.loaded) return;

        var offset  = popup.offset();
        var nheight = popup.outerHeight();
        var nwidth  = popup.outerWidth();

        if (e.pageX <= offset.left + 10 || e.pageX >= nwidth + offset.left + 10 ||
            e.pageY <= offset.top + 5 || e.pageY >= nheight + offset.top + 5) popDown();
    }

    $(document).bind('mousedown', function(e) { hidePopup(e) });

    var orgValue = '';
    $text.bind('keydown', function(e) {
        var code = e.keyCode;
        if (code == 0) code = e.charCode;

        if (code == 9) {
          popDown();
          return;
        }
        else if (code != 38 && code != 40) hidePopup();

        var popup   = $('.auto-popup');
        var curItem = popup.find('ul li.selected');
        var gotoItem;

        if (code == 38) { // up arrow
            if (curItem.length == 0) {
                gotoItem = popup.find('ul li:last');
                if (gotoItem.hasClass('popup-paging')) gotoItem = gotoItem.prev();
            }
            else if (curItem.length > 0) {
                gotoItem = curItem.removeClass('selected').prev();
            }
        }
        else if (code == 40) { // down arrow
            if (curItem.length == 0) {
                gotoItem = popup.find('ul li:first');
            }
            else if (curItem.length > 0) {
                gotoItem = curItem.removeClass('selected').next();
            }
        }

        if (typeof(gotoItem) == 'undefined') return;

        if (gotoItem.length == 0 || gotoItem.hasClass('popup-paging')) {
            $text.val(orgValue);
        }
        else {
            var val = gotoItem.addClass('selected').find('a[rel]').attr('rel');
            val = val.replace(/\s*\(\s*Region\s*\)\s*/, '');
            $text.val(val);
        }
    });

    $text.bind('keyup', function(e) {
        var code = e.keyCode;
        if (code == 0) code = e.charCode;
        if (code == 38 || code == 40) {
            $(this).stopTime('keyup-timer');
            e.returnValue = false;
            return;
        }

        /* Update offset, in case it was invisible */
        $offset = $text.offset();
        pos     = { top : $offset.top + $text.outerHeight() + 1, left : $offset.left, width : $text.width(), height : $text.height() };

        var k = $text.val();

        /* Filter the previous results. If nothing found, then will send a request to the server */
        if (args.load_catch && previous_word.length < k.length && matches.length > 0) {
            var subset = new Array();
            for (var i=0; i<matches.length; i++) {
                if (matches[i].indexOf(k) >= 0) {
                    subset.push(matches[i]);
                }
            }
            matches = subset;

            if (matches.length > 0) {
                createPopup(k);
                return;
            }
        }
        else {
            matches = new Array();
        }

        /* Now sending a request to server if nothing was found in the previous results */
        $text.stopTime('keyup-timer').oneTime(280, 'keyup-timer', function() { 
            $(this).stopTime('keyup-timer');
            popUp(e);
        });
    });

    function loadSource(k, nh) {
        if (k.length < num_suggest) {
            popDown();
            return;
        }

        if (typeof(nh) == 'undefined') nh = 1;
        $text.oneTime(50, 'loading', function() { sourceLoading(); });

        var url = args.url + k;
        if (args.opts) {
          var opts = args.opts;
          for (var k in opts) {
            url += ';' + k + '=' + opts[k].attr('selectedIndex');
          }
        }
        url += ';nh=' + nh;

        $.ajax({
            type : 'GET',
            url : url,
            success : function(req) {
                var words  = req.getElementsByTagName('word');
                var p      = req.getElementsByTagName('paging');
                if (p.length > 0) {
                    paging.num_hits   = parseInt(p[0].getElementsByTagName('num_hits')[0].firstChild.nodeValue);
                    paging.max_hits   = parseInt(p[0].getElementsByTagName('max_hits')[0].firstChild.nodeValue);
                    paging.current_nh = parseInt(p[0].getElementsByTagName('current_nh')[0].firstChild.nodeValue);
                }

                matches = new Array();
                if (words.length > 0) {
                    for (var i=0; i<words.length; i++) {
                        var val = words[i].firstChild.nodeValue;
                        matches.push(val);
                    }
                    createPopup(k);
                }
                else {
                    matches = new Array();
                    popDown();
                }
                previous_word = k;
            }
        });
    }

    function createPopup(k) {
        var html  = '<ul>';
        k = k.replace(/\s+$/, '');
        for (var i=0; i<matches.length; i++) {
            if (i == paging.max_hits) break;

            var name = matches[i].replace(new RegExp('(' + k + ')', 'gi'), "<strong>$1<\/strong>");
            html += '<li><a href="#" rel="' + matches[i] + '">' + name + '<\/a><\/li>\n';
        }
        html += '</ul><div class="clear popup-paging" style="width: ' + pos.width + 'px;"><a href="#" rel="close" class="close" style="padding-right: 0">close<\/a>';
        
        // Handle paging
        if (paging.num_hits > 0) {
            var num_pages = parseInt(paging.num_hits / paging.max_hits);
            if (paging.num_hits % paging.max_hits > 0) num_pages++;
            if (num_pages > paging.current_nh ) {
                html += '<a href="#" rel="paging">more...<\/a>';
            }
        }
        html += '<\/div>';

        orgValue = $text.val();
        var $popup = $('.auto-popup');
        $popup.empty().html(html);

        $popup.find('ul a[rel]').each(function() {
            $(this).mouseover(function() {
//                $popup.find('.selected').removeClass('selected');
                $(this).parent().addClass('selected');
            }).mouseout(function() {
                $(this).parent().removeClass('selected')
            });
            $(this).click(function() {
                var val = htmlUnEscape($(this).attr('rel'));
                val = val.replace(/\s*\(\s*Region\s*\)\s*/, '');
                previous_word = val;
                $text.val(val);
                popDown();
                   // selectRange();
                return false;
            });
        });

        $popup.find('.popup-paging a[rel="paging"]').click(function() {
            loadSource($text.val(), paging.current_nh + 1);
            return false;
        });

        $popup.find('.popup-paging a[rel="close"]').click(function() {
            popDown();
            return false;
        });

        $popup.css({ top : pos.top + args.adjustTop + 'px', left : pos.left + args.adjustLeft + 'px', width: $text.outerWidth() + args.adjustWidth  - 1 + 'px' }).slideDown('normal', function() {
            // Remove loading image and stop timer if visible
            $('.loading').remove(); 
            args.loaded = true;
            $text.stopTime('loading');
        });
        $text.focus();
    }

    function selectRange(from, to) {
        if (from == to) {
            $text.focus();
            return;
        }

        if (text.createTextRange) {
            var range = text.createTextRange();
            range.moveStart('character', from);
            range.select();
        }
        else {
            text.setSelectionRange(from, to);
        }
    }

    function htmlUnEscape(text) {
        text = text.replace(/&quot;/gi, '"');
        text = text.replace(/&gt;/gi, '>');
        text = text.replace(/&lt;/gi, '<');
        text = text.replace(/&amp;/gi, '&');
        return text;
    }
}

$.inlineSearch = function(object, args) {
  var $text    = $(object);
  var $results = $('#inline_results .inline-results');

  if (!args) args = new Object();

  var $default_msg  = $('#inline_results .default-message');
  var $notfound_msg = $('#inline_results .notfound-message');

  var $offset   = $text.val('').offset();
  var pos       = {
    top : $offset.top + 1,
    left : $offset.left,
    width : $text.width(),
    height : $text.height()
  };

  var num_suggest   = 3;
  var prev_query    = '';
  var prev_aResults = new Object();
  var prev_num_hits = 0;

  var removeItem = function(id) {
    $results.find('input[value="' + id + '"]').attr('checked', false);
    $('#cat_selected').find('#line-' + id).remove();
  };

  $('#cat_selected a[rel]').each(function() {
      $(this).click(function() {
        removeItem($(this).attr('rel'));
        return false;
      });
  });

  var loadSource = function(k) {
      if (k.length < num_suggest) return;

      $text.oneTime(50, 'loading', function() {
          if ($('.loading').length == 0) $('body').append('<div class="loading" style="z-index: 10000"></div>');
          $('.loading').css({ top : pos.top + 'px', left: pos.left + pos.width - 20 + 'px', height : pos.height + 'px' }).fadeIn('slow').oneTime(500, 'disable_loading', function() {
              $('.loading').fadeOut().remove();
          });
      });

      $.ajax({
        type : 'GET',
        url : (args.url ? args.url : '/cgi-bin/directory/add.cgi?ajax=cat;query=') + k,
        success : function(req) {
          var category  = req.getElementsByTagName('category');
          var aResults  = new Array();
          var oResults  = new Object();
          var oSelected = new Object();

          $('#cat_selected').find('input[name="CatLinks.CategoryID"]').each(function() {
            oSelected[$(this).val()] = true;
          });

          for (var i=0; i<category.length; i++) {
            var id   = category[i].getElementsByTagName('id')[0].firstChild.nodeValue;
            var name = category[i].getElementsByTagName('name')[0].firstChild.nodeValue;
            aResults.push({ 'id': id, 'name': name });
            oResults[id] = name;
          }

          /* showing aResults */
          if (aResults.length == 0) {
            $results.slideUp('normal', function() {
              $default_msg.fadeOut('normal', function() { $notfound_msg.fadeIn('slow'); });
              $results.empty();
            });
          }
          else {
            $default_msg.fadeOut('normal', function() {
              $notfound_msg.fadeOut('normal');
              $results.show(); 
            });

            $results.find('input[type="checkbox"]').each(function() {
                var $obj = $(this);
                var id   = $(this).val();
                if (typeof(oResults[id]) != 'undefined') {
                  var name = oResults[id].replace(new RegExp('(' + k + ')', 'gi'), "<strong>$1</strong>");
                  $obj.siblings('label').html(name);
                }
                else {
                  $obj.parent().slideUp('slow', function() { $obj.parent().remove() });
                }
            });

            for (var i=0; i<aResults.length; i++) {
              var input  = $results.find('input[value="' + aResults[i].id + '"]');
              if (input.length == 0) {
                var name = aResults[i].name.replace(new RegExp("(" + k + ")","ig"), "<strong>$1</strong>");
                var html = '<div class="form-line" style="display: none"><input type="checkbox" id="cat-' + aResults[i].id + '" name="cat-' + aResults[i].id + '" value="' + aResults[i].id + '"' + (oSelected[aResults[i].id] ? ' checked' : '') + ' class="checkbox" /><label for="cat-' + aResults[i].id + '">' + name + '</label></div>';
                if (i == 0) {
                  if ($results.find('li:first').length == 1) $results.find('li:first').before(html);
                  else $results.append(html);
                }
                else {
                  var posObj = $results.find('input[value="' + aResults[i - 1].id + '"]').parent();
                  posObj.after(html);
                }
                $results.find(':hidden').slideDown('slow');
              }
            }

            $results.find('input[type="checkbox"]').each(function() {
                var $cinput = $(this);
                var max_selected = 3;
                $cinput.click(function() {
                    var found = false;
                    var id    = $(this).val();
                    $('#cat_selected input[name="CatLinks.CategoryID"]').each(function() {
                        if ($(this).val() == $cinput.val()) {
                            found = true;
                            return false;
                        }
                    });

                    var cat_selected = $('#cat_selected');
                    if (found) {// Remove the selected category from category selection listing
                        if (!$cinput.attr('checked')) removeItem(id);
                    }
                    else if (cat_selected.find('input[name="CatLinks.CategoryID"]').length < max_selected) {
                        cat_selected.find('p').remove();
                        cat_selected.append('<div id="line-' + id + '" class="form-line"><input type="hidden" name="CatLinks.CategoryID" value="' + id + '" />' +
                            '<label><a href="#" rel="' + id + '">Remove</a> - ' + $cinput.siblings('label').html() + '</label></div>'
                        ).css({ color: '#33332e' }).find('a[rel="' + id + '"]').click(function() {
                            removeItem(id);
                            return false;
                        });
                    }
                    else {
                        $cinput.attr('checked', false);
                        alert("You can't select more than " + max_selected + ' categories');
                    }
                });
              });
          }
          $('.loading').fadeOut().remove(); 

          prev_query    = k;
          prev_num_hits = aResults.length;
          for (var i=0; i<aResults.length; i++) {
            prev_aResults[aResults[i].id] = true;
          }

        }
      });
    }

    $text.bind('keyup', function(e) {
      var keycode = e.keyCode;
      if (keycode == 0) keycode = e.charCode;
      keycode += '';

      $text.stopTime('keyup-timer');
      if (keycode.search(/^(:?38|40|13|27|9)$/) == 0) {
        e.returnValue = false;
        return;
      }
      
      var k = $text.val();
      k = k.replace(/^\s+/, '');
      k = k.replace(/\s+$/, '');

      if (keycode == 46 || k.length < num_suggest) {
          $results.slideUp('slow', function() {
              $results.empty();
              $notfound_msg.fadeOut('slow', function() { $default_msg.fadeIn('slow') });
          });
          prev_query = k;
      }

      /* Doing nothing if keyword is the same previous search */
      if (k == prev_query) return;

      $text.oneTime(250, 'keyup-timer', function() {
        $(this).stopTime('keyup-timer');
        loadSource(k);
      });
    });
}