﻿
function AutoSuggest(elem, suggestions, divID, searchBeginningStringOnly, HighlightSelectedSuggestions) {

	//The 'me' variable allow you to access the AutoSuggest object
	//from the elem's event handlers defined below.
	var me = this;

	//A reference to the element we're binding the list to.
	this.elem = elem;
	this.suggestions = suggestions;

    // made to either look anywhere in the string or beginning of the string
    this.searchBeginningStringOnly = searchBeginningStringOnly;
    
    // made to hightlight selected values
    this.HighlightSelectedSuggestions = HighlightSelectedSuggestions;

	//Arrow to store a subset of eligible suggestions that match the user's input
	this.eligible = new Array();

	//The text input by the user.
	this.inputText = null;

	//A pointer to the index of the highlighted eligible item. -1 means nothing highlighted.
	this.highlighted = -1;

	//A div to use to create the dropdown.
	this.div = document.getElementById(divID);
	//hide div by default
	this.div.style.display = 'none';
	this.highlighted = -1;

	//Do you want to remember what keycode means what? Me neither.
	var TAB = 9;
	var ESC = 27;
	var ENTER = 13;
	var KEYUP = 38;
	var KEYDN = 40;
	

	//The browsers' own autocomplete feature can be problematic, since it will 
	//be making suggestions from the users' past input.
	//Setting this attribute should turn it off.
	elem.setAttribute("autocomplete","off");

	//We need to be able to reference the elem by id. If it doesn't have an id, set one.
	if(!elem.id) {
		var id = divID + '_' + idCounter;
		idCounter++;

		elem.id = id;
	}

    /********************************************************
	onblur event handler for the input elem.
	used to hide the menu if the focus is lost
	********************************************************/
    elem.onblur  = function() {
        me.useSuggestion();
		me.hideDiv();
    };
    
    /********************************************************
	onfocus event handler for the input elem.
	used to repopulate the suggestions when focus is gained
	********************************************************/
    elem.onfocus  = function() {
        elem.setSuggestionsBox();
    };
    
    /********************************************************
	Sets the suggestion box based on the input of the user
	********************************************************/
    elem.setSuggestionsBox = function() {
		
		//if (this.value != me.inputText && this.value.length > 0) {
	    if (this.value.length > 0) {
	        
		    me.inputText = this.value;
		    me.getEligible();
		    
		    // if no matches found, hide the div
		    if (me.eligible.length > 0) {
		        me.createDiv();
		        me.positionDiv();
		        me.showDiv();
		    } else {
		        me.hideDiv();
		    }
	    } else {
		    me.hideDiv();
	    }
	    
	};
       
    
	/********************************************************
	onkeydown event handler for the input elem.
	Tab key = use the highlighted suggestion, if there is one.
	Esc key = get rid of the autosuggest dropdown
	Up/down arrows = Move the highlight up and down in the suggestions.
	********************************************************/
	elem.onkeydown = function(ev) {
		var key = me.getKeyCode(ev);

		switch(key)	{
			case TAB:
			    me.useSuggestion();
			    break;
			  
			case ENTER:
			    me.useSuggestion();
			    break;

			case ESC:
			    me.hideDiv();
			    break;

			case KEYUP:
			    if (me.highlighted > 0) {
				    me.highlighted--;
			    }
			    me.changeHighlight(key);
			    break;

			case KEYDN:
			    if (me.highlighted < (me.eligible.length - 1))	{
				    me.highlighted++;
			    }
			    me.changeHighlight(key);
			    break;
		}
	};

	/********************************************************
	onkeyup handler for the elem
	If the text is of sufficient length, and has been changed, 
	then display a list of eligible suggestions.
	********************************************************/
	elem.onkeyup = function(ev) {
		var key = me.getKeyCode(ev);
		switch(key)	{
		    //The control keys were already handled by onkeydown, so do nothing.
		    case TAB:
		    case ENTER:
		    case ESC:
		    case KEYUP:
		    case KEYDN:
			    return;
		    default:
                elem.setSuggestionsBox();
		}
	};


	/********************************************************
	Insert the highlighted suggestion into the input box, and 
	remove the suggestion dropdown.
	********************************************************/
	this.useSuggestion = function()	{
		if (this.highlighted > -1)	{
		
		    // repace hightlighted text
		    var tempEligable = this.eligible[this.highlighted];
		    
		    // replace the highlight span
		    if (this.HighlightSelectedSuggestions == "True") {
		        tempEligable = tempEligable.replace(/<span class="suggestionHightlight">/g, '');
		        tempEligable = tempEligable.replace(/<\/span>/g, '');
		    }
		    
			this.elem.value =  tempEligable;
			this.hideDiv();
			//It's impossible to cancel the Tab key's default behavior. 
			//So this undoes it by moving the focus back to our field right after
			//the event completes.
			//setTimeout("document.getElementById('" + this.elem.id + "').focus()",0);
		}
	};

	/********************************************************
	Display the dropdown. Pretty straightforward.
	********************************************************/
	this.showDiv = function() {
		this.div.style.display = 'block';
	};

	/********************************************************
	Hide the dropdown and clear any highlight.
	********************************************************/
	this.hideDiv = function() {
		this.div.style.display = 'none';
		this.highlighted = -1;
	};

	/********************************************************
	Modify the HTML in the dropdown to move the highlight.
	********************************************************/
	this.changeHighlight = function()	{
		var lis = this.div.getElementsByTagName('LI');

		for (var i = 0; i < lis.length; i++) {
			var li = lis[i];

			if (this.highlighted == i)			{
				li.className = "selected";
			} else {
				li.className = "";
			}
		}
	};

	/********************************************************
	Position the dropdown div below the input text field.
	********************************************************/
	this.positionDiv = function() {
		var el = this.elem;
		var x = 0;
		var y = el.offsetHeight;
	
		//Walk up the DOM and add up all of the offset positions.
		while (el.offsetParent && el.tagName.toUpperCase() != 'BODY') {
			x += el.offsetLeft;
			y += el.offsetTop;
			el = el.offsetParent;
		}

		x += el.offsetLeft;
		y += el.offsetTop;

		this.div.style.left = x + 'px';
		this.div.style.top = y + 'px';
	};

	/********************************************************
	Build the HTML for the dropdown div
	********************************************************/
	this.createDiv = function() {
		var ul = document.createElement('ul');
	
		//Create an array of LI's for the words.
		for (var i = 0; i < this.eligible.length; i++) {

			var word = this.eligible[i];
	
			var li = document.createElement('li');
			var a = document.createElement('a');
			a.href="javascript:false";
			a.innerHTML = word;
			li.appendChild(a);
	
			if (me.highlighted == i) {
				li.className = "selected";
			}
	
			ul.appendChild(li);
		}
	
		this.div.replaceChild(ul,this.div.childNodes[0]);
	

		/********************************************************
		mouseover handler for the dropdown ul
		move the highlighted suggestion with the mouse
		********************************************************/
		ul.onmouseover = function(ev) {
			//Walk up from target until you find the LI.
			var target = me.getEventSource(ev);
			while (target.parentNode && target.tagName.toUpperCase() != 'LI') {
				target = target.parentNode;
			}
		
			var lis = me.div.getElementsByTagName('LI');
			
	        for (var i = 0; i < lis.length; i++) {
				var li = lis[i];
				if(li == target) {
					me.highlighted = i;
					break;
				}
			}
			me.changeHighlight();
		};

		/********************************************************
		click handler for the dropdown ul
		insert the clicked suggestion into the input
		********************************************************/
		ul.onclick = function(ev) {
			me.useSuggestion();
			me.hideDiv();
			me.cancelEvent(ev);
			return false;
		};
	
		this.div.className="suggestion_list";
		this.div.style.position = 'absolute';

	};

	/********************************************************
	determine which of the suggestions matches the input
	********************************************************/
	this.getEligible = function() {
		this.eligible = new Array();
		
		for (var i = 0; i < suggestions.length ; i++) {
	
			var suggestion = this.suggestions[i];
			
			if (this.searchBeginningStringOnly == "True") {
			    if(suggestion.toLowerCase().indexOf(this.inputText.toLowerCase()) == "0") {
			        this.setSuggestionText(suggestion);
			    }
		    } else {
		        if(suggestion.toLowerCase().indexOf(this.inputText.toLowerCase()) >= "0") {
				    this.setSuggestionText(suggestion);
			    }
		    }
			
		}
	};

    /********************************************************
	Sets the suggestion text of the matches found
	********************************************************/
    this.setSuggestionText = function(suggestion) {
		if (this.HighlightSelectedSuggestions == "True") {
		    // g = global, i = ignore case
		    if (this.searchBeginningStringOnly == "True") {
                this.eligible[this.eligible.length] = suggestion.replace(new RegExp( this.inputText , 'i'), '<span class="suggestionHightlight">$&</span>');
            } else {
                this.eligible[this.eligible.length] = suggestion.replace(new RegExp( this.inputText , 'gi'), '<span class="suggestionHightlight">$&</span>');
            }
	    } else {
	        this.eligible[this.eligible.length] = suggestion;
	    }
	};

	/********************************************************
	Helper function to determine the keycode pressed in a 
	browser-independent manner.
	********************************************************/
	this.getKeyCode = function(ev) {
		if(ev) {			//Moz
			return ev.keyCode;
		}
		if(window.event) {	//IE
			return window.event.keyCode;
		}
	};

	/********************************************************
	Helper function to determine the event source element in a 
	browser-independent manner.
	********************************************************/
	this.getEventSource = function(ev) {
		if(ev)	{		//Moz
			return ev.target;
		}
	
		if(window.event) {	//IE
			return window.event.srcElement;
		}
	};

	/********************************************************
	Helper function to cancel an event in a 
	browser-independent manner.
	(Returning false helps too).
	********************************************************/
	this.cancelEvent = function(ev)	{
		if(ev) {			//Moz
			ev.preventDefault();
			ev.stopPropagation();
		}
		if(window.event) {	//IE
			window.event.returnValue = false;
		}
	}
}

//counter to help create unique ID's
var idCounter = 0;

