/**
 * Turn a text box into an auto suggest box which search's and 
 * displays results specified in a JSON string
 * 
 *
 * @name jsonSuggest
 * @type jQuery
 * @param searchData :	[required] Can be one of three things; a JSON string which specified the search data, an object that is representative of a parsed JSON string or a function which returns either of these two things.
 *					expected object format example; (either as raw object or JSON string)
 					[
						{
							id: 1,
							text: 'Thomas',
							image: 'img/avator1.jpg',	// optional
							extra: 'www.thomas.com'	// optional
						},
						{
							id: 2,
							text: 'Frederic',
							image: 'img/avator2.jpg',	// optional
							extra: 'www.freddy.com'	// optional
						},
						{
							id: 2,
							text: 'James',
							image: 'img/avator2.jpg',	// optional
							extra: 'www.james.com'	// optional
						}
					]
 * @param Object settings;	[optional]
 *			minCharacters :	[default 1] Number of characters that the input should accept before running a search.
 *			maxResults:	[default undefined] If set then no more results than this number will be found.
 *			wildCard :		[default ''] A character to be used as a match all wildcard when searching. Leaving empty will mean results are matched inside
 *						strings but if a wildCard is present then results are matched from the beginning of strings.
 *			caseSensitive :	[defautl false] True if the filter search's are to be case sensitive.
 *			notCharacter :	[default !] The character to use at the start of any search text to specify that the results should NOT contain the following text.
 *			maxHeight :	[default 350] This is the maximum height that the results box can reach before scroll bars are shown instead of getting taller.	
 *			highlightMatches: [default true] This will add strong tags around the text that matches the search text in each result.
 *			onSelect : 		[default undefined] Function that gets called once a result has been selected, gets passed in the object version of the result as specified in the json string
 *			ajaxResults : 	[default false] If this is set to true then you must specify a function as the searchData construction parameter. This is because when this
 *						settings is true then results are retrieved from an external function each time they are needed instead of being retrieved from the data given on 
 * 						contruction. The searchData function must return a JSON string of resulting objects or the object which represents the JSON string. The function is
 *						passed the following paramenters;
 *						1. The search text typed into the input box
 *						2. The current wildCard setting
 *						3. The current caseSensitive setting
 *						4. The current notCharacter setting 
 *			width:		[default undefined] If set this will become the width of the results box else the box will be the same width as the input
 * @author Tom Coote (www.tomcoote.co.uk)
 * @version 1.2.4
 */(function($){$.fn.jsonSuggest=function(searchData,settings){var defaults={minCharacters:1,maxResults:20,wildCard:"",caseSensitive:false,notCharacter:"!",maxHeight:350,highlightMatches:true,onSelect:undefined,ajaxResults:false,width:undefined};settings=$.extend(defaults,settings);return this.each(function(){function regexEscape(txt,omit){var specials=['/','.','*','+','?','|','(',')','[',']','{','}','\\'];if(omit){for(var i=0;i<specials.length;i++){if(specials[i]===omit){specials.splice(i,1);}}}
var escapePatt=new RegExp('(\\'+ specials.join('|\\')+')','g');return txt.replace(escapePatt,'\\$1');}
var obj=$(this),wildCardPatt=new RegExp(regexEscape(settings.wildCard||''),'g'),results=$('<div />'),currentSelection,pageX,pageY;function selectResultItem(item){obj.val(item.text);$(results).html('').hide();if(typeof settings.onSelect==='function'){settings.onSelect(item);}}
function setHoverClass(el){$('div.resultItem',results).removeClass('hover');$(el).addClass('hover');currentSelection=el;}
function buildResults(resultObjects,sFilterTxt){sFilterTxt="("+ sFilterTxt+")";var bOddRow=true,i,iFound=0,filterPatt=settings.caseSensitive?new RegExp(sFilterTxt,"g"):new RegExp(sFilterTxt,"ig");$(results).html('').hide();for(i=0;i<resultObjects.length;i+=1){var item=$('<div />'),text=resultObjects[i].text;if(settings.highlightMatches===true){text=text.replace(filterPatt,"<strong>$1</strong>");}
$(item).append('<p class="text">'+ text+'</p>');if(typeof resultObjects[i].extra==='string'){$(item).append('<p class="extra">'+ resultObjects[i].extra+'</p>');}
if(typeof resultObjects[i].image==='string'){$(item).prepend('<img src="'+ resultObjects[i].image+'" />').append('<br style="clear:both;" />');}
$(item).addClass('resultItem').addClass((bOddRow)?'odd':'even').click(function(n){return function(){selectResultItem(resultObjects[n]);};}(i)).mouseover(function(el){return function(){setHoverClass(el);};}(item));$(results).append(item);bOddRow=!bOddRow;iFound+=1;if(typeof settings.maxResults==='number'&&iFound>=settings.maxResults){break;}}
if($('div',results).length>0){currentSelection=undefined;$(results).show().css('height','auto');if($(results).height()>settings.maxHeight){$(results).css({'overflow':'auto','height':settings.maxHeight+'px'});}}}
function runSuggest(e){this.value=this.value.replace('ά','α');this.value=this.value.replace('έ','ε');this.value=this.value.replace('ή','η');this.value=this.value.replace('ί','ι');this.value=this.value.replace('ό','ο');this.value=this.value.replace('ύ','υ');this.value=this.value.replace('ώ','ω');this.value=this.value.replace('Ά','Α');this.value=this.value.replace('Έ','Ε');this.value=this.value.replace('Ή','Η');this.value=this.value.replace('Ί','Ι');this.value=this.value.replace('Ό','Ο');this.value=this.value.replace('Ύ','Υ');this.value=this.value.replace('Ώ','Ω');if(this.value.length<settings.minCharacters){$(results).html('').hide();return false;}
var resultObjects=[],sFilterTxt=(!settings.wildCard)?regexEscape(this.value):regexEscape(this.value,settings.wildCard).replace(wildCardPatt,'.*'),bMatch=true,filterPatt,i;if(settings.notCharacter&&sFilterTxt.indexOf(settings.notCharacter)===0){sFilterTxt=sFilterTxt.substr(settings.notCharacter.length,sFilterTxt.length);if(sFilterTxt.length>0){bMatch=false;}}
sFilterTxt=sFilterTxt||'.*';sFilterTxt=settings.wildCard?'^'+ sFilterTxt:sFilterTxt;filterPatt=settings.caseSensitive?new RegExp(sFilterTxt):new RegExp(sFilterTxt,"i");if(settings.ajaxResults===true){resultObjects=searchData(this.value,settings.wildCard,settings.caseSensitive,settings.notCharacter);if(typeof resultObjects==='string'){resultObjects=JSON.parse(resultObjects);}}
else{for(i=0;i<searchData.length;i+=1){if(filterPatt.test(searchData[i].text)===bMatch){resultObjects.push(searchData[i]);}}}
buildResults(resultObjects,sFilterTxt);}
function keyListener(e){switch(e.keyCode){case 13:$(currentSelection).trigger('click');return false;case 40:if(typeof currentSelection==='undefined'){currentSelection=$('div.resultItem:first',results).get(0);}
else{currentSelection=$(currentSelection).next().get(0);}
setHoverClass(currentSelection);if(currentSelection){$(results).scrollTop(currentSelection.offsetTop);}
return false;case 38:if(typeof currentSelection==='undefined'){currentSelection=$('div.resultItem:last',results).get(0);}
else{currentSelection=$(currentSelection).prev().get(0);}
setHoverClass(currentSelection);if(currentSelection){$(results).scrollTop(currentSelection.offsetTop);}
return false;default:runSuggest.apply(this,[e]);}}
$(results).addClass('jsonSuggestResults').css({'top':(obj.position().top+ obj.height())+'px','left':(obj.position().left-10)+'px','width':settings.width||((obj.width()+ 5)+'px')}).hide();obj.after(results).keyup(keyListener).blur(function(e){var resPos=$(results).offset();resPos.bottom=resPos.top+ $(results).height();resPos.right=resPos.left+ $(results).width();if(pageY<resPos.top||pageY>resPos.bottom||pageX<resPos.left||pageX>resPos.right){$(results).hide();}}).focus(function(e){$(results).css({'top':(obj.position().top+ obj.height())+'px','left':(obj.position().left-10)+'px'});if($('div',results).length>0){$(results).show();}}).attr('autocomplete','off');$().mousemove(function(e){pageX=e.pageX;pageY=e.pageY;});if($.browser.opera){obj.keydown(function(e){if(e.keyCode===40){return keyListener(e);}});}
settings.notCharacter=regexEscape(settings.notCharacter||'');if(!settings.ajaxResults){if(typeof searchData==='function'){searchData=searchData();}
if(typeof searchData==='string'){searchData=JSON.parse(searchData);}}});};})(jQuery);
