
var _oldInputFieldValue=""; // inputField value 
var _currentInputFieldValue=""; // also inputField value 
var selectedValue="";
var _eventKeycode=""; // event keycode
var _highlightedSuggestionIndex=-1; // currently hightlighted suggestion index
var _highlightedSuggestionDiv=null; // currently highlisted suggestion div... 
var _completeDivRows=-1; // completeDiv rows at time of keypress... 
var _completeDivDivList=null; // completeDiv div list at time of keypress 
var _completeDivRows2=5; 
var _divTag="div"; 
var _spanTag="span"; 
var _inputField=null; // Input field on form... 
var _completeDiv=null; // document.completeDiv 
var _cursorUpDownPressed=false;  
var completionFrame=null;
var percentageWidth=60;
var _timeoutAdjustment=0; // timeout adjustment... gets adjusted over time...
var dropDowns = null;


// Initial setup routine
setupAutoSuggest=function(fld,dd)
{
  
  if (!fld)
  {
	return
  }
  
  // If Ajax is not supported then do nothing
  if(!getXMLHTTP())
  {
    return
  }
  
  _inputField=fld;
        

  dropDowns = dd;
  
  _inputField.autocomplete="off";
  _inputField.onblur=onBlurHandler;

  // Setup the key handler event for the input text box.   
  var newKeyUp;

  if(_inputField.createTextRange) 
  {
    newKeyUp=new Function("return onKeyUpHandler(event);");
  } 
  else 
  {
    newKeyUp=onKeyUpHandler;
  }

  // Save the existing key handler
  var oldKeyUp = _inputField.onkeyup;

  // If there is no existing key up event handler then simply replace it
  if (typeof oldKeyUp != 'function') 
  {
  	_inputField.onkeyup = newKeyUp;
  } 
  else 
  {
    // Otherwise create a new handler which calls the old and the new
	_inputField.onkeyup = function(e) 
	{
		oldKeyUp(e);
		newKeyUp(e);
	}
  }

  // Store the field value
  _currentInputFieldValue=_inputField.value;
  _oldInputFieldValue=_currentInputFieldValue;

  // Create the div for the suggestions
  _completeDiv=document.createElement("DIV");
  _completeDiv.id="completeDiv";
  _completeDiv.style.borderRight="black 1px solid";
  _completeDiv.style.borderLeft="black 1px solid";
  _completeDiv.style.borderTop="black 1px solid";
  _completeDiv.style.borderBottom="black 1px solid";
  _completeDiv.style.zIndex="1";
  _completeDiv.style.paddingRight="0";
  _completeDiv.style.paddingLeft="0";
  _completeDiv.style.paddingTop="0";
  _completeDiv.style.paddingBottom="0";
  setCompleteDivSize();
  _completeDiv.style.visibility="hidden";
  _completeDiv.style.position="absolute";
  _completeDiv.style.backgroundColor="white";
  document.body.appendChild(_completeDiv);

  setPercentageWidth();

  setStyleForElement(_completeDiv,"mAutoComplete")
  
  var s=document.createElement("DIV");
  s.style.visibility="hidden";
  s.style.position="absolute";
  s.style.left="-10000";
  s.style.top="-10000";
  s.style.width="0";
  s.style.height="0";
  
  var M=document.createElement("IFRAME");
  M.completeDiv=_completeDiv;
  M.name="completionFrame";
  M.id="completionFrame";

  s.appendChild(M);
  
  document.body.appendChild(s);

  if(frames && (frames["completionFrame"] && frames["completionFrame"].frameElement)) 
  {
    completionFrame=frames["completionFrame"].frameElement;
  } 
  else 
  {
    completionFrame=document.getElementById("completionFrame");
  }
  
  // Setup the other event handlers
  window.onresize=setCompleteDivSize;
  document.onkeydown=keyDownHandler;
}

// Blurs focus, then sets focus again on the input field 
// This is getting called when we press cursor up / cursor down...
function blurThenGetFocus()
{
  _cursorUpDownPressed=true;

  _inputField.blur();

  setTimeout("setInputFieldFocus();",10);

  return
}


// Function for handling keydown event
function keyDownHandler(event)
{
  if(!event && window.event) 
  {
    event=window.event;
  }
  
  // We are backspacing here...
	if(event && event.keyCode==8)
	{
		// If the event came from the input text box and 
		if((_inputField.createTextRange && 
			(event.srcElement == _inputField
				// if there is no selection
				&& (getSelectionStart(_inputField) == 0 && getSelectionSize(_inputField)==0))))
		{
			setCaretToEnd(_inputField);

			// Stop the event bubbling upwards
			event.cancelBubble=true;

			event.returnValue=false;

			return false
		}
	  }
}


