
var idCounter = 0;
var _allAutoSuggests = [];
function AutoSuggest(elem, maxDigits, suggestType, suggestions)
{
	//The 'me' variable allow you to access the AutoSuggest object
	//from the elem's event handlers defined below.
	var me = this;
	
	// Add ourself to the list of autosuggests
	_allAutoSuggests.push(this);

	//A reference to the element we're binding the list to.

	this.elem = elem;

	this.elemID = this.elem.id;
	this.oldVal = this.elem.value;
	
	if (elem.onchange) {
	    this.cb = elem.onchange;
	    elem.onchange = null;
	}
	elem.setAttribute("autocomplete", "off");
	
	this.suggestions = suggestions;
	this.maxDigits = maxDigits;
	this.suggestType = 'numeric';
	
	if (suggestType && suggestType.length > 0)
	    this.suggestType = suggestType;

	//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.
	var newDiv = document.createElement('DIV');
	newDiv.id = this.elem.id + '.ac';
	newDiv.className = 'suggestion';
	var ul = document.createElement('UL');
	newDiv.appendChild(ul);
	// Keep a reference to it
	this.div = newDiv;
	document.body.appendChild(this.div);
	// An iframe used to get around an IE6 bug where
	// select boxes always show up in front of divs
	var newFrm = document.createElement('IFRAME');
	newFrm.src = 'about:blank';
	newFrm.setAttribute('scrolling','no');
	newFrm.setAttribute('frameborder','0');
	newFrm.style.position = 'absolute';
	newFrm.style.border = 'none';
	newFrm.style.visibility = 'hidden';
	// Keep a reference
	this.ifrm = newFrm;
	document.body.appendChild(this.ifrm);
	
	//Do you want to remember what keycode means what? Me neither.
	var TAB = 9;
	var ENTER = 13;
	var ESC = 27;
	var KEYUP = 38;
	var KEYDN = 40;

	//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)
		elem.id = "autosuggest" + ++idCounter;

	/********************************************************
	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);
		
		switch(key)
		{
		    case TAB:
		        var val = me.elem.value;
		        if (me.oldVal != val && me.cb) {
		            me.cb.call(me.elem);
		            me.oldVal = val;
		        }
		        me.hideDiv();
		        break;
			case ENTER:
		        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 - 1))
				    me.highlighted++;
			    me.changeHighlight(key);
			    break;
		}
	};


	/********************************************************
	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);
		switch(key)
		{
		    //The control keys were already handled by onkeydown, so do nothing.
		    case TAB:
		    case ENTER:
		    case ESC:
		    case KEYUP:
		    case KEYDN:
			    return;
		    default:
			    if (this.value != me.inputText && this.value.length > 0) {
				    me.inputText = this.value;
				    me.getEligible();
				    me.createDiv();
				    me.positionDiv();
				    me.showDiv();
			    } else {
				    // me.hideDiv();
			    }
		}
	};
	//document.onclick = function(){AutoSuggest.onMouseDownHandler.bind(this);};
	Utils.BrowserCompat.attachEvent(document, 'onclick', this.onMouseDownHandler.bind(this));
	
}
AutoSuggest.prototype.onMouseDownHandler = function(ev) {

    // Don't worry about this unless the div is showing
    if (this.div.style.visibility != 'visible')
        return;

    // Get the event source
    var target = (ev ? ev.target : window.event.srcElement);
    // Walk up the tree to make sure we're not on our AutoSuggest
    var inThisDiv = false;
    var thisDiv = this.div;
    while (target != null) {
        if (target == thisDiv) {
            inThisDiv = true;
            break;
        }
        target = target.parentNode;
    }

    // If we're not on the active suggest div, hide it
    if (!inThisDiv) {
        this.hideDiv(); 
        if (this.cb)
            this.cb.call(this.elem);
    }
    

}


/********************************************************
Insert the highlighted suggestion into the input box, and 
remove the suggestion dropdown.
********************************************************/
AutoSuggest.prototype.useSuggestion = function() {
    if (this.highlighted > -1) {
        // Detect IE from the user agent.  Better ways to do this?
        //var isIE = (/MSIE (\d+\.\d+);/.test(navigator.userAgent))
        
        //var id = this.eligibleID[this.highlighted];
        var val = this.eligible[this.highlighted];
        this.elem.value = val;
        //this.hideDiv();

        if (this.suggestType == 'city') {
            var stateCodeEl = document.getElementById('DefaultStateCode');
            if (stateCodeEl && val.indexOf(',') < 0)
                val += ',' + stateCodeEl.value;
            this.elem.value = val;

           // if (this.elemID && this.elemID != null)
            //    this.elemID.value = id;

            if (this.oldVal != val && this.cb)
                this.cb.call(this.elem);
        } else {
            this.elem.value = val;
            //if (this.elemID && this.elemID != null)
            //    this.elemID.value = id;
            // If there was a callback attached to the element, call it
            if (this.oldVal != val && this.cb)
                this.cb.call(this.elem);
        }
        this.hideDiv();
    } else {
        // If there was a callback attached to the element, call it
        if (this.oldVal != val && this.cb)
            this.cb.call(this.elem);
        this.hideDiv();
    }
    this.oldVal = val;
}


/********************************************************
Display the dropdown. Pretty straightforward.
********************************************************/
AutoSuggest.prototype.showDiv = function()
{
    this.ifrm.style.visibility = 'visible';
    this.div.style.visibility = 'visible';
}

/********************************************************
Hide the dropdown and clear any highlight.
********************************************************/
AutoSuggest.prototype.hideDiv = function()
{
    this.ifrm.style.visibility = 'hidden';
    this.div.style.visibility = 'hidden';
    this.highlighted = -1;
}

/********************************************************
Modify the HTML in the dropdown to move the highlight.
********************************************************/
AutoSuggest.prototype.changeHighlight = function()
{
	var lis = this.div.getElementsByTagName('LI');
	for (var i=0, len=lis.length; i<len; i++) {
	    var li = lis[i];
		if (this.highlighted == i)
			li.className = "selected";
		else
			li.className = "";
	}
}

/********************************************************
Position the dropdown div below the input text field.
********************************************************/
AutoSuggest.prototype.positionDiv = function()
{
	var el = this.elem;
	var x = 0;
	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;
		el = el.offsetParent;
	}

	x += el.offsetLeft;
	y += el.offsetTop;

    // Set the position of the autosuggest div + iframe
    var divStyle = this.div.style;
    var frmStyle = this.ifrm.style;
    
	frmStyle.left = x+1 + 'px';
    frmStyle.top = y+1 + 'px';
    frmStyle.width = this.div.offsetWidth + 'px';
    frmStyle.height = this.div.offsetHeight + 'px';

	divStyle.left =  frmStyle.left;
	divStyle.top = frmStyle.top;
}

