

function JSuggest( textboxId, suggestDivId, suggestName )
{
  var m_textboxId = textboxId || "";
  var m_suggestDivId = suggestDivId || "";
  var m_suggestId = suggestName || "suggest";
  var m_noSuggestion = -1;
  var m_currentSuggestion = m_noSuggestion;
  var script = "suggest.asp";
  var m_suggestions;
  var m_lastTyped = "";
  var m_ajax;
  
  //colors
  var m_suggestionBackgroundColor = "#FFFFFF";
  var m_suggestionColor = "#000000";
  var m_suggestionHighlightBackgroundColor = "#3355FF";
  var m_suggestionHighlightColor = "#FFFFFF";
  
  
  this.GetTextbox = GetTextbox;
  this.GetSuggestDiv = GetSuggestDiv;
  this.GetCurrentSuggestion = GetCurrentSuggestion;
  this.script = script;
  this.GetSuggestions = GetSuggestions;
  this.SetSuggestions = SetSuggestions;
  this.m_noSuggestion = m_noSuggestion;
  this.m_currentSuggestion = m_currentSuggestion;
  this.m_lastTyped = m_lastTyped;
  this.m_ajax = m_ajax;
  
  //colors
  this.m_suggestionBackgroundColor = m_suggestionBackgroundColor;
  this.m_suggestionColor = m_suggestionColor;
  this.m_suggestionHighlightBackgroundColor = m_suggestionHighlightBackgroundColor;
  this.m_suggestionHighlightColor = m_suggestionHighlightColor;
  
  var _this = this;
  
  document.body.onclick = function()
    { _this.CancelSuggestions.call( _this ); }
  if ( document.body.captureEvents )
    document.body.captureEvents( Event.CLICK );
    
  var element = this.GetTextbox();
  element.onkeyup = function()
    { _this.RequestSuggestion.apply( _this, arguments ); }
  if ( element.captureEvents )
    element.captureEvents( Event.KEYUP );
  element.onkeydown = function()
    { _this.NavigateSuggestions.apply( _this, arguments ); }
  if ( element.captureEvents )
    element.captureEvents( Event.KEYDOWN );
  element.onblur = function ()
    { _this.CancelSuggestions.call( _this ); }
  element.autocomplete = "off";
  
  var container = document.getElementById( m_suggestDivId );
  container.innerHTML = "<div id=\"suggestcontainer\" style=\"position:relative;z-index:2;float:left;\"><div id=\"" + m_suggestId + "\" style=\"z-index:3;\">&nbsp;</div></div>";
  var suggestdiv = this.GetSuggestDiv();
  suggestdiv.style.display = "none";
  suggestdiv.style.border = "solid 1px black";
  suggestdiv.style.fontFamily = "arial";
  suggestdiv.style.fontSize = "10pt";
  suggestdiv.style.lineHeight = "12pt";
  suggestdiv.style.styleFloat = "left";
  suggestdiv.style.position = "absolute";
  suggestdiv.style.textAlign = "left";
  suggestdiv.style.top = "-4px";
  var difference = getRealLeft(element)-getRealLeft(container);
  suggestdiv.style.left = difference + "px";
  //suggestdiv.style.height = "200px";
  //suggestdiv.style.overflow = "auto";
  suggestdiv.style.background = m_suggestionBackgroundColor;
  
  function GetTextbox()
  {
    return document.getElementById( m_textboxId );
  }
  
  function GetSuggestDiv()
  {
    return document.getElementById( m_suggestId );
  }
  
  function GetCurrentSuggestion()
  {
    return this.m_currentSuggestion;
  }
  
  function GetSuggestions()
  {
    return m_suggestions;
  }
  
  function SetSuggestions( array )
  {
    m_suggestions = array;
  }
}

