var ajaxtags = {
	// Settings
	elmIdToPresentResultsIn : "searchResults",
	elmIdResultsContainer : "searchResultAjaxTags",
	charactersBeforeSearch : 0,
	timeBeforeSuggest : 100, // In milliseconds
	sameWidthAsInputElm : false,
	offsetLeft: 0,
	offsetTop : 0,
	urlExt : "search=",
	addSearchTermToQueryString : true,
	addKeyNavigationEvents : true,
	hideResultsOnDocumentClick : false,
	itemClassName : "item",
	itemSelectedClassName : "selected",
	itemInsertValueIntoInputClassName : "chooseValue",
	itemInsertValueSetFocusToInput : true,
	hideResultsWhenInsertValueIsSelected : true,
	itemSeparator : ",",
	turnAutoCompleteOff : true,
	// Object properties
	req : null,
	elements : [],
	timer : null,
	currentElm : null,
	currentKeyEvent : null,
	suggestionsForElm : null,
	elmToPresentResultsIn : null,
	elmResultsContainer : null,
	suggestions : [],
	resultIndex : 0,
	selectedItem : -1,
	resultsAreVisible : false,
	valueAddedFromResultsListToInput : true,
	fullView : false,
	
	init : function (){
		if(typeof document.getElementsByClassName != "function"){
			document.getElementsByClassName = this.elmByClass;
		}
		this.elements = document.getElementsByClassName("KeywordSearch", "input");
		this.applyEvents();
		this.elmToPresentResultsIn = document.getElementById(this.elmIdToPresentResultsIn);
		this.elmResultsContainer = document.getElementById(this.elmIdResultsContainer);
		if(this.addKeyNavigationEvents){
			this.addEvent(document, "keydown", this.preventDefaultForArrowKeys);
			this.addEvent(document, "keypress", this.preventDefaultForArrowKeys);
			this.addEvent(document, "keyup", this.navigateResults);
		}
		if(this.hideResultsOnDocumentClick){
			this.addEvent(document, "click", this.clearResultsElement);
		}
        this.req=new j2httpRequest_js();
	},
	
	applyEvents : function (){
		var element;
		for(var i=0; i<this.elements.length; i++){
			element = this.elements[i];
			if(this.turnAutoCompleteOff){
				element.setAttribute("autocomplete", "off");
			}
			this.addEvent(element, "keyup", this.startSuggestionsTimer);
			if(this.hideResultsOnDocumentClick){
				this.addEvent(element, "click", this.preventInputClickBubbling);
			}
		}
	},
	
	startSuggestionsTimer : function (evt){
		clearTimeout(ajaxtags.timer);
		ajaxtags.currentElm = (/input/i.test(this.nodeName))? this : evt.srcElement;
		ajaxtags.currentKeyEvent = evt.keyCode;
		ajaxtags.timer = setTimeout("ajaxtags.getSuggestions()", ajaxtags.timeBeforeSuggest);
	},

	getButtonClick : function (field){
		this.hideResultsOnDocumentClick=false;
		this.fullView=true;
		this.currentElm=field;
//		this.applyEvents();
		this.getSuggestions();
		this.hideResultsOnDocumentClick=true;
		return false;
	},
	
	getSuggestions : function (){	
		var value = this.currentElm.value;
		var tags  = value.split(ajaxtags.itemSeparator);
		if(!/13|27|37|39/.test(this.currentKeyEvent)){
			var url = this.currentElm.className.replace(/.*url-([\w\/\?\.-]+).*/, "$1");
			if(!this.valueAddedFromResultsListToInput){
				ajaxtags.clearResults(true);
			}
			if((tags[tags.length-1].length > this.charactersBeforeSearch && url.length > 0)||this.fullView){
				this.makeSuggestionCall(value, url);
			}
			else if(tags[tags.length-1].length == 0 || !this.valueAddedFromResultsListToInput){
				ajaxtags.clearResults();
			}
		}
	},
	
	makeSuggestionCall : function (value, url){
		var regExpValue = new RegExp(("^" + value + "$"), "i");
		var exists = this.suggestions.length != 0;
		var suggestionItem;
		var url = url + ((/\?/.test(url))? "&" : "?") + this.urlExt + ((this.addSearchTermToQueryString)? value : "");
		this.currentValue = value;
		this.currentURL = url;
		for(var i=0; i<this.suggestions.length; i++){
			suggestionItem = this.suggestions[i];
			exists = true;
			this.resultIndex = i;
			this.presentResult(this.suggestions[i][1]);
			break;
		};
		if(!exists){
			this.req=null;
			this.req=new j2httpRequest_js();
			this.req.onreadystatechange = function (){};
			this.req.abort();
			this.req.open("GET", url, true);
			this.req.onreadystatechange = this.getResults;
			this.req.send({id:this.currentElm.form,'keywords':keywords});
		}
	},
	
	getResults : function (){
		if(ajaxtags.req.readyState == 4 && ajaxtags.req.responseJS.tags.length > 0){
			ajaxtags.loadResults();
		}
	},
	
	loadResults : function (){
		this.resultIndex = this.suggestions.length;		
		this.suggestions.push([this.currentValue,ajaxtags.req.responseJS.tags,this.currentURL]);
		this.presentResult();
	},
	
	presentResult : function (){
		var tags = this.suggestions[this.resultIndex][1];
		var tag  = this.currentValue.split(ajaxtags.itemSeparator);		
		var html = "<h4>Search suggestions:</h4>";
		var lis = "";
		var str = "";
		var hash = ">"+this.trim(tag[tag.length-1].toUpperCase());
		for (var i=0;i<tags.length;i++)
		{
			str = tags[i].toUpperCase();
			if (str.indexOf(hash)!=-1 || this.fullView)
			{
				lis+="<li>"+tags[i]+"</li>";
			}
		}
		html += "<ul>"+lis+"</ul>";
		this.elmToPresentResultsIn.innerHTML = html;
		var coordinates = this.getCoordinates();
		var elm = this.elmResultsContainer.style;
		elm.left = coordinates[0] + this.offsetLeft + "px";
		elm.top = coordinates[1] + this.currentElm.offsetHeight + this.offsetTop + "px";
		if(this.sameWidthAsInputElm){
			elm.width = this.currentElm.offsetWidth + "px";
		}
		this.applyResultEvents();
		elm.display = "block";
		this.resultsAreVisible = true;
		if(this.addKeyNavigationEvents && /38|40/.test(this.currentKeyEvent)||this.fullView){
			if(!this.valueAddedFromResultsListToInput){
				this.selectedItem = -1;
			}
			this.navigateResults(null, this.currentKeyEvent);
		}
		this.fullView = false;
	},
	
	clearResults : function (justClear){
		if(this.elmResultsContainer && this.elmToPresentResultsIn){
			if(!justClear){
				this.elmResultsContainer.style.display = "none";
				this.resultsAreVisible = false;
			}
			this.elmToPresentResultsIn.innerHTML = "";
			this.selectedItem = -1;
		}
	},
	
	clearResultsElement : function (){
		ajaxtags.clearResults();
	},

	trim : function (str){
	 return str.replace(/^\s*|\s*$/g,"");
	},
	
	navigateResults : function (evt, keyCode){
		if(ajaxtags.currentElm && ajaxtags.elmToPresentResultsIn){
			var event = (typeof evt != "undefined")? evt : event;
			if(typeof ajaxtags.elmToPresentResultsIn.getElementsByClassName != "function"){
				ajaxtags.elmToPresentResultsIn.getElementsByClassName = ajaxtags.elmByClass;
			}
			var results = ajaxtags.elmToPresentResultsIn.getElementsByClassName(ajaxtags.itemClassName);
			var selectedItem = (!evt && keyCode == 38)? results.length : ajaxtags.selectedItem;
			var keyCode;
			if (event) keyCode = keyCode || event.keyCode;
			var navigateUp = keyCode == 37 || keyCode == 38;
			var navigateDown = keyCode == 39 || keyCode == 40;
			if(results.length > 0 && (navigateUp || navigateDown)){
				if(navigateUp){
					if((selectedItem - 1) >= 0){
						selectedItem--;
					}
					else{
						selectedItem = -1;
					}
				}		
				else if(navigateDown){
					if((selectedItem + 1) < results.length){
						selectedItem++;
					}
					else{
						selectedItem = -1;				
					}
				}
				var item;
				var classToRemove;
				for(var i=0; i<results.length; i++){
					item = results[i];
					classToRemove = new RegExp((ajaxtags.itemSelectedClassName + "\s?"), "i");
					item.className = item.className.replace(classToRemove, "").replace(/^\s?|\s?$/g, "");
				};
				ajaxtags.selectedItem = selectedItem;
				var elmToFocus = ajaxtags.currentElm;
				if(selectedItem > -1){
					var currentItem = results[selectedItem];
					var currentClass = item.className;
					if(!new RegExp(ajaxtags.itemSelectedClassName, "i").test(currentClass)){
						currentItem.className = currentClass + ((currentClass.length > 0)? " " : "") + ajaxtags.itemSelectedClassName;
					}
					elmToFocus = results[selectedItem];
				}
				try{
					elmToFocus.focus();
				}
				catch(e){
					// Just in case... :-)
				}
				if(event){
					if(event.preventDefault){
						event.preventDefault();
					}
					else{
						event.returnValue = false;
					}
					if(event.stopPropagation){
						event.stopPropagation();
					}
					else{
						event.cancelBubble = true;
					}
				}
				return false;
			}			
			else if(keyCode == 27){
				ajaxtags.clearResults();
				try{
					ajaxtags.currentElm.focus();
				}
				catch(e){
					// Just in case... :-)
				}
			}
		}
	},
	
	applyResultEvents : function (){
		if(typeof this.elmToPresentResultsIn.getElementsByClassName != "function"){
			this.elmToPresentResultsIn.getElementsByClassName = this.elmByClass;
		}
		var insertValueItems = this.elmToPresentResultsIn.getElementsByClassName(this.itemInsertValueIntoInputClassName, "a");
		var item;
		for(var i=0; i<insertValueItems.length; i++){
			item = insertValueItems[i];
			item.inputRef = this.currentElm;
			this.addEvent(item, "click", this.insertValueIntoField);
		};		
	},
	
	insertValueIntoField : function (evt){
		var elm = (/a/i.test(this.nodeName))? this : evt.srcElement;		
		var input = elm.inputRef;
		var value = elm.firstChild.nodeValue;
		var tags  = input.value.split(ajaxtags.itemSeparator);
		if(!new RegExp(value).test(input.value) && tags.valueOf(value)){
			tags[tags.length-1] = value;
			input.value = tags.join(ajaxtags.itemSeparator);
		}
		if(evt.preventDefault){
			evt.preventDefault();
		}
		else{
			evt.returnValue = false;
		}
		if(evt.stopPropagation){
			evt.stopPropagation();
		}
		else{
			evt.cancelBubble = true;
		}
		if(ajaxtags.itemInsertValueSetFocusToInput){
			try{
				input.focus();
			}
			catch(e){
				// Just in case... :-)
			}
		}
		if(ajaxtags.hideResultsWhenInsertValueIsSelected){
			ajaxtags.clearResults();
		}
		ajaxtags.valueAddedFromResultsListToInput = true;
	},
	
	preventInputClickBubbling : function (evt){
		if(evt.preventDefault){
			evt.preventDefault();
		}
		else{
			evt.returnValue = false;
		}
		if(evt.stopPropagation){
			evt.stopPropagation();
		}
		else{
			evt.cancelBubble = true;
		}
		return false;
	},
	
	preventDefaultForArrowKeys : function (evt){
		var keyCode = evt.keyCode;
		var navigateUp = keyCode == 37 || keyCode == 38;
		var navigateDown = keyCode == 39 || keyCode == 40;
		if((!evt.ctrlKey && !evt.metaKey) && ajaxtags.resultsAreVisible && (navigateUp || navigateDown)){
			if(evt.preventDefault){
				evt.preventDefault();
			}
			else{
				evt.returnValue = false;
			}
			if(evt.stopPropagation){
				evt.stopPropagation();
			}
			else{
				evt.cancelBubble = true;
			}
			return false;
		}	
	},
	
	getCoordinates : function (){
		var elm = this.currentElm;
		var offsetLeft = 0;
		var offsetTop = 0;
		while(elm.offsetParent){
			offsetLeft += elm.offsetLeft;
			offsetTop += elm.offsetTop;
			if(elm.scrollTop > 0){
				offsetTop -= elm.scrollTop;
			}
			elm = elm.offsetParent;
		}
		return [offsetLeft, offsetTop];
	},
	
	closeSession : function (){
		delete ajaxtags;
		ajaxtags = null;
	},
	
	elmByClass : function (className, tag){
		return ajaxtags.getElementsByClassName.call(this, className, tag);
	},
	
	getElementsByClassName : function (className, tag){		
		var elms = ((!tag || tag == "*") && this.all)? this.all : this.getElementsByTagName(tag || "*");
		var returnElms = [];
		var className = className.replace(/\-/g, "\\-");
		var regExp = new RegExp("(^|\\s)" + className + "(\\s|$)");
		var elm;
		for(var i=0; i<elms.length; i++){
			elm = elms[i];		
			if(regExp.test(elm.className)){
				returnElms.push(elm);
			}
		}
		return (returnElms);
	},

	addEvent : function (elm, evt, func){
		if(elm){
			if(elm.addEventListener){
				elm.addEventListener(evt, func, false);
			}
			else if(window.attachEvent){
				elm.attachEvent(("on" + evt), func)
			}
		}
	}
};
String.prototype.ltrim = function() { 
    return this.replace(/^\s+/, ''); } 

String.prototype.rtrim = function() { 
    return this.replace(/\s+$/, ''); } 

String.prototype.trim = function() { 
    return this.ltrim().rtrim(); } 
// ---
ajaxtags.addEvent(window, "load", function(){ajaxtags.init();});
ajaxtags.addEvent(window, "unload", function(){ajaxtags.closeSession();});
// ---