function AutoSuggestControl(oTextbox, oProvider) {
  this.cur = -1; // The currently selected suggestion index
  this.orig = ""; // the original string in the text box
  this.layer = null; // The dropdown list layer.
  this.limit = 15; // number of items to show
  this.provider = oProvider; // Suggestion provider for the autosuggest feature.
  this.textbox = oTextbox; // The textbox to capture.
  this.init(); //initialize the control
}

/*
 * Autosuggests one or more suggestions for what the user has typed.
 * If no suggestions are passed in, then no autosuggest occurs.
 */
AutoSuggestControl.prototype.autosuggest = function (aSuggestions) {
  var d = document.getElementById('dictype');
  if ( d && d.value != this.dtype ) {
    this.createDropDown();
    this.hideSuggestions();
  }

  //make sure there's at least one suggestion
  if (aSuggestions.length > 0 && aSuggestions[0].length > 0) {
    this.showSuggestions(aSuggestions);
    this.layer.style.left = this.getLeft() + "px";
    this.layer.style.top = (this.getTop()+this.textbox.offsetHeight) + "px";
  } else {
    this.hideSuggestions();
  }
};

/**
 * Creates the dropdown layer to display multiple suggestions.
 * @scope private
 */
AutoSuggestControl.prototype.createDropDown = function () {
  var oThis = this;

  //create the layer and assign styles
  this.layer = document.createElement("div");
  this.layer.className = "suggestions-en";

  var d = document.getElementById('dictype');
  if ( d ) {
     var dtype = d.value ; 
     if ( dtype.substr(0,3) == 'ug_' ) {
       this.layer.className = "suggestions";
     } else if ( dtype.substr(0,3) == 'ar_' ) {
       this.layer.className = "suggestions-ar";
     } else if ( dtype.substr(0,3) == 'ur_' ) {
       this.layer.className = "suggestions-ur";
     } else if ( dtype.substr(0,3) == 'cn_' ) {
       this.layer.className = "suggestions-cn";
     }

     this.dtype = dtype;
  }

  this.layer.style.visibility = "hidden";
  this.layer.style.width = this.textbox.offsetWidth;
  
  //when the user clicks on the a suggestion, get the text (innerHTML)
  //and place it into a textbox
  this.layer.onmousedown = 
  this.layer.onmouseup = 
  this.layer.onmouseover = function (oEvent) {
    oEvent = oEvent || window.event;
    oTarget = oEvent.target || oEvent.srcElement;

    if (oEvent.type == "mousedown") {
      oThis.textbox.value = oTarget.firstChild.nodeValue;
      oThis.hideSuggestions();
      validate();  // this will submit query
    } else if (oEvent.type == "mouseover") {
      oThis.highlightSuggestion(oTarget);
    } else {
      oThis.textbox.focus();
    }
  };
  
  document.body.appendChild(this.layer);
};

// Gets the left coordinate of the textbox.
AutoSuggestControl.prototype.getLeft = function () {

  var oNode = this.textbox;
  var iLeft = 0;
  
  while(oNode.tagName != "BODY") {
    iLeft += oNode.offsetLeft;
    oNode = oNode.offsetParent;
  }

  //console.log("iLeft: %d\n", iLeft);
  
  return iLeft; 
};

// Gets the top coordinate of the textbox.
AutoSuggestControl.prototype.getTop = function () /*:int*/ {

  var oNode = this.textbox;
  var iTop = 0;
  
  while(oNode.tagName != "BODY") {
    iTop += oNode.offsetTop;
    oNode = oNode.offsetParent;
  }
  
  return iTop - 1;
};

// Handles three keydown events.
AutoSuggestControl.prototype.handleKeyDown = function (oEvent) {

  switch(oEvent.keyCode) {
    case 38: //up arrow
      this.previousSuggestion();
      break;
    case 40: //down arrow 
      this.nextSuggestion();
      break;
    case 13: //enter
    case 27: //escape
      this.hideSuggestions();
      break;
  }

};

// Handles keyup events.
AutoSuggestControl.prototype.handleKeyUp = function (oEvent) {

  var iKeyCode = oEvent.keyCode;

  //for backspace (8) and delete (46), shows suggestions without typeahead
  if (iKeyCode == 8 || iKeyCode == 46) {
    this.provider.requestSuggestions(this, false);
    
  //make sure not to interfere with non-character keys
  } else if (iKeyCode < 32 || (iKeyCode >= 33 && iKeyCode < 46) || (iKeyCode >= 112 && iKeyCode <= 123)) {
    //ignore
  } else {
    //request suggestions from the suggestion
    this.provider.requestSuggestions(this);
  }
};

