// Type-ahead functionality for selectboxes

// Global variables
var keyTime, keyStr = '', allOpts, lastElement;
var is_gecko = (navigator.userAgent.toLowerCase().indexOf("gecko") != -1);

var enterKeyNum = 13;
var tabKeyNum = 9;

//poulate array from selectbox
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;
  }
}

// do type-ahead for a selectbox on a onkeydown
function typeAhead(srcEvent)
{
  var myEvent = (srcEvent)? srcEvent : window.event;
  var element = (myEvent.target)? myEvent.target : myEvent.srcElement;
  var keyCode = myEvent.keyCode;
  

  // preprocess Keycodes
  if((keyCode > 47 && keyCode < 58) || (keyCode > 64 && keyCode < 91 || keyCode == 32)) ; // bypass the space character and alphanumerical characters
  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.
    }
  }
  
  
  // Keycode conversion for 'ä', 'ö' and 'å'
  // probably works only with finnish or swedish keyboard setting.
  if(keyCode == 39) keyCode = 196; // 'ä' 
  if(keyCode == 93) keyCode = 197; // 'å'
  if(keyCode == 96) keyCode = 214; // 'ö'
  
  var currentKey = String.fromCharCode(keyCode).toLowerCase();
  var idx, currentSIdx = element.selectedIndex, useOld = false;
  var newTime = new Date().getTime();
  if(keyTime != null && newTime - keyTime < 2000) // do type-ahead if two keys were pressed within 2000 milliseconds (duration can be adjusted if needed)
  {
    keyStr += currentKey;
    idx = findIndex();
    if(idx == -1) return; // Index not found - keep current selection.
  }
  else // 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 = findIndex();
  }
  idx;
  if(idx >= 0) // if keyStr is found in an option, select the option
  {
    element.options[currentSIdx].selected = false;
    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;
}

// find the correct index
function findIndex()
{
  // full scan to find the smallest index that matches 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;
}