JSuggest.prototype.RequestSuggestion = function( e )
{
  var keycode;
  if (window.event)
    keycode = window.event.keyCode;
  else if (e)
    keycode = e.which;
  
  if (keycode == kArrowDown || keycode == kArrowUp)
    return;
  
  var typed = this.GetTextbox().value;
  if (typed == "")
  {
    this.CancelSuggestions();
    return;
  }
  if (typed == this.m_lastTyped)
    return;
  else
    this.m_lastTyped = typed;
  
  this.SendRequest( typed, this.RequestSuggestionCallback );
}
 
JSuggest.prototype.SendRequest = function( typed, callback )
{ 
  //fix global
  var requestString = getURL( typed );
  var _this = this;
  
  if ( !this.m_ajax )
    this.m_ajax = new AJAX();
  
  var bReuse = false;
  var bCache = true;
  this.m_ajax.SendRequest( bReuse, this.script, requestString, bCache, "text/text", _this, callback, typed );
}

JSuggest.prototype.RequestSuggestionCallback = function( strResponse, typed )
{
  var currentTyped = this.GetTextbox().value;
  var error = strResponse.search(/<|>/i) != -1;
  if ((currentTyped == "") || ( currentTyped != typed ) || (error))
  {
    this.CancelSuggestions();
    return;
  }
  
  //fix global
  var suggestions = parseSuggestions( strResponse );
  this.SetSuggestions( suggestions );
  if ( this.GetSuggestions().length == 0)
  {
    this.CancelSuggestions();
    return;
  }
  
  this.SetNoSuggestion();
  this.DisplaySuggestions(suggestions);
}

JSuggest.prototype.NavigateSuggestions = function( e )
{
  var keycode;
  if (window.event)
    keycode = window.event.keyCode;
  else if (e)
    keycode = e.which;

  if (keycode == kArrowDown)
    this.MoveSuggestionDown();
  else if (keycode == kArrowUp)
    this.MoveSuggestionUp();
}

JSuggest.prototype.MouseoverSuggestion = function( index )
{
  var suggestion = this.GetSuggestionElem( index );
  if ( !suggestion )
    return;
  suggestion.style.cursor = "default";
  this.DehighlightSuggestion( this.GetCurrentSuggestion() );
  this.HighlightSuggestion(index);
}

JSuggest.prototype.MouseoutSuggestion = function( index )
{
  this.DehighlightSuggestion( index );
}

JSuggest.prototype.MousedownSuggestion = function( index )
{
  this.CloseSuggestions( index );
}

JSuggest.prototype.clickSuggestion = function( index )
{
  this.CloseSuggestions( index );
}

JSuggest.prototype.EmptySuggestions = function()
{
  this.SetSuggestions( new Array() );
}

JSuggest.prototype.SetNoSuggestion = function()
{
  this.SetCurrentSuggestion( this.m_noSuggestion );
}

JSuggest.prototype.DisplaySuggestions = function()
{
  var suggestions = this.GetSuggestions();
  if ( !suggestions )
    return;
    
  if ( suggestions.length == 0 )
    return;
  
  var x;
  var suggestdiv = this.GetSuggestDiv();
  suggestdiv.style.display = "";
  this.SetSuggestWidth();
  
  var strHTML = "";
  this.m_suggestionElemArray = new Array();
  for (x in suggestions)
  {
    strHTML += "<div id=\"suggestion" + x + "\"> " + suggestions[x] + "</div>";
  }
  suggestdiv.innerHTML = strHTML;
  for (x in suggestions)
  {
    this.SetMouseEventsOnSuggestion( x );
  }
}

JSuggest.prototype.SetMouseEventsOnSuggestion = function( x )
{
  var _this = this;
  var sugElem = this.GetSuggestionElem( x );
  sugElem.onmousedown = function()
    { _this.MousedownSuggestion.call( _this, x ); }
  sugElem.onmouseover = function()
    { _this.MouseoverSuggestion.call( _this, x ); }
  sugElem.onmouseout = function()
    { _this.MouseoutSuggestion.call( _this, x ); }
}