/********************************************************
Build the HTML for the dropdown div
********************************************************/
AutoSuggest.prototype.createDiv = function()
{
    var thisDiv = this.div;
    var thisEligible = this.eligible;
	var ul = document.createElement('ul');

	//Create an array of LI's for the words.
	for (var i=0, len=thisEligible.length; i<len; i++) {
		var li = document.createElement('li');
		var a = document.createElement('a');
		a.setAttribute('href','javascript:void(0)');
		a.innerHTML = '<nobr>' + thisEligible[i] + '</nobr>';
		li.appendChild(a);

		if (this.highlighted == i)
			li.className = "selected";

		ul.appendChild(li);
	}
	thisDiv.replaceChild(ul, thisDiv.childNodes[0]);

	var me = this;
	/********************************************************
	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 = thisDiv.getElementsByTagName('LI');
		for (var i=0, len=lis.length; i<len; i++)
		{
			if(lis[i] == target) {
				me.highlighted = i;
				break;
			}
		}
		me.changeHighlight();
	};

	/********************************************************
	click handler for the dropdown ul
	insert the clicked suggestion into the input
	********************************************************/
	ul.onclick = function(ev)
	{
		me.useSuggestion();
		me.hideDiv();
		me.cancelEvent(ev);
		return false;
	};
}

/********************************************************
determine which of the suggestions matches the input
********************************************************/
AutoSuggest.prototype.getEligible = function()
{
    var newEligible = [];
	if (this.suggestType == 'city') {
	    var suggs = this.suggestions;
	    for (var i=0, len=suggs.length; i<len; i++)
	    {
		    var suggestion = suggs[i];
		    if(suggestion.toLowerCase().indexOf(this.inputText.toLowerCase()) == "0")
			    newEligible.push(suggestion);
	    }
	} else { // Assume this is numeric
	    var txt = this.inputText;
	    txt = txt.replace(",", "");
        txt = txt.replace(".", "");
        if (txt.length > 0 && IsNumeric(txt))
        {
            var zeros = '';
            var len = this.maxDigits-txt.length;
            for (i = 0; i < len; i++) {
              zeros += "0";
              newEligible.push(Utils.Format.addCommas(txt + zeros));
            }
        }
    }
    this.eligible = newEligible;
}

/********************************************************
Helper function to determine the keycode pressed in a 
browser-independent manner.
********************************************************/
AutoSuggest.prototype.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.
********************************************************/
AutoSuggest.prototype.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).
********************************************************/
AutoSuggest.prototype.cancelEvent = function(ev)
{
	if(ev)			//Moz
	{
		ev.preventDefault();
		ev.stopPropagation();
	}
	if(window.event)	//IE
	{
		window.event.returnValue = false;
	}
}