/*
*	jquery.suggest 1.2 - 2008-05-19
*	
*	Uses code and techniques from following libraries:
*	1. http://www.dyve.net/jquery/?autocomplete
*	2. http://dev.jquery.com/browser/trunk/plugins/interface/iautocompleter.js	
*
*	All the new stuff written by Peter Vulgaris (www.vulgarisoip.com)	
*	Feel free to do whatever you want with this file
* 
*	Rodrigo Uroz: Sobre la base de la versión 1.1 se implementaron cambios
*	para adaptarlo a nuestros requerimientos 
*
*/
(function($) {
$.suggest = function(input, options) {
var loadingText = options.loadingText;
var loading = [];
loading[loading.length] = loadingText;
var rq_object;
var noResultsFromLastInput = false;
var lastLength = 0;
var $input = $(input).attr("autocomplete", "off");
var $results = $(document.createElement("ul"));
var timeout = false;		// hold timeout ID for suggestion results to appear	
var prevLength = 0;			// last recorded length of $input.val()
var cache = [];				// cache MRU list
var cacheSize = 0;			// size of cache in chars (bytes?)
$results.addClass(options.resultsClass).appendTo('body');
resetPosition();
$(window)
.load(resetPosition)		// just in case user is changing size of page while loading
.resize(resetPosition);
$input.blur(function() {
setTimeout(function() { $results.hide() }, 200);
});
// help IE users if possible
try {
$results.bgiframe();
} catch(e) { }
/*
// I really hate browser detection, but I don't see any other way
if ($.browser.mozilla)
$input.keypress(processKey);	// onkeypress repeats arrow keys in Mozilla/Opera
else
$input.keydown(processKey);		// onkeydown repeats arrow keys in IE/Safari
*/
$input.keydown(processKey);				
function resetPosition() {
// requires jquery.dimension plugin
var offset = $input.offset();
$results.css({
top: (offset.top + input.offsetHeight) + 'px',
left: offset.left + 'px'
});
}
function processKey(e) {
lastKeyPressCode = e.keyCode;
// handling up/down/escape requires results to be visible
// handling enter/tab requires that AND a result to be selected
if ((/27$|38$|40$/.test(e.keyCode) && $results.is(':visible')) ||
(/^13$|^9$|^32$/.test(e.keyCode) && getCurrentResult())) {
if (e.preventDefault)
e.preventDefault();
if (e.stopPropagation)
e.stopPropagation();
e.cancelBubble = true;
e.returnValue = false;
switch(e.keyCode) {
case 38: // up
prevResult();
break;
case 40: // down
nextResult();
break;
case 9:  // tab
case 13: // return
selectCurrentResult();
break;
case 27: //	escape
$results.hide();
break;
case 32: // espace
selectCurrentResult();
$input.val($input.val()+' ');
if (timeout) 
clearTimeout(timeout);
timeout = setTimeout(suggest, options.delay);
prevLength = $input.val().length;
break;				
}
} else if ($input.val().length != prevLength) {
if (timeout) 
clearTimeout(timeout);
timeout = setTimeout(suggest, options.delay);
prevLength = $input.val().length;
}			
}
function suggest() {
var q = $input.val();
var dontSearch = noResultsFromLastInput && q.length > lastLength;
if (q.length >= options.minchars && !dontSearch) {
lastLength = q.length;
cached = checkCache(q);
if (cached) {
displayItems(cached['items']);
} else {
displayItems(loading);
if ( rq_object ) {
rq_object.abort();
}
rq_object = $.ajax({
type:"get",
url:options.source,
data:"q="+q,
success:function(txt) {
$results.hide();
var items = parseTxt(txt, q);
if ( items.length > 1 ) {
displayItems(items);
addToCache(q, items, txt.length);
noResultsFromLastInput = false;	
} else if ( items.length == 1 ) {
// si trae un solo elemento, hacemos la busqueda agregando un espacio
// al final porque quiza le traiga mejores resultados
var prevResults = items;
$.ajax({
type:"get",
url:options.source,
data:"q="+q+' ',
success:function(txt) {
$results.hide();
var items = parseTxt(txt, q);
if ( items.length > 0 ) {
displayItems(items);
addToCache(q+' ', items, txt.length);
noResultsFromLastInput = false;	
} else {
displayItems(prevResults);
addToCache(q, prevResults, txt.length);
noResultsFromLastInput = false;
}		
}
});	
} else {
noResultsFromLastInput = true;
}								
rq_object = null;
}
}); 
}
} else {
$results.hide();
}
}
function checkCache(q) {
for (var i = 0; i < cache.length; i++)
if (cache[i]['q'] == q) {
cache.unshift(cache.splice(i, 1)[0]);
return cache[0];
}
return false;
}
function addToCache(q, items, size) {
while (cache.length && (cacheSize + size > options.maxCacheSize)) {
var cached = cache.pop();
cacheSize -= cached['size'];
}
cache.push({
q: q,
size: size,
items: items
});
cacheSize += size;
}
function displayItems(items) {
if (!items)
return;
if (!items.length) {
$results.hide();
return;
}
var html = '';
for (var i = 0; i < items.length; i++)
html += '<li>' + items[i] + '</li>';
$results.html(html).slideDown(options.animation);
$results
.children('li')
.mouseover(function() {
$results.children('li').removeClass(options.selectClass);
$(this).addClass(options.selectClass);
})
.click(function(e) {
e.preventDefault(); 
e.stopPropagation();
selectCurrentResult();
});
}
function parseTxt(txt, q) {
var items = [];
// le saco el comentario que se pone a cada ejecucion de php
txt = txt.replace(/<!--[\w\W]*-->/,'');
var tokens = txt.split(options.delimiter);
// parse returned data for non-empty items
for (var i = 0; i < tokens.length; i++) {
var token = $.trim(tokens[i]);
if (token) {
token = token.replace(
new RegExp(q, 'ig'), 
function(q) { return '<span class="' + options.matchClass + '">' + q + '</span>' }
);
items[items.length] = token;
}
}
return items;
}
function getCurrentResult() {
if (!$results.is(':visible'))
return false;
var $currentResult = $results.children('li.' + options.selectClass);
if (!$currentResult.length)
$currentResult = false;
return $currentResult;
}
function selectCurrentResult() {
$currentResult = getCurrentResult();
if ($currentResult) {
if ($currentResult.text() == loadingText) {
return;
}
$input.val($currentResult.text());
$results.hide();
if (options.onSelect)
options.onSelect.apply($input[0]);
}
}
function nextResult() {
$currentResult = getCurrentResult();
if ($currentResult)
$currentResult
.removeClass(options.selectClass)
.next()
.addClass(options.selectClass);
else
$results.children('li:first-child').addClass(options.selectClass);
}
function prevResult() {
$currentResult = getCurrentResult();
if ($currentResult)
$currentResult
.removeClass(options.selectClass)
.prev()
.addClass(options.selectClass);
else
$results.children('li:last-child').addClass(options.selectClass);
}
}
$.fn.suggest = function(source, options) {
if (!source)
return;
options = options || {};
options.source = source;
options.delay = options.delay || 100;
options.resultsClass = options.resultsClass || 'ac_results';
options.selectClass = options.selectClass || 'ac_over';
options.matchClass = options.matchClass || 'ac_match';
options.minchars = options.minchars || 3;
options.delimiter = options.delimiter || '\n';
options.onSelect = options.onSelect || false;
options.maxCacheSize = options.maxCacheSize || 65536;
options.animation = "slow";
this.each(function() {
new $.suggest(this, options);
});
return this;
};
})(jQuery);