JSuggest.prototype.GetSuggestionElem = function( index )
{
  var divId = "suggestion" + index;
  var suggestion = document.getElementById(divId);
  return suggestion;
}

JSuggest.prototype.SetSuggestWidth = function()
{
  var width = this.GetTextbox().offsetWidth;
  this.GetSuggestDiv().style.width = width + "px";  
}

JSuggest.prototype.SetCurrentSuggestion = function( index )
{
  var currentSuggestion = this.GetCurrentSuggestion();
  this.DeselectSuggestion(currentSuggestion);
  if ( index < 0 )
    index = this.m_noSuggestion;
  if ( index >= this.GetSuggestions().length )
    index = this.GetSuggestions().length - 1;
  currentSuggestion = index;
  this.SelectSuggestion(currentSuggestion);
}

JSuggest.prototype.MoveSuggestionDown = function()
{
  var currentSuggestion = this.GetCurrentSuggestion();
  this.SetCurrentSuggestion( ++currentSuggestion );
}

JSuggest.prototype.MoveSuggestionUp = function()
{
  var currentSuggestion = this.GetCurrentSuggestion();
  this.SetCurrentSuggestion( --currentSuggestion );
}

JSuggest.prototype.DeselectSuggestion = function( index )
{
  if (( index == this.m_noSuggestion ) || ( index >= this.GetSuggestions().length ))
    return;
  this.DisplayDeselectSuggestion(index);
  this.m_currentSuggestion = this.m_noSuggestion;
}

JSuggest.prototype.SelectSuggestion = function( index )
{
  if (( index == this.m_noSuggestion ) || ( index >= this.GetSuggestions().length ))
    return;
  this.m_currentSuggestion = index;
  this.DisplaySelectSuggestion( index );
}

JSuggest.prototype.DisplaySelectSuggestion = function( index )
{
  var suggestion = this.GetSuggestionElem(index);
  if ( !suggestion )
    return;
  this.HighlightSuggestion( index );
  var suggestionText = suggestion.innerHTML;
  this.GetTextbox().value = trim( suggestionText );
}

JSuggest.prototype.DisplayDeselectSuggestion = function( index )
{
  this.DehighlightSuggestion( index );
}

JSuggest.prototype.CancelSuggestions = function()
{
  this.ClearSuggest();
  this.EmptySuggestions();
  this.m_currentSuggestion = this.m_noSuggestion;
}

JSuggest.prototype.ClearSuggest = function()
{
  var suggestdiv = this.GetSuggestDiv();
  suggestdiv.innerHTML = "";
  suggestdiv.style.display = "none";
}

JSuggest.prototype.HighlightSuggestion = function( index )
{
  var suggestion = this.GetSuggestionElem( index );
  if ( !suggestion )
    return;
  suggestion.style.backgroundColor = this.m_suggestionHighlightBackgroundColor;
  suggestion.style.color = this.m_suggestionHighlightColor;
}

JSuggest.prototype.DehighlightSuggestion = function( index )
{
  var suggestion = this.GetSuggestionElem( index );
  if ( !suggestion )
    return;
  suggestion.style.backgroundColor = this.m_suggestionBackgroundColor;
  suggestion.style.color = this.m_suggestionColor;
}

JSuggest.prototype.CloseSuggestions = function( index )
{
  this.SelectSuggestion( index );
  this.ClearSuggest();
  this.m_currentSuggestion = this.m_noSuggestion;
}

function shouldSuggestSubmit(e)
{
  var keycode;
  if (window.event)
    keycode = window.event.keyCode;
  else if (e)
    keycode = e.which;
  
  if (keycode == kEnter)
  {
    if (getCurrentSuggestion() != _noSuggestion)
    {
      closeSuggestions(getCurrentSuggestion());
      return false;
    }
  }
  return true;
}