// Set the size of the completion DIV
function setCompleteDivSize()
{

var fudge;

  if (isOpera())
  {
	fudge=145;
  }
  else
  {
  fudge =1;
  }

  if(_completeDiv)
  {
    _completeDiv.style.left=calculateOffsetLeft(_inputField)+"px";
    _completeDiv.style.top=calculateOffsetTop(_inputField)+_inputField.offsetHeight-fudge+"px";
    _completeDiv.style.width=calculateWidth()+"px"
  }
    
}

// calculate width of inputField... Note browser specific adjustments...
function calculateWidth()
{
  if(isIE())
  {
    return _inputField.offsetWidth-1*2
  }else
  {
    return _inputField.offsetWidth
  }
}


// Handles the blur event of the input text box
function onBlurHandler(event)
{
  if(!event&&window.event) 
  {
    event=window.event;
  }
  
  // If it is not the cursor up/down key then hide the completion div
  if(!_cursorUpDownPressed)
  {
    hideCompleteDiv();
  }

  _cursorUpDownPressed=false

}

// Key up event handler for the text box
onKeyUpHandler=function(e)
{
  _eventKeycode=e.keyCode;

  // Ignore tabs
  if (_eventKeycode == 9 || _eventKeycode == 16)
  {
	return;
  }
	
  // 38 is up cursor key, 40 is down cursor key...
  if(_eventKeycode==40||_eventKeycode==38) 
  {
    // This causes the blur event to be sent and then resets the focus after a timeout  
    blurThenGetFocus();
  }
  
  var selectSize=getSelectionSize(_inputField);
  var selectStart=getSelectionStart(_inputField);
  var textValue=_inputField.value;
  
  if (_eventKeycode!=0)
  {
    // If something is selected  
    if (selectSize > 0 && selectStart!= -1) 
    {
      // Get the unselected section
      textValue=textValue.substring(0,selectStart);
    } 
    
    // If key is carriage return or end-of-text
    if (_eventKeycode==13 || _eventKeycode==3)
    { 
      setCaretToEnd(_inputField); 
    } 
    else 
    { 
      // If the field is not equal to the unselected section
      if(_inputField.value!=textValue) 
      {
        // Set the field to that value
        selectEntry(textValue)
      }
    }
  }

  // Store the text value
  _currentInputFieldValue=textValue;

  // If cursor up/down or enter has been pressed
  if (handleCursorUpDownEnter (_eventKeycode) && _eventKeycode!=0) 
  { 
  
    // Process the autocomplete
    processAutoComplete(_completeDiv,valueOfCAutoComplete)
  }
}
;

// Set focus to the input text box
setInputFieldFocus=function()
{
  _inputField.focus()
}
;

// Replace spaces with nbsp in a string
function replaceSpacesInString(va)
{
  return va.replace(/ /,"&nbsp;")
}

// Replace nbsp with spaces in a string
function replaceNbSpacesInString(va)
{
  return va.replace(/&nbsp;/," ")
}


// Replace &amp with & in a string
function replaceAmpersandInString(va)
{
  return va.replace(/&amp;/,"&")
}

// strip CR from a string
function stripCRFromString(va)
{
  for(var f=0,oa="",zb="\n\r"; f<va.length; f++) 
  {
    if (zb.indexOf(va.charAt(f))==-1) 
    {
      oa+=va.charAt(f);
    } 
    else 
    {
      oa+=" ";
    }
  }
return oa
}

// Find span value with className = dc...
function findSpanValueForClass(i,dc)
{
  var ga=i.getElementsByTagName(_spanTag);
  
  if(ga)
  {
    for(var f=0; f<ga.length; ++f)
    {
      if(ga[f].className==dc)
      {
        var value = replaceAmpersandInString(ga[f].innerHTML);
        if(value=="&nbsp;") 
        {
          return"";
        } 
        else
        {
          var z=stripCRFromString(value);
          return z
        }
      }
    }
  }
  else
  {
    return""
  }
}

// Return null if i undefined...
// otherwise return value of span cAutoComplete...
function valueOfCAutoComplete(i)
{
  if(!i) 
  {
    return null;
  }
  return findSpanValueForClass(i,"cAutoComplete")
}

// Reveal the hidden dropdowns and hide the autocompletion division
function hideCompleteDiv()
{	

  toggleDropdowns(false);

  document.getElementById("completeDiv").style.visibility="hidden"
}

