var LOVOptions = new Array();
var LOVTimer = new Array();
var httpRequest = new Array();

function cascadeLOV(URL, Delay, LOVGroup, fieldUpdated, fieldHandles, blankDisplay, disableMatching, addNewOption, selectSingleMatch, selectValues) {
	//URL - The URL that returns the LOV options javascript array. Leave blank to use existing options
	//Delay - the number of milliseconds to wait before refreshing LOV options. Useful for waiting for user to finish typing
	//LOVGroup - The LOV group id number. Used for using this function for multiple LOV groups
	//fieldUpdated is the number of the field calling the function
	//fieldHandles is a record of LOV/SELECT fields. Select tag names should match the names in LOVOptions. 
	//blankDisplay is the TEXT to display for a blank LOV option (eg. '<All>')
	//disableMatching - if this is set to true, LOV's will be disabled if there is only 1 matching value
	//addNewOption - an a array containing the field numbers to allow <Add New> options
	//selectSingleMatch - if the filter returns a single option for an LOV, should it be selected
	//selectValues - an array of values to selected, used for setting initial values for editing. 

	if(URL!='') {
		//Disable the fields while the data is refreshing
		for (x=0;x<fieldHandles.length;x++) {
			fieldHandles[x].disabled=true;
		}
		httpRequest[LOVGroup] = getHTTPRequest('text/javascript');    
    	URL=encodeURI(URL);

		if (Delay > 0) {
			if ( LOVTimer[LOVGroup] != null ) {
	    		window.clearTimeout( LOVTimer[LOVGroup] );
	    	}
  			LOVTimer[LOVGroup] = window.setTimeout( function watchRequest() {
			    httpRequest[LOVGroup].onreadystatechange = function() { 
					if (httpRequest[LOVGroup].readyState == 4 && httpRequest[LOVGroup].status == 200 ) {
						LOVOptions[LOVGroup] = eval(httpRequest[LOVGroup].responseText);
						cascadeLOV('', 0, LOVGroup, fieldUpdated, fieldHandles, blankDisplay, disableMatching, addNewOption, selectSingleMatch, selectValues);
					}
				};
   				httpRequest[LOVGroup].open('GET', URL, true);
   				httpRequest[LOVGroup].send(null);
				LOVTimer[LOVGroup] = null;
			}, Delay );
		} else {
			if ( LOVTimer[LOVGroup] != null ) {
	    		window.clearTimeout( LOVTimer[LOVGroup] );
	    		LOVTimer[LOVGroup] = null;
	    	}
		    httpRequest[LOVGroup].onreadystatechange = function() { 
					if (httpRequest[LOVGroup].readyState == 4 && httpRequest[LOVGroup].status == 200 ) {
						LOVOptions[LOVGroup] = eval(httpRequest[LOVGroup].responseText);
						cascadeLOV('', 0, LOVGroup, fieldUpdated, fieldHandles, blankDisplay, disableMatching, addNewOption, selectSingleMatch, selectValues);
					}
			};
    		httpRequest[LOVGroup].open('GET', URL, true);
    		httpRequest[LOVGroup].send(null);
		}
		return true;
	}
	

	prevValue='';
	
	if(!blankDisplay) blankDisplay="";
	if(!disableMatching) disableMatching=false;
	if(!addNewOption) addNewOption = new Array();
	if(!selectSingleMatch) selectSingleMatch = true;

	for (fNum=fieldUpdated+1; fNum<fieldHandles.length; fNum++) {
		//Clear the current options
		for (op=fieldHandles[fNum].options.length; op>=0; op--) {
			//lFields[fLocation].options.remove(i);   may be required for netscape? who cares?
			fieldHandles[fNum].options[op] = null;
		}

		//Add a blank option to the LOV
		fieldHandles[fNum].options[0] = new Option(blankDisplay,'',false,true);

		if (fNum == fieldUpdated+1) {
			//Step through the LOVOptions
			for (i=0; i<LOVOptions[LOVGroup].length; i++) {
				if(prevValue!=LOVOptions[LOVGroup][i][fNum]) {
					prevValue=LOVOptions[LOVGroup][i][fNum];
					match=true;
					for (fMatch=0; fMatch<=fieldUpdated; fMatch++) {
						if (LOVOptions[LOVGroup][i][fMatch]!=fieldHandles[fMatch].value) {
							match=false;
						}
					}

					if (match && LOVOptions[LOVGroup][i][fNum]!='') {
						fieldHandles[fNum].options[fieldHandles[fNum].options.length] = new Option(LOVOptions[LOVGroup][i][fNum],LOVOptions[LOVGroup][i][fNum],false,false);
					}
				}
			}
		}
		//Enable all fields if disabling is turned on
		if(disableMatching) fieldHandles[fNum].disabled=false;
	}



	//Add an <Add New> option to fields specified by the addNewOption array
	for (h=0; h<addNewOption.length; h++) {
		fNum=addNewOption[h];
		if (fieldHandles[fNum-1].value!=''){
			if (fieldHandles[fNum].options[fieldHandles[fNum].options.length-1].value != '<Add New>') {
				fieldHandles[fNum].options[fieldHandles[fNum].options.length] = new Option('(Add New)------------>','<Add New>',false,false);
			}
		}
	}

	//If only one option exists for a field and that option was not selected before, select it
	if(selectSingleMatch) {
		if(fieldUpdated+1<fieldHandles.length) {
			if(fieldHandles[fieldUpdated+1].options.length<=2 || (fieldHandles[fieldUpdated+1].options.length==3 && fieldHandles[fieldUpdated+1].options[2].value=='<Add New>') ) {
				fieldHandles[fieldUpdated+1].options[1].selected = true;
				cascadeLOV('',0,LOVGroup, fieldUpdated+1, fieldHandles, blankDisplay, disableMatching, addNewOption, selectSingleMatch);
				if(disableMatching) fieldHandles[fieldUpdated+1].disabled = true;
			}
		}
	}
	//If default values have been specified
	if(selectValues != undefined) {
		fieldUpdated++;
		if(fieldUpdated < selectValues.length) {
			if(selectValues[fieldUpdated]!='') {
				fieldHandles[fieldUpdated].value = selectValues[fieldUpdated];
				cascadeLOV('',0,LOVGroup, fieldUpdated, fieldHandles, blankDisplay, disableMatching, addNewOption, selectSingleMatch, selectValues);
			}
		}
	}
}
