
var KeywordController = function( keywordInput, ajaxUrl, keywordTable, existingKeywords){
	var thisObj = this;
	var xmlhttp;
	var cursorPos = -1;
	var currentSuggestion = -1;
	var lastSuggestion = "";
	var input = -1;
	var searchBox;
	var addButton;
	var url = ajaxUrl;
	var numKeywordsInput;
	var suggestionContainer;
	var numDisplayedSuggestions = 5;
	var keywordContainer;
	var keywords = Array();
	var suggestions = Array();
	
	// set up the search controls
	searchContainer = document.createElement("DIV");
	searchContainer.id = keywordInput.id + "_searchContainer";

	searchBox = document.createElement("INPUT");
	searchBox.id = keywordInput.id;
	searchBox.setAttribute("autocomplete", "off"); 
	
	addButton = document.createElement("DIV");
	addButton.id = searchBox.id + "_addButton";

	suggestionContainer = document.createElement('DIV');
	suggestionContainer.id = searchBox.id + "_suggestionContainer"; 
	suggestionContainer.className = "suggestionContainer";
	
	numKeywordsInput = document.createElement('INPUT');
	numKeywordsInput.name = searchBox.id + "_numKeywordsInput";
	numKeywordsInput.type = "hidden";
	numKeywordsInput.value = keywords.length;
	
	keywordContainer = document.createElement('DIV');
	keywordContainer.id = searchBox.id + "_keywordContainer";
	keywordContainer.className = "keywordContainer"; 	

	keywordInput.parentNode.replaceChild( searchContainer, keywordInput );	
	searchContainer.appendChild( searchBox );
	searchContainer.appendChild( addButton );
	searchContainer.appendChild( suggestionContainer );
	searchContainer.appendChild( numKeywordsInput );
	searchContainer.appendChild( keywordContainer );

	searchBox.onkeyup = function(e) { 
		input = e.keyCode;
		if ( input == 8 && lastSuggestion != "") {		// Backspace pressed
			lastSuggestion = "";
			suggestions[currentSuggestion].className = "suggestion";
			currentSuggestion = -1;
		} else if ( input == 38 || input == 40 ) { 		// UP or DOWN arrow key pressed
			thisObj.navigate( input );
 		} else if ( ( input == 37 || input == 39 ) && lastSuggestion == "" ){ 	// LEFT or RIGHT arrow pressed
			
		} else {
			thisObj.getSuggestions( searchBox.value );
			if ( input == 8) cursorPos--; 						// Backspace pressed
			else if ( input >= 65 && input <= 122 ){			// Character entered
				cursorPos++;	
			} else if ((input == 37 || input == 39) && lastSuggestion != ""){	// LEFT or RIGHT arrow pressed
				lastSuggestion = "";
				suggestions[currentSuggestion].className = "suggestion";
				currentSuggestion = -1;				
			}
		}		
	};
	searchBox.onkeydown = function(e) { 
		cursorPos = searchBox.selectionStart;				
		if (!e) var e = window.event;
		if ( e.keyCode == 13 ){								// Enter key pressed
			if ( searchBox.value != "" ) thisObj.addKeyword( searchBox.value );
			return false;	//cancels default action of the event
		} else if ( e.keyCode == 38 || e.keyCode == 40 ){	//UO or DOWN arrow key pressed
			return false;	//cancels default action of the event
		} 
	};
	searchBox.onblur = function() { 
		if ( searchBox.value != "" ) thisObj.addKeyword( searchBox.value );
		thisObj.hideSuggestions() 
	};
	searchBox.onclick = function(e){
		if ( searchBox.value != "" ) thisObj.getSuggestions( searchBox.value, e );
	}
	addButton.onclick = function(e) {
		if ( searchBox.value != "" ) thisObj.addKeyword( searchBox.value );
		return false;	//cancels default action of the event
	}

	this.addKeyword = function ( word ){
		lastSuggestion = "";
		for ( var i = 0; i < keywords.length; i++ ){	// Check if keyword was already inputted
			 if ( keywords[i].getName()	== word ) {
				searchBox.value = "";
				return;
			}
		}
		var newKeyword = new Keyword( word, searchBox.id );
		newKeyword.setIndex( keywords.length );
		keywords.push( newKeyword );
		numKeywordsInput.value = keywords.length;
		newKeyword.getdbox().onclick = function(){ thisObj.removeKeyword( newKeyword );};
		keywordContainer.appendChild( newKeyword.getdbox() );
		searchBox.value = "";
	}

	this.removeKeyword = function( keywordObject ){
		keywords.splice( keywordObject.getIndex(), 1 );
		keywordContainer.removeChild( keywordObject.getdbox() );
		for ( var i = 0; i < keywords.length; i++ ) {		// Reset keyword indeces
			keywords[i].setIndex(i);
		}
		numKeywordsInput.value = keywords.length;
	}

	this.getSuggestions = function( str ){
		if ( str.length == 0 ){
			thisObj.hideSuggestions();
			return;
		}
		
		xmlhttp = getXmlHttpObject();
		if ( xmlhttp == null ){
			alert ("Your browser does not support XMLHTTP!");
			return;
		}

		xmlhttp.onreadystatechange = thisObj.stateChanged;
		xmlhttp.open( "GET", url + "?str=" + str + "&table=" + keywordTable + "&sid=" + Math.random(), true );
		xmlhttp.send( null );
	}

	this.hideSuggestions = function(){
		currentSuggestion = -1;
		while ( suggestionContainer.hasChildNodes() ) {
			suggestionContainer.removeChild( suggestionContainer.childNodes[0] );
		}
		suggestionContainer.style.display = 'none';
	}

	this.showSuggestions = function(){
		suggestionContainer.style.display = 'block';
	}

	this.navigate = function( input ){			
		if (currentSuggestion == -1){
			if (input == 40) currentSuggestion = 0;
		} else if (currentSuggestion >= 0 && currentSuggestion < suggestions.length-1){
			if (input == 40) {
				suggestions[currentSuggestion++].className = "suggestion";
			} else if (input == 38) {
				suggestions[currentSuggestion--].className = "suggestion";
			}
		} else if (currentSuggestion == suggestions.length-1){
			if (input == 38) {
				suggestions[currentSuggestion--].className = "suggestion";
			}
		}
		
		if ( currentSuggestion >= 0 && currentSuggestion < suggestions.length ){
			thisObj.highlightSuggestion(suggestions[currentSuggestion]);
		} else if ( currentSuggestion == -1 ){
			lastSuggestion = ""; 
			var searchBoxVal = searchBox.value;
			searchBox.value = searchBoxVal.substring( 0, cursorPos );
		}
	}
	
	this.mouseSelect = function( selectedSuggestion ){
		var suggestions = suggestionContainer.getElementsByTagName("div");
		var suggestionCount = suggestions.length;
		for ( i = 0; i < suggestionCount; i++ ){
			if ( suggestions[i].className == "suggestionSelected" )	suggestions[i].className = "suggestion"; 
			if ( selectedSuggestion == suggestions[i] ) currentSuggestion = i;
		}
		thisObj.highlightSuggestion( selectedSuggestion )
	} 
	
	this.highlightSuggestion = function( selectedSuggestion ){
		selectedSuggestion.className = "suggestionSelected";
		searchBox.value = selectedSuggestion.innerHTML;
		lastSuggestion = selectedSuggestion.innerHTML;
		searchBox.setSelectionRange( cursorPos, searchBox.value.length );
		searchBox.focus();	
	}
	
	this.stateChanged = function() {
		thisObj.hideSuggestions();
		if ( xmlhttp.readyState == 4 ){
			var response = eval("(" + xmlhttp.responseText + ")");
			suggestions = [];
			if ( response.suggestions.length > 0 ){
				for (var i = 0; i < response.suggestions.length && i < numDisplayedSuggestions; i++ ){
					var suggestion = document.createElement("DIV");
					suggestion.className = "suggestion";
					suggestion.innerHTML = response.suggestions[i];
					suggestion.onmouseover = function(e){ thisObj.mouseSelect( this ); };
					suggestionContainer.appendChild(suggestion);
					suggestions.push( suggestion );				
					if ( input!= 37 && input != 39 && suggestion.innerHTML == lastSuggestion) {
						thisObj.highlightSuggestion( suggestion );
						currentSuggestion = i;
					}
				}
				thisObj.showSuggestions();
			} 
		}
	}

	function getXmlHttpObject() {
		if (window.XMLHttpRequest) {
			// code for IE7+, Firefox, Chrome, Opera, Safari
			return new XMLHttpRequest();
		}
		if (window.ActiveXObject){
			// code for IE6, IE5
			return new ActiveXObject("Microsoft.XMLHTTP");
		}
		return null;
	}

	for ( var i = 0; i < existingKeywords.length; i++ ) {
		this.addKeyword(existingKeywords[i]);
	}
	
}

function Keyword( name, searchBoxId ){
	var name = name;
	var index;
	var dbox;
	var keywordInput;
	var searchBoxId = searchBoxId;
	
	dbox = document.createElement('DIV');
	dbox.className = searchBoxId+"_keywordBox";

	span = document.createElement('SPAN');
	span.innerHTML = name;

	keywordInput = document.createElement('INPUT');
	keywordInput.type = "hidden";
	keywordInput.value = name;
	
	dbox.appendChild( span );
	dbox.appendChild( keywordInput );
	
	this.getdbox = function(){ return dbox; };
	this.getName = function(){ return name; };
	this.getIndex = function(){ return index; };
	this.setIndex = function( newIndex ){ 
		index = newIndex; 
		keywordInput.name = searchBoxId + "_keywordInput_" + newIndex;
	}
	
	return true;
}
