/*
	THE $BINDSELECT FUNCTION IS USED TO BIND ANY TWO SELECT FIELDS TOGETHER IN A FORM. THE FIRST FIELD, THE PARENT,
	IS THE CONTROLLING SELECT. WHEN IT CHANGES, THE SECOND FIELD, THE CHILD, IS UPDATED BASED ON THE VALUE OF THE PARENT'S
	SELECTED OPTION.
	
	IN ORDER TO USE THIS FUNCTION, A WEB SERVICE MUST BE SETUP TO RETURN A JSON OBJECT OF THE FOLLOWING FORMAT. NOTE THAT THE
	COLUMNS MUST BE NAMED VALUE AND DISPLAY AND MUST BE IN ALL CAPS. ONLY THE ROWCOUNT VALUE, THE DATA.VALUE ARRAY AND 
	DATA.DISPLAY ARRAY WILL CHANGE.
	{
		"ROWCOUNT":5
		,"COLUMNS":["VALUE","DISPLAY"]
		,"DATA":{
			"VALUE":[1,2,3,4,5]
			,"DISPLAY":["One","Two","Three","Four","Five"]
		}
	}
	
	ARGUMENT DESCRIPTION
	=========================================================================================================
	NAME				TYPE			DESCRIPTION
	path				string			url to the web service
	method				string			method in the web service you wish to invoke
	arg					string			the name of the argument you are providing to the method
	form				string			the id of the form
	parent				string			the id of the parent select
	child				string			the id of the child select
	childRequired		boolean			if results are returned, should the child be required?
	childDefaultValue	string			the value to use for the first option in the updated child select
	childDefaultLabel	string			the text that will display for the first option in the updated 
										child select if results are returned
	otherText			string			id of a text field to use as other input if the child gets no results
	otherTextRequired	boolean			if no results are returned, should the otherText field be required?
	=========================================================================================================
	
	EXAMPLE
	<select name="country" id="country" onchange="$bindSelect('/cfc/web_service.cfc','qry_states','country_id','edit_form','country','state',true,0,'Choose a State','state_other',true);">
		<option value="0">Choose a Country</option>
		<option value="1">United States</option>
		<option value="2">Canada</option>
		<option value="3">United Kingdom</option>
		...
	</select>
	<select name="state" id="state>...</select>
	<input type="text" name="state_other" id="state_other"/>
	
	DEPENDENCIES
	=========================================================================================================
	THIS FUNCTION USES FUNCTIONS IN UTILS.JS. MAKE SURE THAT FILE IS INCLUDED ANYTIME YOU INCLUDE THIS FILE.
*/
function $bindSelect(path,method,arg,form,parent,child,childRequired,childDefaultValue,childDefaultLabel,otherText,otherTextRequired) {
	// CHECK FOR EXISTANCE OF PARENT AND CHILD
	if ( $(parent) != null && $(child) != null ) {
		// GET THE SELECTED VALUE OF THE PARENT
		var objParent = $(parent);
		var objChild = $(child);
		var objOtherText = $(otherText);
		var queryString = "?method=" + method + "&" + arg + "=" + objParent.value + "&queryFormat=column&dummy=" + new Date().getTime();
		path = path + queryString;
		// PASS THE VALUE TO THE AJAX CALL TO RETRIEVE THE CHILD OPTIONS
		var req = new AjaxRequest({
			f:path,
			m:'get',
			t:'json',
			a:'',
			r:function() {
				// SINCE THE RESULT IS A TEXT STRING WE HAVE TO CONVERT IT INTO A JSON OBJECT
				// THE FOLLOWING EVAL STATEMENT WILL CONVERT A VALID JSON STRING INTO AN OBJECT
				var objResult = eval('(' + arguments[0] + ')');
				
				// REMOVE CURRENT OPTIONS
				$removeChildNodes(child);
				
				// IF RESULTS WERE RETURNED CREATE THE OPTIONS
				if (objResult.ROWCOUNT > 0) {
					// CREATE A NEW OPTION ELEMENT
					var option = document.createElement("option");
					option.value = childDefaultValue;
					// CREATE THE TEXT NODE (THE DISPLAYED TEXT FOR THE OPTION)
					option.appendChild(document.createTextNode(childDefaultLabel));
					objChild.appendChild(option);
					
					// LOOP THROUGH THE RESULTS AND ADD THE OPTIONS
					for (var o=0; o<objResult.ROWCOUNT; o++) {
						// CREATE A NEW OPTION ELEMENT
						var option = document.createElement("option");
						option.value = objResult.DATA.VALUE[o];
						// CREATE THE TEXT NODE (THE DISPLAYED TEXT FOR THE OPTION)
						option.appendChild(document.createTextNode(objResult.DATA.DISPLAY[o]));
						objChild.appendChild(option);
					}
					
					if (childRequired) { // CHILD SELECT IS REQUIRED
						// CHECK TO SEE IF IT IS ALREADY REGISTERED AS A REQUIRED FIELD
						if (!validation[form][child].required) {
							// UPDATE THE VALIDATION OBJECT
							// WE ARE USING THE FIELD TYPE FOR THE VALIDATION BECAUSE WITH SELECTS
							// THERE IS DIFFERENT VALIDATION FOR SELECT-ONE AND SELECT-MULTIPLE
							$editValidation('add',form,child,true,objChild.type,objChild.type);
							
							// UPDATE THE LABEL CLASS. SINCE THIS IS BINDING SELECTS IN A UNIFORM FORM WE KNOW THE HTML FORMAT 
							var p = objChild.parentNode;
							var label = p.getElementsByTagName("label");
							label[0].className = "required";
							
							// ADD THE ASTRIX
							var em = document.createElement("em");
							em.appendChild(document.createTextNode('*'));
							// USE INSERTBEFORE BECAUSE THE EM TAG IS FLOATED RIGHT AND MUST COME FIRST TO DISPLAY PROPERLY
							label[0].insertBefore(em,label[0].childNodes[0]);
						}
						
					} else { // CHILD SELECT IS NOT REQUIRED
						// UPDATE THE VALIDATION OBJECT
						$editValidation('remove',form,child);
						
						// CLEAR THE LABEL CLASS.
						var p = objChild.parentNode;
						var label = p.getElementsByTagName("label");
						label[0].className = "";
						
						// REMOVE THE ASTRIX
						var em = label[0].getElementsByTagName("em");
						// IN CASE MULTIPLE <EM>*</EM> TAGS GOT ADDED WE'LL JUST REMOVE ALL OF THEM
						while(em.length > 0) {
							$removeElement(em[0]);
							//label[0].removeChild(em[0]);
						}
					}
					
					// IF OTHERTEXT IS PASSED IN UPDATE THE VALIDATION OBJECT TO MAKE IT NOT REQUIRED
					if (objOtherText != null) {
						$editValidation('remove',form,otherText);
						
						// CLEAR THE LABEL CLASS.
						var p = objOtherText.parentNode;
						var label = p.getElementsByTagName("label");
						label[0].className = "";
						
						// REMOVE THE ASTRIX
						var em = label[0].getElementsByTagName("em");
						// IN CASE MULTIPLE <EM>*</EM> TAGS GOT ADDED WE'LL JUST REMOVE ALL OF THEM
						while(em.length > 0) {
							$removeElement(em[0]);
							//label[0].removeChild(em[0]);
						}
					}
				
				} else { 
					// OTHERWISE CREATE A NO RESULTS FOUND OPTION
					var option = document.createElement("option");
					option.value = childDefaultValue;
					// CREATE THE TEXT NODE (THE DISPLAYED TEXT FOR THE OPTION)
					if (objParent.selectedIndex == 0) {
						option.appendChild(document.createTextNode(childDefaultLabel));
					} else {
						option.appendChild(document.createTextNode('No results found'));
					}
					objChild.appendChild(option);
					
					// MAKE THE CHILD SELECT NOT REQUIRED
					$editValidation('remove',form,child);
					// CLEAR THE LABEL CLASS.
					var p = objChild.parentNode;
					var label = p.getElementsByTagName("label");
					label[0].className = "";
					
					// REMOVE THE ASTRIX
					var em = label[0].getElementsByTagName("em");
					// IN CASE MULTIPLE <EM>*</EM> TAGS GOT ADDED WE'LL JUST REMOVE ALL OF THEM
					while(em.length > 0) {
						$removeElement(em[0]);
						//label[0].removeChild(em[0]);
					}
					
					// IF OTHERTEXT IS PASSED IN AND OTHERTEXT IS REQUIRED UPDATE THE VALIDATION OBJECT
					if (objOtherText != null) {
						if (objParent.selectedIndex != 0 && otherTextRequired) {
							// CHECK TO SEE IF IT IS ALREADY REQUIRED. ONLY UPDATE IT IF THE STATE HAS CHANGED.
							if (!validation[form][otherText].required) {
								// UPDATE THE VALIDATION OBJECT
								$editValidation('add',form,otherText,true,objOtherText.type,'');
								
								// UPDATE THE LABEL CLASS. SINCE THIS IS BINDING SELECTS IN A UNIFORM FORM WE KNOW THE HTML FORMAT 
								var p = objOtherText.parentNode;
								var label = p.getElementsByTagName("label");
								label[0].className = "required";
								
								// ADD THE ASTRIX
								var em = document.createElement("em");
								em.appendChild(document.createTextNode('*'));
								// USE INSERTBEFORE BECAUSE THE EM TAG IS FLOATED RIGHT AND MUST COME FIRST TO DISPLAY PROPERLY
								label[0].insertBefore(em,label[0].childNodes[0]);
							}
						} else {
							// MAKE THE OTHER TEXT NOT REQUIRED
							$editValidation('remove',form,otherText);
							
							// CLEAR THE LABEL CLASS.
							var p = objOtherText.parentNode;
							var label = p.getElementsByTagName("label");
							label[0].className = "";
							
							// REMOVE THE ASTRIX
							var em = label[0].getElementsByTagName("em");
							// IN CASE MULTIPLE <EM>*</EM> TAGS GOT ADDED WE'LL JUST REMOVE ALL OF THEM ONE AT A TIME
							while(em.length > 0) {
								$removeElement(em[0]);
								//label[0].removeChild(em[0]);
							}
						}
					}
				}
				// FIRE THE CHILD'S ONCHANGE EVENT
				// IF THERE IS CHAINING GOING ON THIS WILL ALLOW THE GRANDCHILDREN TO BE UPDATED WHEN THE PARENT CHANGES
				$fireEvent(objChild,"change");
				
				// THE FOLLOWING NONSENSE IS ONLY HERE BECAUSE IN IE7 THE CHILD SELECT CHANGES SIZE IF IT
				// IS SPECIFIED AS A PERCENTAGE. SO IF IT IS SET TO WIDTH:50% THEN EACH TIME AN OPTION IS ADDED
				// OR REMOVED IT WILL BECOME ABOUT HALF AS WIDE AS BEFORE. THE FOLLOWING HACK SEEMS TO FIX THIS.
				objChild.style.visibility = 'hidden';
				objChild.style.visibility = 'visible';
			
			} // END AJAX RETURN FUNCTION
		}); // END NEW AJAX REQUEST
	} // END CHECK FOR EXISTANCE OF PARENT AND CHILD
} // END BINDSELECT FUNCTION