(function($)
{
    $.fn.autocomplete = function (sSearchAjaxUrl, data)
    {
        $(this).each(function()
        {
            var $oInput = $(this);
            var $oResultDiv = $(document.createElement("div")).attr('id', 'searchresult');            
            $('#contentwrapper').append($oResultDiv);
            var iSelectedIndex = 0;
            var iMaxSelectedIndex = 0;
            var tTimeout;
            var oKey = {
        		UP: 38,
        		DOWN: 40,
        		DEL: 46,
        		TAB: 9,
        		RETURN: 13,
        		ESC: 27,
        		COMMA: 188,
        		PAGEUP: 33,
        		PAGEDOWN: 34,
        		BACKSPACE: 8
        	};
        	$(this.form).bind("submit", function()
        	{
        		if(iSelectedIndex)
                {
                    return false;
                }
        	});
        	
        	$oInput
                .attr("autocomplete", "off")
                .bind("keyup.autocomplete", function(event)
                {
            		switch(event.keyCode)
            		{
            			case oKey.UP:
            			case oKey.PAGEUP:
            				event.preventDefault();
            				if($oResultDiv.is(":visible"))
            				{
            					selectPrev();
            				}
            				break;
            				
            			case oKey.DOWN:
            			case oKey.PAGEDOWN:
            				event.preventDefault();
            				if($oResultDiv.is(":visible"))
            				{
            					selectNext();
            				}
            				break;
            			
            			case oKey.RETURN:
            			
            				if(iSelectedIndex && $oResultDiv.is(":visible"))
            				{
            				    event.preventDefault();
            				    selectCurrent();
            				    return false;
            				}
            				else
            				{
            				    return true;
            				}            				
            				break;
            				
            			case oKey.ESC:
            				iSelectedIndex = 0;
            				$oResultDiv.fadeOut();
            				break;
            				
            			default:
            				iSelectedIndex = 0;
            				sSearchStr = $oInput.val();
            				if (!sSearchStr || sSearchStr.length < 2)
                            {
                                $oResultDiv.fadeOut();
                                return;
                            }
            				clearTimeout(tTimeout);
            				tTimeout = setTimeout(getResults, 400);
            				break;
            		}
            	})
                .blur(function()
                {
                    $oResultDiv.fadeOut();
                    iSelectedIndex = 0;
                    $oInput.removeClass('busy');
                });
                
            showResults = function(sHtml)
            {
                oPos = $oInput.offset(); 
                $oResultDiv
                    .css({left: oPos.left, top: oPos.top + $oInput.height() + 7})
                    .html(sHtml)
                    .fadeIn()
                    .find('a')
                    .unbind()
                    .bind('mouseover', function()
                    {
                        $oResultDiv
                            .find('a')
                            .removeClass('hover');
                        $(this).addClass('hover');
                    })
                    .bind('mouseout', function()
                    {
                        $(this).removeClass('hover');
                    });
                $oInput.removeClass('busy');
                iMaxSelectedIndex = $oResultDiv.find('a').length;

                // pngfix
                if ($.fn.pngFix) $($oResultDiv).pngFix();
            }
            
            selectPrev = function()
            {
                iSelectedIndex--;
                iSelectedIndex = Math.max(1, iSelectedIndex);
                selectLink();                
            }
            
            selectNext = function()
            {
                iSelectedIndex++;
                iSelectedIndex = Math.min(iMaxSelectedIndex, iSelectedIndex);
                selectLink();
            }
            
            selectLink = function()
            {
                $oResultDiv
                    .find('a')
                    .removeClass('hover')
                    .end()
                    .find('a:eq(' + (iSelectedIndex - 1) + ')')
                    .addClass('hover');
            }
            
            selectCurrent = function()
            {
                window.location.href = $oResultDiv.find('a:eq(' + (iSelectedIndex - 1) + ')').attr('href');
            }

            getResults = function()
            {
                // cache ?
                if($oInput.data("result_" + encodeURIComponent(sSearchStr)))
                {
                    // show records
                    showResults($oInput.data("result_" + encodeURIComponent(sSearchStr)));
                    return;
                }

                // record latest_keypress_time
                var dKeypressTime = new Date();
                $oInput.data("dLatestKeypressTime", dKeypressTime);
                          
                // ajax
                $oInput.addClass('busy');
                $.get(sSearchAjaxUrl, {q: sSearchStr}, function(sResponse)
                {
                    // compare keypress_time with latest_keypress_time
                    var dLatestKeypressTime = $oInput.data("dLatestKeypressTime");
                    if (dKeypressTime < dLatestKeypressTime)
                    {
                        return;
                    }
                    
                    // into cache
                    $oInput.data("result_" + encodeURIComponent(sSearchStr), sResponse);
                    
                    // show records
                    showResults(sResponse);
                    
                }, 'html');
            }
        });
        return $(this);
    };
})(jQuery);