// Hide or reveal the dropdowns that would otherwise be visible through the suggestions (IE only)
function toggleDropdowns(hidden)
{
    if (document.all && dropDowns)
	{
		
	    for (var i=0; i < dropDowns.length; i++) 
	    {

		if (dropDowns[i])
		{
			if (document.getElementById(dropDowns[i]))
			{
			
			if (hidden == true)
			{
				document.getElementById(dropDowns[i]).style.visibility="hidden";
			}
			else
			{
				document.getElementById(dropDowns[i]).style.visibility="visible";			
			}
				
			}
		}
	   }
	}
}

// Display the completion division
function showCompleteDiv()
{

  document.getElementById("completeDiv").style.visibility="visible";
  setCompleteDivSize()
}


// Process the suggestions returned from the server
processSuggestions=function(frame, suggestions)
{
  // Decrement the timeout adjustment
  if(_timeoutAdjustment>0) 
  {
    _timeoutAdjustment--;
  }

  // Get the completion div    
  var completionDiv=frame.completeDiv;
  
  // Copy the suggestions list
  completionDiv.completeStrings=suggestions;

  // create the suggestions display
  displaySuggestedList(completionDiv);
  
  // Process the autocompletion
  processAutoComplete(completionDiv, valueOfCAutoComplete);

  
  if(_completeDivRows2>0) 
  {
    completionDiv.height=16*_completeDivRows2+4;
  } 
  else 
  {
    hideCompleteDiv();
  }
}

// If Mb is 0, will return 150...
// If Mb is 3, will return 250...
// If Mb is 4, will return 450...
// If Mb is X, will return 850...
function recalculateTimeout(Mb){
  var H=100;
  for(var o=1; o<=(Mb-2)/2; o++){
    H=H*2
  }
  H=H+50;
  return H
}

// This function sets itself up and gets called over and over (timeout driven)
mainLoop=function()
{

  if(_oldInputFieldValue!=_currentInputFieldValue)
  {
	// Increment the timeout adjustment
	_timeoutAdjustment++;
	
	// Make the AJAX call to get the suggestions
	getSuggestions(_currentInputFieldValue)
	
	// Set the focus
	_inputField.focus()
  }

  // Store the current text box value
  _oldInputFieldValue=_currentInputFieldValue;

  // Set the timeout to call the mainloop again
  setTimeout("mainLoop()",recalculateTimeout(_timeoutAdjustment));

  return true
};

// Call mainLoop() after 10 milliseconds...
setTimeout("mainLoop()",10);

// Called when cursor up/down pressed... selects new entry in completeDiv...
function highlightNewValue(selectedIndex)
{	

  if (selectedIndex == -1)
  {
	return;
  }
  	
  _currentInputFieldValue=selectedValue;
  
  selectEntry(selectedValue);

  if(!_completeDivDivList || _completeDivRows <=0) 
  {
    return;
  }

  // Display the suggestions   
  showCompleteDiv();
  
  if(selectedIndex>=_completeDivRows)
  {
    selectedIndex=_completeDivRows-1
  }
  
  if(_highlightedSuggestionIndex != -1 && selectedIndex != _highlightedSuggestionIndex)
  {
    setStyleForElement(_highlightedSuggestionDiv,"aAutoComplete"); 
    _highlightedSuggestionIndex=-1
  }
  
  if(selectedIndex<0)
  {
    _highlightedSuggestionIndex=-1;
    _inputField.focus();
    return
  }
  _highlightedSuggestionIndex=selectedIndex;

  _highlightedSuggestionDiv=_completeDivDivList.item(selectedIndex);

  setStyleForElement(_highlightedSuggestionDiv,"bAutoComplete");

  _currentInputFieldValue=selectedValue;

  selectEntry(valueOfCAutoComplete(_highlightedSuggestionDiv))
}

// returns false if cursor up / cursor down or enter pressed...
function handleCursorUpDownEnter(eventCode)
{
  if(eventCode==40)
  {
    highlightNewValue(_highlightedSuggestionIndex+1);
    return false
  }
  else if(eventCode==38)
  {
    highlightNewValue(_highlightedSuggestionIndex-1);
    return false
  }
  else if(eventCode==13||eventCode==3)
  {
    return false
  }
  return true
}

