var keyTime, keyStr = '', allOpts, lastElement;
var agt = navigator.userAgent.toLowerCase();
//var is_ie = ((agt.indexOf("msie") != -1) && (agt.indexOf("opera") == -1));
var is_gecko = (agt.indexOf("gecko") != -1);
function populate(srcEvent)
{
	var element = (srcEvent)? ((srcEvent.target)? srcEvent.target : srcEvent.srcElement) : window.event.srcElement;
	if(lastElement != element)
	{
		allOpts = new Array();
		for(var i = 0; i < element.options.length; i++)
		allOpts[i] = element.options[i].text.toLowerCase();
		lastElement = element;
	}
}
function setSelection(srcEvent)
{				
	var myEvent = (srcEvent)? srcEvent : window.event;
	var element = (myEvent.target)? myEvent.target : myEvent.srcElement;
	var keyCode = myEvent.keyCode;
	// messy JS keycodes force me to preprocess. Note: I use a US keyboard, other keyboards may vary?
	if((keyCode > 47 && keyCode < 58) || (keyCode > 64 && keyCode < 91 || keyCode == 32)) ; // space or alphanumerical characters, leave them alone
	else if(keyCode > 95 && keyCode < 106) keyCode -= 48; // keypad numbers
	else if(keyCode > 105 && keyCode < 112) keyCode -= 64; // keypad '+', '-', '/', '*', '.'
	else if(keyCode > 187 && keyCode < 192) keyCode -= 144; // '/', '.', ',', '-'
	else if(keyCode > 218 && keyCode < 222) keyCode -= 128; // '\', '[', ']'
	else
	{
		switch(keyCode)
		{
		case 187: keyCode = 61; break; // '='
		case 222: keyCode = 39; break; // '''
		case 192: keyCode = 96; break; // '`'
		case 186: keyCode = 59; break; // ';'
		default: return; // do not process non printable characters (unfortunately backspace cannot be supported because browsers like IE interpret backspace as go back a page in history)
		}
	}
	var currentKey = String.fromCharCode(keyCode).toLowerCase();
	var idx, currentSIdx = element.selectedIndex, useOld = false;
	var newTime = new Date().getTime();
	if(keyTime != null && newTime - keyTime < 1000) // do type-ahead if two keys were pressed within 500 milliseconds (0.5 second, one can change this value for customization)
	{
		keyStr += currentKey;
		idx = findIdx();
		if(idx == -1) return; // not found, keep current selection then (leave the incorrect keyStr alone)
	}
	else // unfortunately we seem to have to handle default browser behavior too
	{
		keyStr = currentKey;
		// behavior should be: if next option is available and begins with the same character, select the next option
		// when there is either no more option, or no more option that begins with the same character as the current option,
		// then select the first option that starts with the currentKey
		idx = currentSIdx + 1;
		if(idx >= allOpts.length || allOpts[idx].length == 0 || allOpts[idx].charAt(0) != keyStr)
		idx = findIdx();
	}
	if(idx >= 0) // if keyStr is found in an option, select the option
	{
		element.options[currentSIdx].selected = false;
		// gecko-based browsers have a very strange bug that strikes when user presses
		// the same character multiple times (like 'AAA', 'BBBB'), which could be "fixed"
		// in a strange way too (actually the idx > 0 test is not even necessary!)
		// first make a pattern to check if it's same character multiple times
		var pattern = new RegExp('^' + keyStr.charAt(0) + '+$', "i");
		if(is_gecko && pattern.test(keyStr) && idx > 0) element.options[idx-1].selected = true;
		else element.options[idx].selected = true;
	}
	keyTime = newTime;
}
function findIdx()
{
	// full scan to find the smallest idx that match string keyStr (case-insensitive)
	var len = keyStr.length;
	for(var i = 0; i < allOpts.length; i++)
		if(allOpts[i].length >= len && allOpts[i].substring(0, len) == keyStr)
		return i;
	return -1;
}