// Hides the suggestion dropdown.
AutoSuggestControl.prototype.hideSuggestions = function () {
  this.cur = -1;
  this.layer.style.visibility = "hidden";
};

// Highlights the given node in the suggestions dropdown.
AutoSuggestControl.prototype.highlightSuggestion = function (oSuggestionNode) {
  
  for (var i=0; i < this.layer.childNodes.length; i++) {
    var oNode = this.layer.childNodes[i];
    if (oNode == oSuggestionNode) {
      oNode.className = "current"
    } else if (oNode && oNode.className == "current") {
      oNode.className = "";
    }
  }
};

// Initializes the textbox with event handlers for
AutoSuggestControl.prototype.init = function () {
  //save a reference to this object
  var oThis = this;

  var d = document.getElementById('dictype');
  if ( d ) {
     oThis.dtype = d.value;
  }
  
  //assign the onkeyup event handler
  this.textbox.onkeyup = function (oEvent) {
  
    //check for the proper location of the event object
    if (!oEvent) {
      oEvent = window.event;
    }  
    
    //call the handleKeyUp() method with the event object
    oThis.handleKeyUp(oEvent);
  };
  
  //assign onkeydown event handler
  this.textbox.onkeydown = function (oEvent) {
  
    //check for the proper location of the event object
    if (!oEvent) {
      oEvent = window.event;
    }  
    
    //call the handleKeyDown() method with the event object
    oThis.handleKeyDown(oEvent);
  };

  //assign onblur event handler (hides suggestions)  
  this.textbox.onblur = function () {
    oThis.hideSuggestions();
  };
  
  //create the suggestions dropdown
  this.createDropDown();
};

// Highlights the next suggestion in the dropdown and places the suggestion into the textbox.
AutoSuggestControl.prototype.nextSuggestion = function () {
  var cSuggestionNodes = this.layer.childNodes;

  if (cSuggestionNodes.length > 0 ) {
    if ( this.cur < cSuggestionNodes.length - 1) {
       var oNode = cSuggestionNodes[++this.cur];
       this.highlightSuggestion(oNode);
       this.textbox.value = oNode.firstChild.nodeValue; 
    } else {
       this.highlightSuggestion(null);
       this.textbox.value = this.orig; 
       this.cur = -1;
    }
  }
};

// Highlights the previous suggestion in the dropdown and places the suggestion into the textbox.
AutoSuggestControl.prototype.previousSuggestion = function () {
  var cSuggestionNodes = this.layer.childNodes;

  if (cSuggestionNodes.length > 0 ) {
    if (this.cur ==  -1) {
       this.cur = cSuggestionNodes.length; 
    } 

    if (this.cur > 0) {
       var oNode = cSuggestionNodes[--this.cur];
       this.highlightSuggestion(oNode);
       this.textbox.value = oNode.firstChild.nodeValue;   
    } else {
       this.highlightSuggestion(null);
       this.textbox.value = this.orig; 
       this.cur = -1;
    }
  }
};

// Selects a range of text in the textbox.
AutoSuggestControl.prototype.selectRange = function (iStart /*:int*/, iLength /*:int*/) {

  //use text ranges for Internet Explorer
  if (this.textbox.createTextRange) {
    var oRange = this.textbox.createTextRange(); 
    oRange.moveStart("character", iStart); 
    oRange.moveEnd("character", iLength - this.textbox.value.length);    
    oRange.select();
    
  //use setSelectionRange() for Mozilla
  } else if (this.textbox.setSelectionRange) {
    this.textbox.setSelectionRange(iStart, iLength);
  }   

  //set focus back to the textbox
  this.textbox.focus();    
}; 

// Builds the suggestion layer contents, moves it into position and displays the layer.
AutoSuggestControl.prototype.showSuggestions = function (aSuggestions) {
  
  var oDiv = null;
  this.layer.innerHTML = "";  //clear contents of the layer
  this.orig = this.textbox.value;
  
  for (var i=0; i < this.limit && i < aSuggestions.length; i++) {
    oDiv = document.createElement("div");
    oDiv.appendChild(document.createTextNode(aSuggestions[i]));
    this.layer.appendChild(oDiv);
  }
  
  this.layer.style.left = this.getLeft() + "px";
  this.layer.style.top = (this.getTop()+this.textbox.offsetHeight) + "px";
  this.layer.style.visibility = "visible";
};