// This function gets called for every keypress I make...
function processAutoComplete(localCompleteDiv, ib)
{
  var localInputField=_inputField;
  var T=false;
  
  _highlightedSuggestionIndex=-1;
  // This becomes the rows in our suggestion list...
  var J=localCompleteDiv.getElementsByTagName(_divTag);
  // # of rows in list...
  var O=J.length;
  _completeDivRows=O;
  _completeDivDivList=J;
  _completeDivRows2=O;
  selectedValue=_currentInputFieldValue;

  if(_currentInputFieldValue=="" || O<2)
  {
    hideCompleteDiv()
  }
  else
  {
    showCompleteDiv()
  }

  if(_currentInputFieldValue.length>0)
  {
    var f;

    for(var f=0; f<O; f++)
    {
		var Ib=""+_currentInputFieldValue;
		if(ib(J.item(f)).toUpperCase().indexOf(Ib.toUpperCase())==0) 
		{
			T=true; 
			break
		}
    }
  }
  
  if(T) 
  {
    _highlightedSuggestionIndex=f;
  }
  for(var f=0; f<O; f++) 
  {
    setStyleForElement(J.item(f),"aAutoComplete");
  }
  
  if(T)
  {
    _highlightedSuggestionDiv=J.item(_highlightedSuggestionIndex);

  }
  else
  {

    _highlightedSuggestionIndex=-1;
    _highlightedSuggestionDiv=null
  }
  var ab=false;
  
  switch(_eventKeycode)
  {
    // cursor left, cursor right, others??
    case 8:
    case 33:
    case 34:
    case 35:
    case 35:
    case 36:
    case 37:
    case 39:
    case 45:
    case 46:
      ab=true;
      break;
    default:
      // regular keypress ...
      break
  }

  if(!ab&&_highlightedSuggestionDiv)
  {
    var Da=_currentInputFieldValue;
    setStyleForElement(_highlightedSuggestionDiv,"bAutoComplete");
    var z;
    if(T) 
    {
      z=ib(_highlightedSuggestionDiv);
    } 
    else 
    {
      z=Da;
    }
    if(z!=localInputField.value)
    {
      if(localInputField.value!=_currentInputFieldValue) 
      {
        return;
      }
    if(localInputField.createTextRange||localInputField.setSelectionRange) 
    {
        selectEntry(z);
    }
    if(localInputField.createTextRange)
    {
        var t=localInputField.createTextRange();
        t.moveStart("character",Da.length);
        t.select()
    }
    else if(localInputField.setSelectionRange)
		{
        localInputField.setSelectionRange(Da.length,localInputField.value.length)
		}
    }
  }
  else
  {
    _highlightedSuggestionIndex=-1;
  }
}

// Called as:
// calculateOffsetLeft(_inputField)
function calculateOffsetLeft(r){
  return calculateOffset(r,"offsetLeft")
}

// Called as:
// calculateOffsetTop(_inputField)
function calculateOffsetTop(r){
  return calculateOffset(r,"offsetTop")
}

function calculateOffset(r,attr){
  var kb=0;
  while(r){
    kb+=r[attr]; 
    r=r.offsetParent
  }
  return kb
}

function getSelectionSize(n){
  var N=-1;
  if(n.createTextRange){
    var fa=document.selection.createRange().duplicate();
    N=fa.text.length
  }else if(n.setSelectionRange){
    N=n.selectionEnd-n.selectionStart
  }
  return N
}

function getSelectionStart(n)
{
  var v=0;
  
  if(n.createTextRange)
  {
    var fa=document.selection.createRange().duplicate();
    fa.moveEnd("textedit",1);
    v=n.value.length-fa.text.length
  }
  else if(n.setSelectionRange)
  {
    v=n.selectionStart
  }
  else
  {
    v=-1
  }
  return v
}

// Sets the caret to the end of the text box and negates the selection
function setCaretToEnd(d)
{
  if(d.createTextRange)
  {
    var t=d.createTextRange();
    t.moveStart("character", d.value.length);
    t.select() 
  } 
  else if(d.setSelectionRange) 
  {
    d.setSelectionRange(d.value.length, d.value.length)
  }
}

function setStyleForElement(c,name)
{

  var wordWrap = "break-word";
  var overflow = "hidden";
 	  
  setPercentageWidth();
  c.className=name;

  if (isIE())
  {
	wordWrap = "break-word";
	overflow = "visible";
  }
  
  switch(name.charAt(0))
  {
    case "m":
      c.style.fontSize="82%";
      c.style.fontFamily="arial,sans-serif";
      c.style.wordWrap=wordWrap;
      break;
    case "l":
      c.style.display="block";
      c.style.paddingLeft="3";
      c.style.paddingRight="3";
      c.style.overflow=overflow;
      break;
    case "a":
      c.style.backgroundColor="white";
      c.style.color="black";
      if(c.displaySpan){
        c.displaySpan.style.color="green"
      }

      break;
    case "b":
      c.style.backgroundColor="#3366cc";
      c.style.color="white";
      if(c.displaySpan){
        c.displaySpan.style.color="white"
      }

      break;
    case "c":
      c.style.cssFloat="left";
     
      break;
    case "d":
      c.style.cssFloat="right";
      c.style.width=100-percentageWidth+"%";
	  c.style.fontSize="10px";
	  c.style.textAlign="right";
	  c.style.color="green";
	  c.style.paddingTop="3px"
      break
  }
}

