function getHTTPObject() {
  var xmlhttp;
  /*@cc_on
  @if (@_jscript_version >= 5)
    try {
      xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e) {
      try {
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
      } catch (E) {
        xmlhttp = false;
      }
    }
  @else
  xmlhttp = false;
  @end @*/
  if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
    try {
      xmlhttp = new XMLHttpRequest();
    } catch (e) {
      xmlhttp = false;
    }
  }
  return xmlhttp;
}


function AutoSuggest(elem, suggestions, chars4ServerHit, suggestionServerCallbackFn, 
					 suggestionSelectedCallbackFn, maxSuggestions, divOffsetPx, autoSuggestDivId, divName2Hide)
{

    //The 'me' variable allow you to access the AutoSuggest object
    //from the elem's event handlers defined below.
    var me = this;

    //A reference to the element we're binding the list to.
    this.elem = elem;

    this.suggestions = suggestions;

    this.minChars4ServerHit = chars4ServerHit;
    this.serverCallbackFn = suggestionServerCallbackFn;
    this.selectedCallbackFn = suggestionSelectedCallbackFn;
    this.maxSuggestionsInList = maxSuggestions;
	this.divOffset = divOffsetPx;
	this.divNameToHide = divName2Hide;

    //Arrow to store a subset of eligible suggestions that match the user's input
    this.eligible = new Array();

    //The text input by the user.
    this.inputText = null;

    //A pointer to the index of the highlighted eligible item. -1 means nothing highlighted.
    this.highlighted = -1;

    //A div to use to create the dropdown.
    this.div = document.getElementById(autoSuggestDivId);

    // Keep track of when all chars deleted from input box
    this.noChars = true;

	this.itWasReset = true;

    //Do you want to remember what keycode means what? Me neither.
    var TAB = 9;
    var ESC = 27;
    var KEYUP = 38;
    var KEYDN = 40;
    var ENTER = 13;
    

    //The browsers' own autocomplete feature can be problematic, since it will 
    //be making suggestions from the users' past input.
    //Setting this attribute should turn it off.
    elem.setAttribute("autocomplete","off");

    //We need to be able to reference the elem by id. If it doesn't have an id, set one.
    if(!elem.id)
    {
        var id = autoSuggestDivId + idCounter;
        idCounter++;

        elem.id = id;
    }


    /********************************************************
    onkeydown event handler for the input elem.
    Tab key = use the highlighted suggestion, if there is one.
    Esc key = get rid of the autosuggest dropdown
    Up/down arrows = Move the highlight up and down in the suggestions.
    ********************************************************/
    elem.onkeydown = function(ev)
    {
        var key = me.getKeyCode(ev);
		var retValue = true;

        switch(key)
        {
            case TAB:
            case ENTER:
	           retValue = me.useSuggestion();
		       break;

            case ESC:
			      me.hideDiv();
               break;

            case KEYUP:
               if (me.highlighted > 0)
               {
                   me.highlighted--;
               }
               me.changeHighlight(key);
            break;

            case KEYDN:
               if (me.highlighted < (me.eligible.length) && me.highlighted < me.maxSuggestionsInList)
               {
                   me.highlighted++;
               }
               me.changeHighlight(key);
               break;
        }
		return retValue;
    };

    /********************************************************
    onkeyup handler for the elem
    If the text is of sufficient length, and has been changed, 
    then display a list of eligible suggestions.
    ********************************************************/
    elem.onkeyup = function(ev) 
    {
        var key = me.getKeyCode(ev);

		// Clear any timeouts so div stays up 5 more seconds
		if (me.asTimeoutHandle) clearTimeout(me.asTimeoutHandle);
		// Set timeout to remove the div if they stop typing
        me.asTimeoutHandle = setTimeout(me.divNameToHide,5000);

        switch(key)
        {
        //The control keys were already handled by onkeydown, so do nothing.
        case TAB:
        case ESC:
        case KEYUP:
        case KEYDN:
            return;
        default:

            if (this.value != me.inputText && this.value.length > 0 && !me.noChars && this.value.substr(0,me.minChars4ServerHit).toLowerCase() == me.inputText.substr(0,me.minChars4ServerHit).toLowerCase())
            {
				   // Get here when more than one character in the input text block
               // and this isn't a newly added single character (!me.noChars)
               // and the first X chars aren't different than previously
               //     (this picks up case where there could be "jones" in the
               //      text block and guy overwrites "jones" with "l")
                me.inputText = this.value;
                me.resetSuggestions();
				me.highlighted = -1;
	            me.changeHighlight(key);
            }
            else if ((this.value.length == me.minChars4ServerHit) || (me.itWasReset && (this.value.length >= me.minChars4ServerHit)))
			{
               // Only one character, lets hit the server
			   // Also a check for reset which picks up when they type first chars really fast and length>minChars
               me.inputText = this.value;
               me.noChars = false;
               me.hideDiv();
               if (me.serverCallbackFn)
               {
                   me.serverCallbackFn(this.value);
               }
			   me.itWasReset = false;
			}
			else if (this.value.length == 0)
            {
               me.noChars = true;
               me.hideDiv();
            }
        }

		return;
    };

    /********************************************************
    Insert the highlighted suggestion into the input box, and 
    remove the suggestion dropdown.
    ********************************************************/
    this.resetSuggestions = function()
    {
		  me.itWasReset = true;
          me.getEligible();
          me.createDiv();
          me.positionDiv();
          me.showDiv();
    };

    /********************************************************
    Insert the highlighted suggestion into the input box, and 
    remove the suggestion dropdown.
    ********************************************************/
    this.useSuggestion = function()
    {
		var lastRow = false;
		var retValue = true;
      var highlightedText = "";

        if (this.highlighted > -1)
        {
         highlightedText = this.eligible[this.highlighted];
			if (this.eligible[this.highlighted] && this.highlighted < me.maxSuggestionsInList) {
				// Take out the <a href... stuff
			    startPos = this.eligible[this.highlighted].indexOf('>');
			    endPos = this.eligible[this.highlighted].indexOf('</a>');
				if (startPos > 0 && endPos > startPos) {
					startPos++;
		            this.elem.value = this.eligible[this.highlighted].substr(startPos, endPos - startPos);
				}
				else
		            this.elem.value = this.eligible[this.highlighted];
			}
			else {
				// we're here because the user picked the special last row
				// with the message about displaying all results
				lastRow = true;
			}

            this.hideDiv();
            //It's impossible to cancel the Tab key's default behavior. 
            //So this undoes it by moving the focus back to our field right after
            //the event completes.
            setTimeout("document.getElementById('" + this.elem.id + "').focus()",0);

            // Callback to a function to do something with the selected suggestion
            if (me.selectedCallbackFn)
            {
				if (!lastRow)
					index = me.getSuggestionIndex(highlightedText)
				else
					index = -1
				retValue = me.selectedCallbackFn(index);
            }
        }
		return retValue;
    };

    /********************************************************
    Display the dropdown. Pretty straightforward.
    ********************************************************/
    this.showDiv = function()
    {
        this.div.style.display = 'block';
    };

    /********************************************************
    Hide the dropdown and clear any highlight.
    ********************************************************/
    this.hideDiv = function()
    {
        this.div.style.display = 'none';
        this.highlighted = -1;
    };

    /********************************************************
    Modify the HTML in the dropdown to move the highlight.
    ********************************************************/
    this.changeHighlight = function()
    {
        var lis = this.div.getElementsByTagName('LI');
        for (i in lis)
        {
			var li = lis[i];
			if (li) {
				if (this.highlighted == i)
				{
					li.className = "selected";
				}
				else
				{
					li.className = "";
				}
			}
        }
    };

    /********************************************************
    Position the dropdown div below the input text field.
    ********************************************************/
    this.positionDiv = function()
    {
        var el = this.elem;
		var prevEl = el;    // hold onto this to find next to last element before BODY
        var x = me.divOffset;
        var y = el.offsetHeight;
    
        //Walk up the DOM and add up all of the offset positions.
        while (el.offsetParent && el.tagName.toUpperCase() != 'BODY')
        {
            x += el.offsetLeft;
            y += el.offsetTop;
			prevEl = el;
            el = el.offsetParent;
        }

        x += el.offsetLeft;
		if (prevEl.offsetWidth - x < 180) {
			// If it's within 180 pix of the far right border, move it left or else it'll be too narrow
			x = prevEl.offsetWidth - 180;   // 
		}
        y += el.offsetTop;

        this.div.style.left = x + 'px';
        this.div.style.top = y + 'px';
    };

    /********************************************************
    Build the HTML for the dropdown div
    ********************************************************/
    this.createDiv = function()
    {
        var numInList = 0;
        var ul = document.createElement('ul');
    
        //Create an array of LI's for the words.
        for (i in this.eligible)
        {
			//MJR - Need this check because the prototype.js code used for the drag/drop 
			//modifies the for(..in..) loop operation.
			if (! this.eligible.hasOwnProperty(i)) continue;

			var word = this.eligible[i];
    
            var li = document.createElement('li');
//            var a = document.createElement('a');
//            a.href="javascript:false";
//            a.innerHTML = word;
//            li.appendChild(a);
			li.innerHTML = word;
	
            if (me.highlighted == i)
            {
                li.className = "selected";
            }
    
            ul.appendChild(li);
            
            // Only show maxSuggestionsInList in the list
            if (++numInList >= me.maxSuggestionsInList)
            {
               break;
            }
        }
    
        // Then a special message for the last row
        var li = document.createElement('li');
        var a = document.createElement('a');
        a.href="javascript:false";
        a.innerHTML = "<b>&nbsp;&nbsp;Show all results for \"" + me.inputText + "\"</b>";
        li.appendChild(a);
        ul.appendChild(li);

        this.div.replaceChild(ul,this.div.childNodes[0]);
    

        /********************************************************
        mouseover handler for the dropdown ul
        move the highlighted suggestion with the mouse
        ********************************************************/
        ul.onmouseover = function(ev)
        {
            //Walk up from target until you find the LI.
            var target = me.getEventSource(ev);
            while (target.parentNode && target.tagName.toUpperCase() != 'LI')
            {
                target = target.parentNode;
            }
        
            var lis = me.div.getElementsByTagName('LI');
            
    
            for (i in lis)
            {
                var li = lis[i];
                if(li == target)
                {
                    me.highlighted = i;
                    break;
                }
            }
            me.changeHighlight();

			// Clear any timeouts so div stays up 5 more seconds
			if (me.asTimeoutHandle) clearTimeout(me.asTimeoutHandle);
			// Set timeout to remove the div if they stop typing
			me.asTimeoutHandle = setTimeout("hideMyDiv()",5000);

			return;

		};

        /********************************************************
        click handler for the dropdown ul
        insert the clicked suggestion into the input
        ********************************************************/
        ul.onclick = function(ev)
        {
           // if last row selected, pass it through instead of honoring the a href and letting browser handle it
           if (!me.eligible[me.highlighted] || me.highlighted >= me.maxSuggestionsInList) {
              me.useSuggestion();
              me.hideDiv();
              me.cancelEvent(ev);
			  return false;
           }
           else {
              me.hideDiv();
			  return true;  // false;
		   }
        };
    
        this.div.className="suggestion_list";
        this.div.style.position = 'absolute';

    };

    /********************************************************
    determine which of the suggestions matches the input
    ********************************************************/
    this.getEligible = function()
    {
        this.eligible = new Array();
        for (i in this.suggestions) 
        {
			//MJR - Need this check because the prototype.js code used for the drag/drop 
			//modifies the for(..in..) loop operation.
			if (! this.suggestions.hasOwnProperty(i)) continue;

			var suggestion = this.suggestions[i];

			textSuggestion = suggestion.substr(suggestion.indexOf('>') + 1);
            
            if(textSuggestion.toLowerCase().indexOf(this.inputText.toLowerCase()) == "0")
            {
                this.eligible[this.eligible.length]=suggestion;
            }
        }
    };

    /********************************************************
    Helper function to determine the keycode pressed in a 
    browser-independent manner.
    ********************************************************/
    this.getKeyCode = function(ev)
    {
        if(ev)            //Moz
        {
            return ev.keyCode;
        }
        if(window.event)    //IE
        {
            return window.event.keyCode;
        }
    };

    /********************************************************
    Helper function to determine the event source element in a 
    browser-independent manner.
    ********************************************************/
    this.getEventSource = function(ev)
    {
        if(ev)            //Moz
        {
            return ev.target;
        }
    
        if(window.event)    //IE
        {
            return window.event.srcElement;
        }
    };

    /********************************************************
    Helper function to cancel an event in a 
    browser-independent manner.
    (Returning false helps too).
    ********************************************************/
    this.cancelEvent = function(ev)
    {
        if(ev)            //Moz
        {
            ev.preventDefault();
            ev.stopPropagation();
        }
        if(window.event)    //IE
        {
            window.event.returnValue = false;
        }
    }

    /********************************************************
    Helper function to get an index into the array of
    suggestions).
		-1 means they selected the last row special message or
		they selected nothing, which should react the same way
		as selecting the last row special message
    ********************************************************/
    this.getSuggestionIndex = function(suggestion)
    {
        var indexFound = -1;       
        for (i in this.suggestions) 
        {
			//MJR - Need this check because the prototype.js code used for the drag/drop 
			//modifies the for(..in..) loop operation.
			if (! this.suggestions.hasOwnProperty(i)) continue;

			if (suggestion == this.suggestions[i]) {
                indexFound = i;
				break;
            }
        }
        return indexFound;
    }
}

//counter to help create unique ID's
var idCounter = 0;

