/*
From http://www.mingyi.org/other/autocomplete.html
must add the following Attributes to the <SELECT> tag
onFocus=populate(event) onKeyDown=setSelection(event) onKeyPress="javascript:return false"
===================================================================================================
This javascript creates the "auto-complete" behavior for web forms
displayed in Internet Explorer (one may call the behavior "type-ahead", "find-as-you-type" etc.

This script is freeware by author Mingyi Liu and comes with no warranty whatsoever.
in no case should the author be held liable for anything including loss/damage of any
kind as the result of using this script.

The author hereby grants you license to freely distribute or modify the scriipt
for whatever purposes.  For any bug report or feature request, please send
email to mingyiliu@yahoo.com

Version change log:
0.07 (July 12, 2005) Added handling of most printable characters, and safeguarded
      against non-printable characters such as arrow keys. An exhaustive list of
      characters allowed in the dropdown list includes: any printable characters
      that can be input with a single key press (e.g., '0' can be produced by
      pressing only '0' key, but ')' cannot be produced by a single key (it
      requires both shift and '0' keys), therefore ')' is not supported).
0.06 (July 1, 2005) Added handling of numpad/keypad keys.
0.05 (April 22, 2005) Significant code changes:
     removed unnecessary variables and function,
     changed time recording (I found that onKeyUp is not fired as quickly as
       they should be, causing inconsistent behavior at times)
     changed to use options.text instead of value, in case web page author needs
       to use value differently from text (text is the text web page viewers see,
       value is the text used by the form cgi application).
     changed default time gap for type-ahead behavior to 0.5 second from 0.3 second.
0.04 (April 7, 2005) added handling of all browsers and an improvement.
     Please note that with this version out, one probably wants to use this
     script in all Gecko-based browsers too (Mozilla, Firefox, Netscape, K-Meleon,
     ...) since the default behavior in these browsers handles consecutive
     letters in a special way (if the letter is used as the first letter for an
     option), which could be confusing to users IMO (and it works incorrectly
     for option that is composed of only one character like 'AA', since firefox
     etc. would instead move to 'AB' after users press two 'A's).
0.03 (April 6, 2005) added Duncan Cook's improvement to allow the script work on
     more than one selects
0.02 (Jan 11, 2005) added comments, shortened/improved code a little to avoid
     exception
0.01 (Oct 7, 2004) first version
===================================================================================================
*/
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 < 500) // 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(trim(allOpts[i]).length >= len && trim(allOpts[i]).substring(0, len) == keyStr)
      return i;
  return -1;
}