function setPercentageWidth()
{

  percentageWidth=65;

  var wb=110;
  var Sa=calculateWidth();
  var tb=(Sa-wb)/Sa*100;
  percentageWidth=tb

}

// Displays the suggestions
function displaySuggestedList(cDiv)
{

  // Hide the dropdowns
  toggleDropdowns(true);

  // Clear the div of any existing suggestions	
  while(cDiv.childNodes.length>0) 
  {
    cDiv.removeChild(cDiv.childNodes[0]);
  }

  // For each suggestion
  for(var f=0; f<cDiv.completeStrings.length; ++f)
  {
    // Create a new div
    var u=document.createElement("DIV");
    
    setStyleForElement(u,"aAutoComplete");
    
    // Attach mouse event handlers
    u.onmousedown=function()
        {
		selectEntry(valueOfCAutoComplete(this));
		};
		
    u.onmouseover=function()
        {
		if(_highlightedSuggestionDiv) 
		{
			setStyleForElement(_highlightedSuggestionDiv,"aAutoComplete");
		}
		setStyleForElement(this,"bAutoComplete")
	    };
	
    u.onmouseout=function() 
      {
	  setStyleForElement(this,"aAutoComplete")
	  };
	
	// Create a number of SPAN elements setting the text of one to the suggestion
    var ka=document.createElement("SPAN");
    setStyleForElement(ka,"lAutoComplete");
    
    var ua=document.createElement("SPAN");
    
    if(!isIE())
		{
			ua.innerHTML=replaceSpacesInString(cDiv.completeStrings[f]); // the text for the suggested result...
		}
		else
		{
			ua.innerHTML=cDiv.completeStrings[f]; // the text for the suggested result...
		}
    

    setStyleForElement(ua,"cAutoComplete");

    var ea=document.createElement("SPAN");    
    setStyleForElement(ea,"dAutoComplete");
    ea.innerHTML=""; 
    
    u.displaySpan=ea;

	// Attach the SPANs
    ka.appendChild(ua);
    ka.appendChild(ea);
    u.appendChild(ka);
    
    // Attach the SPANs to the completion DIV
    cDiv.appendChild(u)
  }
}

// Does the browser support AJAX
function getXMLHTTP(){
  var A=null;
  try{
    A=new ActiveXObject("Msxml2.XMLHTTP")
  }catch(e){
    try{
      A=new ActiveXObject("Microsoft.XMLHTTP")
    } catch(oc){
      A=null
    }
  }
  if(!A && typeof XMLHttpRequest != "undefined") {
    A=new XMLHttpRequest()
  }
  return A
}

// Make the AJAX call to get the matching locations
function getSuggestions(prefix){

	QuickSearch.GetMatchingLocations(prefix, LoadLocations);

}

// The callback routine for the AJAX call
function LoadLocations(response)
{

//if the server-side code threw an exception
if (response.error != null)
 {
  // Lets just ignore this 
  return;
 }

 // Get the matching suggestions from the response 
 var matches = response.value;  

 //if the response wasn't what we expected  
 if (matches == null || typeof(matches) != "object" )
 {
  return;
 }

 // Process the suggestions 
 processSuggestions(completionFrame, matches)

 
 }
 
// Select suggested entry...
// wa is the value to set the inputfield to...
function selectEntry(Wa)
{
    if(!isIE())
		{
			_inputField.value=replaceNbSpacesInString(Wa); 
		}
		else
		{
			_inputField.value=Wa;
		}

}


function isOpera()
{
	
    if(navigator && navigator.userAgent.toLowerCase().indexOf("opera")!=-1)
		{

			return true; 
		}
		else
		{
			return false;
		}

}	

function isIE()
{

    if(!isOpera() && navigator && navigator.userAgent.toLowerCase().indexOf("msie")!=-1)
		{
			return true; 
		}
		else
		{
			return false;
		}

}	

function disableEnterKey(e)
{
     var key;

     if(window.event)
          key = window.event.keyCode;     //IE
     else
          key = e.which;     //firefox

     if(key == 13)
          return false;
     else
          return true;
}
