/*!  
 *  jQuery - autocomplete
 *
 */
$.fn.extend({
    autoComplete: function(args) {
        return this.each(function() {
            new $.autoComplete(this, args);
        });
    }
});

$.autoComplete = function(text, args) {
    if (!args || !args.url) return;

    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 cache     = { query: '', matches: new Array() };
    var current_selected = null;

    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 $popup        = $('.auto-popup');
    var num_suggest   = args.suggests || 3;
    var paging        = { nh: 1, max_hits : 10 };

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

    var popDown = function() {
        cache.matches = new Array();
        args.loaded = false;
        $('.auto-popup').slideUp('fast');
        $text.stopTime('keyup-timer');
    };

    var popUp = function(e) {
        paging.nh = 1;
        var c = e.keyCode;
        if (c == 0) c = e.charCode;
        switch (c) {
            case 38: // Up
                e.returnValue = false;
                break;
            case 40: // Down
                e.returnValue = false;
                break;
            case 13: // Enter
                popDown();
                e.returnValue = false;
                break;
            case 27: //ESC
                popDown();
                e.returnValue = false;
                break;
            case 9: //TAB
                popDown();
                e.returnValue = false;
                break;
            case 8: //BACKSPACE
                if ($text.val().length > 0) loadSource($text.val());
                else popDown();
                break;
            case 46: //Delete
                cache.query = '';
                break;
            default: 
                if ($text.val().length >= num_suggest) loadSource($text.val());
                else popDown();
                break;
        }
    };
    
    var hidePopup = function(e) {
        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(e);

        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');
             if (val.search('Region') != -1) val = val.substring(0, val.indexOf('(') - 1);
             $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() };

        $text.stopTime('keyup-timer').oneTime(50, 'keyup-timer', function() { 
            $(this).stopTime('keyup-timer');
            popUp(e);
        });
    });

    function loadSource(k, more) {
        if (!k) return;

        k = k.replace(new RegExp('(,\s*)', 'g'), ' ');
        k = k.replace(/\s+$/, ' ');
        k = k.replace(/^\s+/, '');
        if (k == cache.query && !more) return;

        if (k.length < num_suggest) {
            popDown();
            return;
        }

        cache.key  = randomString();
        var url    = args.url + k + ';nh=' + paging.nh + ';autokey=' + cache.key;
        if (args.opts) {
          var opts = args.opts;
          for (var k in opts) {
            url += ';' + k + '=' + opts[k].attr('selectedIndex');
          }
        }
        $.get(url, function(html) {
            if (html != '') {
                // Will show matches with the lasted keyword
                if (html.search('name="autokey" value="' + cache.key + '"') == -1) return;

                cache.query = k;
                $popup.empty().html(html);

                $popup.find('ul a[rel]').each(function() { 
                    $(this).hover(function() {
                        $(this).parent().addClass('selected');
                    }, function() {
                        $(this).parent().removeClass('selected')
                    });
                    $(this).click(function() {
                        var val = htmlUnEscape($(this).attr('rel'));
                        $text.val(val);
                        popDown();
                        return false;
                    });
                });

                $popup.find('a[rel=more]').click(function() {
                    paging.nh += 1;
                    loadSource(k, true);
                    return false;
                });

                $popup.find('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' }).show();
                args.loaded = true;
                //$text.focus();
            }
            else {
                args.loaded = false;
                popDown();
            }
        }, 'html');
    }

    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;
    }

    function randomString() {
        var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
        var string_length = 8;
        var randomstring = '';
        for (var i=0; i<string_length; i++) {
            var rnum = Math.floor(Math.random() * chars.length);
            randomstring += chars.substring(rnum, rnum+1);
        }
        return randomstring;
    }
}


