/*-------------------------------------------------------------------
	Title: Javascript autocomplete text box with drop down list
	Author: Matt Guibord
	Date: 9-2008
	
	Instructions:
	
	To create an autocomplete text box, call vuDAT_ACT.initialize function on page load:
		vuDAT_ACT.initialize(myField, dataArray, optionsHash);
	Where:
		myField - text field to be used
		dataArray - array of data elements
			NOTE: If elements are presorted, setup over head is GREATLY reduced
		optionsHash - Javascript Object - object of options
			SelectedClass   - String    - class of selected item in drop down list
			UnselectedClass - String    - class of unselected item in drop down list
			DropDownClass   - String    - class of drop down list
			Case            - bool      - true if case of selection matters
			Submit          - function  - function to call when enter is pressed
				NOTE: If the text field is blank and enter is pressed,
					"" is passed to submit.
			Sort			- bool		- true if data needs to be sorted (must be sorted to work)
				NOTE: sorting comes with a great deal of overhead, always pass dataArray as a sorted
					array when possible.
			HashedData		- bool		- true if data is prehashed
			Clickable		- bool		- true if drop down items should be clickable
			DropDownNum		- int		- number of items to show in drop down, default is 10
			
			
-------------------------------------------------------------------*/
vuDAT_ACT_css = window.vuDAT_ACT_css || "vuDAT_ACT.css";
vuDAT_ACT = {
	ACT_Options: [],
	noEventKeys: [8,13,16,17,18,20,27,33,34,35,36,37,38,39,40,45,46,91,92,93],
	numACT: 0,
	initialize: function(myField, dataArray, optionsHash) {
		//<![CDATA[
		// loading the stylesheet into the document header
		if(document.createStyleSheet) { // non-standard IE way of doing it
			document.createStyleSheet(vuDAT_ACT_css);
		} else { // do it the W3C DOM way
			var newCSS=document.createElement('link');
			newCSS.rel='stylesheet';
			newCSS.href=vuDAT_ACT_css;
			newCSS.type='text/css';
			document.getElementsByTagName("head")[0].appendChild(newCSS);
		}
		//]]>
		vuDAT_ACT.ACT_Options[vuDAT_ACT.numACT] = {};
		var obj = vuDAT_ACT.ACT_Options[vuDAT_ACT.numACT];
		obj.numACT = vuDAT_ACT.numACT++;
		myField.value = "";
		obj.searchNum = 0;
		obj.myField = myField;
		vuDAT_ACT.parseOptions(obj,optionsHash);
		vuDAT_ACT.insertDropDownDiv(obj);
		if(optionsHash.HashedData == false || optionsHash.HashedData === undefined) {
			if(optionsHash.Sort == true) {
				if(obj.Case) {
					dataArray.sort();
				}
				else{ 
					dataArray.sort( 
						function (a, b) {
							var anew = a.toLowerCase();
							var bnew = b.toLowerCase();
							if (anew < bnew) { 
								return -1;
							}
							if (anew > bnew) {
								return 1;
							}
							return 0;
						}
					);
				}
			}
			vuDAT_ACT.hashData(dataArray,obj);
		} else {
			obj.data = dataArray;	
		}
		vuDAT_ACT.noEventKeys.sort(function(a, b) {return (a-b);});
		obj.myField.onkeydown = function(event) {
			++obj.currentSearch;
			if(event) {
				e = event;
				key = e.which;
			} else {
				e = window.event;
				key = e.keyCode;
			}
			obj.lastKey = key;
			if(key == 13) { //enter key submit action
				if(e.preventDefault) {
					e.preventDefault();
				} else {
					e.returnValue = false;
				}
				if(obj.myField.value === "" ) {
					obj.Submit("");
				} else {
					var exactMatch = vuDAT_ACT.findMatch(obj.myField.value,obj,true,obj.searchNum++);
					if(exactMatch !== -1) {
						obj.Submit(exactMatch);
					} else {
						alert("No Match for " + obj.myField.value + " found.");
					}
				}
			} else if((key == 38 && obj.dropDownIndex > 0) || (key == 40  && obj.dropDownIndex < obj.dropDownContents.length-1)) { //scrolling through drop down div
				if(obj.dropDownContents.length > 0 && obj.dropDownDiv.style.display != "none") {
					var lastSelection = obj.dropDownDiv.getElementsByTagName("div")[obj.dropDownIndex];
					if(key == 38) {
						newSelection = obj.dropDownDiv.getElementsByTagName("div")[--obj.dropDownIndex]; 
					} else { 
						newSelection = obj.dropDownDiv.getElementsByTagName("div")[++obj.dropDownIndex]; 
					}
					var newValue = newSelection.innerHTML;
					vuDAT_ACT.fillAndSelect(newValue,obj.typedText.length,newSelection.innerHTML.length,obj,"noKey");
					lastSelection.className = obj.UnselectedClass; 
					newSelection.className = obj.SelectedClass;
					e.preventDefault();
				}
			}
		};
		obj.myField.onkeyup = function(event) {
			if(event) {
				e = event;
				key = e.which;
			} else {
				e = window.event;
				key = e.keyCode;
			}
			obj.currentSearch = obj.searchNum;
			if(key == 8) {
				obj.typedText = obj.myField.value;
				if(obj.myField.value === "") {
					obj.dropDownDiv.style.display = "none"; 
				} else { 
					vuDAT_ACT.findMatch(obj.myField.value,obj,false,obj.searchNum++); 
				}
			}
			vuDAT_ACT.autoComplete(key, e.altKey || e.ctrlKey, obj, obj.searchNum);
			if(key == 38 || key == 40) {
				e.preventDefault(); 
			}
		};
		obj.myField.onkeypress = function(event) {
			if(event) {
				e = event;
				key = e.which;
			} else {
				e = window.event;
				key = e.keyCode;
			}
			obj.currentSearch = obj.searchNum;
			if(key == 38 || key == 40) {
				e.preventDefault();
			}
		};
		obj.myField.onblur = function() {
			if(obj.Clickable){
				setTimeout(function(){obj.dropDownDiv.style.display = "none";},200);
			} else {
				obj.dropDownDiv.style.display = "none";
			}
		};
		obj.myField.onfocus = function() {
			obj.typedText = obj.myField.value;
			vuDAT_ACT.positionDropDown(obj);
			if(obj.myField.value === "") {
				obj.dropDownDiv.style.display = "none";
			} else {
				vuDAT_ACT.findMatch(obj.myField.value,obj,false,obj.searchNum++);
			}
		};
	},
	getHashedData: function(index){
		return vuDAT_ACT.ACT_Options[index].data;
	},
	parseOptions: function(obj, optionsHash) {
		if(optionsHash.SelectedClass !== undefined) {
			obj.SelectedClass = optionsHash.SelectedClass;
		} else {
			obj.SelectedClass = "dropDownSelected";
		}
		if(optionsHash.UnselectedClass !== undefined) {
			obj.UnselectedClass = optionsHash.UnselectedClass;
		} else {
			obj.UnselectedClass = "dropDownUnselected";
		}
		if(optionsHash.DropDownClass !== undefined) {
			obj.DropDownClass = optionsHash.DropDownClass;
		} else {
			obj.DropDownClass = "dropDownBox";
		}
		obj.Submit = optionsHash.Submit;
		if(optionsHash.Case !== undefined) {
			obj.Case = optionsHash.Case;
		} else {
			obj.Case = false;
		}
		if(optionsHash.Clickable !== undefined) {
			obj.Clickable = optionsHash.Clickable;
		} else {
			obj.Clickable = false;
		}
		if(optionsHash.DropDownNum !== undefined) {
			obj.DropDownNum = optionsHash.DropDownNum;
		} else {
			obj.DropDownNum = 10;
		}
	},
	insertDropDownDiv: function(obj) {
		newDiv = document.createElement("div");
		newDiv.style.position = "absolute";
		newDiv.className = obj.DropDownClass;
		newDiv.style.display = "none";
		obj.myField.parentNode.insertBefore(newDiv, obj.myField.nextSibling);
		obj.dropDownDiv = newDiv;
	},
	positionDropDown: function(obj) {
		var curleft = curtop = 0;
		var offsetObj = obj.myField;
		if (offsetObj.offsetParent) {
			do {
				curleft += offsetObj.offsetLeft;
				curtop += offsetObj.offsetTop;
			} while (offsetObj = offsetObj.offsetParent);
		}
		obj.dropDownDiv.style.top = curtop + obj.myField.offsetHeight + "px";
		obj.dropDownDiv.style.left = curleft+"px";
		obj.dropDownDiv.style.width = (obj.myField.offsetWidth-2) + "px";
	},
	autoComplete: function(myKey,cmdKey,obj,searchNum) {
		if(myKey != "noKey") {
			var keyGood = vuDAT_ACT.checkKey(myKey);
		}
		if((keyGood && !cmdKey) || myKey == "noKey") {
			obj.typedText = obj.myField.value;
			var matched = vuDAT_ACT.findMatch(obj.typedText,obj,false,obj.searchNum++);
			if(matched !== -1 && searchNum == obj.currentSearch) {
				vuDAT_ACT.fillAndSelect(obj.typedText+matched, obj.typedText.length, (obj.typedText+matched).length, obj, myKey);
			}
		}
	},
	fillAndSelect: function(value, start, end, obj, myKey) {
		myField = obj.myField;
		if(myKey == obj.lastKey || myKey == "noKey") {
			if (myField.createTextRange) {
				myField.value = value;
				var oRange = myField.createTextRange();
				oRange.moveStart("character", start);
				oRange.moveEnd("character", end);
				oRange.select();
			} else if (myField.setSelectionRange) {
				myField.value = value;
				myField.setSelectionRange(start, end);
			}
		}
	},
	checkKey: function(key) {
		for(i = 0; i < vuDAT_ACT.noEventKeys.length; ++i) {
			if(key == vuDAT_ACT.noEventKeys[i]) {
				return false;
			}
		}
		return true;
	},
	hashData: function(dataArray,obj) {
		obj.data = [];
		for(i = 0; i < dataArray.length; ++i) {
			if(dataArray[i] !== "") {
				if(obj.Case) {
					hashTerm = dataArray[i].charAt(0).charCodeAt(0);
				} else {
					hashTerm = dataArray[i].charAt(0).toLowerCase().charCodeAt(0);
				}
				if(obj.data[hashTerm] === undefined) {
					obj.data[hashTerm] = [];
				}
				obj.data[hashTerm][obj.data[hashTerm].length] = dataArray[i];
			}
		}
	},
	findMatch: function(text,obj,exact,searchNum) {
		obj.currentSearch = searchNum;
		if(!obj.Case) {
			text = text.toLowerCase();
		}
		var hashIndex = text.charAt(0).charCodeAt(0);
		if(obj.data[hashIndex] !== undefined) {
			for(i = 0; i < obj.data[hashIndex].length; ++i) {
				if(searchNum != obj.currentSearch) {
					return -1;
				}
				testStr = obj.data[hashIndex][i].substr(0,text.length);
				if(!obj.Case) {
					testStr = testStr.toLowerCase();
				}
				if(testStr === text) {
					if(exact) {
						return obj.data[hashIndex][i];
					} else {
						vuDAT_ACT.populateDropDown(hashIndex,i,text,obj);
						return obj.dropDownContents[0].substr(text.length);
					}
				}
			}
		}
		if(!exact) {
			obj.dropDownContents = [];
			vuDAT_ACT.fillDropDown(obj);
		}
		return -1;
	},
	populateDropDown: function(hashIndex,i,text,obj) {
		obj.dropDownContents = [];
		for(j = 0; j < obj.DropDownNum && i+j < obj.data[hashIndex].length; ++j) {
			testStr = obj.data[hashIndex][i+j].substr(0,text.length);
			if(!obj.Case) {
				testStr = testStr.toLowerCase();
			}
			if(testStr === text) {
				obj.dropDownContents[j] = obj.data[hashIndex][i+j];
			} else {
				break;
			}
		}
		vuDAT_ACT.fillDropDown(obj);
	},
	fillDropDown: function(obj) {
		if(obj.dropDownContents.length > 0) {
			var addStr = "";

			obj.dropDownDiv.innerHTML = "";
			for(i = 0; i < obj.dropDownContents.length; ++i) {
				addStr = addStr + "<div class=\"";
				if(i === 0) {
					addStr = addStr + obj.SelectedClass;
				} else {
					addStr = addStr + obj.UnselectedClass;
				}
				if(obj.Clickable){
					addStr = addStr + "\" onmouseup=\"vuDAT_ACT.dropDownClick(" + obj.numACT + ",'" + obj.dropDownContents[i] + "');\"";	
				}
				addStr = addStr +  "\">" + obj.dropDownContents[i] + "</div>";
			}
			obj.dropDownIndex = 0;
			obj.dropDownDiv.innerHTML = addStr;
		} else {
			obj.dropDownIndex = "";
			obj.dropDownDiv.innerHTML = "<div class='"+obj.UnselectedClass+"'>No Matches</div>";	
		}
		obj.dropDownDiv.style.display = "block";
	},
	dropDownClick: function(index, text){
		obj = vuDAT_ACT.ACT_Options[index];
		obj.myField.value = text;
		obj.Submit(text);
	}
};