//
//  irCombo makes select elements act somewhat like windows auto-complete combo boxes
//
//  - auto-complete features adapted from matt@mattkruse.com
//  - appearance features adapted from ryan@particletree.com
//  - adapted by jclarke@independentreach.com
//  - declares a global singleton irCombo
//  - usage, in script: 
//          var instanceIndex = irCombo.init(selectBoxID); 
//          irCombo.focus(instanceIndex);
//          irCombo.setValue(instanceIndex, v);
//  - input value will be stored in select box passed
//  - tested on Firefox 1.5.0.7 and IE 6.0.2900
//  - wish list:
//       - open select box on alt-up or alt-down in textbox
//       - better repaint on parent transitions
//
var irCombo = new function()
{//irComboImpl handles an array of irComboInstances
    //public methods
    this.init = aaainit;
    this.focus = focus;
    this.setValue = setValue;
    //private members
    var instances = new Array();
    //
    function aaainit(sSelectBoxID)
    {
        if (instances.length==0)
        {
            addEvent(window,"load",setPosition,false);
            addEvent(window,"resize",setPosition,false);
        }
        var sb = document.getElementById(sSelectBoxID);
        var inst = new irComboInstance(sb);
        instances[instances.length] = inst;
        return instances.length-1;
    }
    //
    function addEvent(obj, evType, fn, useCapture)
    {
        if (obj.addEventListener)
        { 
            obj.addEventListener(evType, fn, useCapture); 
        } 
        else if (obj.attachEvent)
        { 
            obj.attachEvent("on"+evType,fn); 
        } 
    } 
    //
    function focus(i)
    {
        instances[i].focus();
    }
    //
    function setPosition()
    {
        for (var i=0;i<instances.length;i++)
        {
            instances[i].setPosition();
        }
    }
    //
    function setValue(i,v)
    {
        instances[i].setValue(v);
    }
    //
    function irComboInstance(selectBox)
    {//inner class 
        //public methods
        this.setPosition = setPosition;
        this.focus = focus;
        this.setValue = setValue;
        //private members
        var myFr; 
        var myMark = "";
        var mySb = selectBox;
        var myTb;
        var insetHeight=2;
		var _tabsSet = false;
        //
        aaainit();
        //
        function aaainit()
        {   
			var initValue = mySb.value;
            if (mySb.options.length==0 || mySb.options[0].value != myMark)
            {//put a placeholder in option 0 to hold current tbText
                var oZero = document.createElement("OPTION");
                oZero.value = myMark;
                mySb.options.add(oZero,0);  
            }
            //mySb.selectedIndex = 0;
            var tbHeight=(mySb.offsetHeight - insetHeight - insetHeight) + "px";
            var tbMarLft = "1px";
            //
            if (isIE())
            {
                myFr = document.createElement("IFRAME");
                myFr.style.margin = 0;
                myFr.style.marginLeft = tbMarLft;
                myFr.style.position = "absolute";
                myFr.style.height = tbHeight;
                myFr.style.border = "none";
                myFr.tabIndex = -1;
                myFr.scrolling = "no";
                mySb.parentNode.appendChild(myFr);
            }
            //
            myTb = document.createElement("INPUT");
            myTb.id = mySb.id + "_tb";
            myTb.style.zIndex = "99999";
            myTb.autocomplete = "OFF";
            myTb.style.margin = 0;
            myTb.style.marginLeft = tbMarLft;
            myTb.style.height = tbHeight;
            myTb.style.position = "absolute";
            myTb.style.border = "none";
			myTb.value = initValue;
            mySb.parentNode.appendChild(myTb);
			try
			{
				if (! _tabsSet)
				{//reindex form tabbing on first instance
					var form = document.forms[0];
					for (var i=0; i < form.elements.length; i++) 
					{ 
						var ele = form.elements[i];
						if (ele.tabIndex>0)
						{
							ele.tabIndex = i+1;
						}
					}  
					_tabsSet=true;
				}
				//insert myTb into tab position of mySb
				myTb.tabIndex = mySb.tabIndex;
				mySb.tabIndex = -1;
			}
			catch (e)
			{
				window.status = "failed to set tabindex for " + mySb.id + ":" + e;
			}
            //
            setWidth();
            setPosition();
            //
            addEvent(myTb,"keyup",tbKeyUp,false);
            addEvent(mySb,"beforecut",selBeforeCut,false);
            addEvent(mySb,"change",selChange,false);
        }
        //
        function find(bPartial)
        {
            var uc = myTb.value.toUpperCase();
            if (uc.length==0)
                return -1       
            for (var i = 1; i < mySb.options.length; i++) 
            {//start search at element 1 because of placeholder at 0    
                var ou = mySb.options[i].text.toUpperCase();
                if (uc==ou)
                    return i;   
                if (bPartial && ou.indexOf(uc)==0)
                    return i;
            }
            return -1;
        }
        function focus()
        {
            myTb.focus();
        }
        function isIE()
        {
            return navigator.userAgent.toLowerCase().indexOf("msie") > -1;
        }
        function selBeforeCut()
        {
            myTb.style.display="none";
            mySb.parentNode.removeChild(myTb);          
            if (myFr)
            {
                myFr.style.display="none";
                mySb.parentNode.removeChild(myFr);
            }
        }
        function selChange()
        {
            myTb.value = mySb.options[mySb.selectedIndex].text;
            myTb.focus();
        }
        function setPosition()
        {
			var curleft = 2;
			var curtop = insetHeight + 1;
			var obj = mySb;
			while (obj = obj.offsetParent) 
			{
				curleft += obj.offsetLeft
				curtop += obj.offsetTop
			}
            myTb.style.top = curtop + "px";
            myTb.style.left = curleft + "px";
            if (myFr)
            {
                myFr.style.top = myTb.style.top;
                myFr.style.left = myTb.style.left;
            }
        }
        function setValue(v)
        {       
            myTb.value = v;
            var i = find(false);
            if (-1 == i)
            {
                mySb.options[0].text = v;
                i = 0;
                setWidth();
            }
            mySb.selectedIndex=i;
        }
        function setWidth()
        {
			if (mySb.offsetWidth<60)
			{
				mySb.style.width="60px";
			}
            var cx = mySb.offsetWidth;
            if (isIE())
				cx -= 20;			
			else
				cx -= 24;
            myTb.style.width = cx + "px";
            if (myFr)
            {
                myFr.style.width = cx + "px";
            }
        }
        function tbKeyUp(e) 
        {
            e = e ? e : event;
            if (e.keyCode==40)
            {//cursor down
                if (e.altKey)
                {//would be nice if we could open the select box here,
                // but I don't know of a way to programmatically open
                }
                else if ( mySb.selectedIndex < mySb.options.length-1)
                {
                    mySb.selectedIndex++;
                    selChange();
                }
                return;
            }
            if (e.keyCode==38 && ! e.altKey  && mySb.selectedIndex >0)
            {//cursor up
                mySb.selectedIndex--;
                selChange();
                return;
            }
            var skipKeys ="8;46;37;38;39;40;33;34;35;36;45;13;";
            if (skipKeys.indexOf(e.keyCode+";") != -1) 
                return;
            var idx = find(true);
            if (idx == -1)
            {//not even partial match - set 0 and leave
                mySb.options[0].text = mySb.options[0].value = myTb.value;
                mySb.selectedIndex = 0;
                setWidth();
                return;
            }
            if (myTb.value==mySb.options[idx].text)
            {//exact match - select and leave
                mySb.selectedIndex = idx;
                return;
            }
            //partial match - append and select trailing characters
            var lenB4 = myTb.value.length;
			var sel = mySb.options[idx].text;
			myTb.value += sel.substr(lenB4);
			var lenNow = myTb.value.length;
			if (myTb.createTextRange) 
			{//IE style   
				var range = myTb.createTextRange(); 
				range.move("character",0);   
				range.moveStart("character",lenB4);
				range.moveEnd("character",lenNow);
				range.select();   
			} 
			else if(myTb.selectionStart) 
			{//Gecko style   
				myTb.focus();   
				myTb.setSelectionRange(lenB4, lenNow);   
			}       
            mySb.selectedIndex = idx;
        }
        //end irComboInstance
    }
//end irComboImpl
}



