
// Begin LookupStateCounties.ajax.js
// Created by: Steve Seaquist
//
// Inputs (the first 2 are required):
//		pStCd			String containing a valid 2-letter state code. 
//		pEltDropdown	Form element reference to the dropdown menu	form element to be populated. 
//
// Two example usages (both of which use onChange instead of a "Lookup" button or hotlink): 
//
//		<input type="Text" name="MyStCd"  size="2" maxlength="2" onChange="
//		if	(EditState('State Code', this, 1))
//			{
//			LookupStateCounties(this.value, this.form.MyCntyDropdown);
//			return true;
//			]
//		this.focus();
//		return false;
//		">
//
//		<select name="MyStCd" size="10" multiple onChange="
//		var	sLastOptSelected		= 0;
//		var	sNumberSelected			= 0;
//		for	(var i = 1; i < this.options.length; i++)	// skip 0-th position, which says "Any state"
//			if	(this.options[i].selected)
//				{
//				sNumberSelected++;
//				if	(sNumberSelected > 1)
//					break;
//				sLastOptSelected	= i;
//				}
//		if	(sNumberSelected == 1)
//			LookupStateCounties(this.options[sLastOptSelected].value, this.form.MyCntyDropdown);
//		">
//
// For an example that uses a lookup hotlink, see DSBS (/pro-net/search/dsp_dsbs.cfm). 
//
// NEW FEATURE: You can now use gLookupStateCountiesMenuSelList to preselect a county, or even several counties. 
// Its name ends in "SelList" to make it similar to "DspOptsSelList", used by /library/cfincludes/dsp_options.cfm. 
// But because this is JavaScript, the SelList is actually an Array. If the dropdown is a <select multiple>, you 
// can pass more than one county code to select multiple counties. For example: 
//
//		gLookupStateCountiesMenuSelList	= ["031","033"];
//		LookupStateCounties(...);
//
// If the dropdown is NOT a <select multiple>, you would pass at most one element. 
//
//		gLookupStateCountiesMenuSelList	= ["033"];	// Although only one, use array literal syntax (must be an array). 
//		LookupStateCounties(...);
//
// If you don't set it to anything, it defaults to an empty array ([]), which will not preselect any county. If you 
// use gLookupStateCountiesMenuSelList, be careful about leftover previous values. That is, if you set it once, you 
// pretty much have to set it on every call (on the same page). 
//
// Steve Seaquist, 04/13/2007

// Set these before calling LookupStateCounties to get other behaviors: 
var	gLookupStateCountiesAsyncly			= true;											// false = synchronously. 
var	gLookupStateCountiesCallback		= "/library/callbacks/ajax/dsp_LookupStateCounties.ajax.cfm";	// Allows override. 
var	gLookupStateCountiesMenuNotSelText	= "Not selected yet";							// Text to appear in first item. 
var	gLookupStateCountiesMenuShowCode	= false;										// true = display county code too. 
var	gLookupStateCountiesMenuSelList		= [];											// Array of CntyCds to be selected. 
var	gLookupStateCountiesTimeout			= 10000;										// 10,000 milliseconds = 10 seconds. 
var	gLookupStateCountiesTrace			= false;										// true = display trace alerts. 
var	gSilentLookupStateCounties			= false;										// true = don't complain to user. 

// These will get set automatically (= DON'T MESS WITH THEM!!): 
var	gLookupStateCountiesMenu			= null;											// Set by call. 
var	gLookupStateCountiesRows			= null;											// Set by call. Usable externally. 
var	gLookupStateCountiesAborting		= false;										// Set by call. 
var	gLookupStateCountiesTimeoutId		= null;											// Set by call. 
var	gLookupStateCountiesXHR				= false;										// Set by call. 

function LookupStateCountiesAbort		()
{
gLookupStateCountiesAborting			= true;
gLookupStateCountiesXHR.abort();
alert("Unable to contact the SBA server to lookup counties. "
	+ "If you are still connected to the Internet, the problem could be that the SBA server is down.");
}

function LookupStateCountiesRow			(pCntyCd, pCntyNm)
{// Allows you to reference gLookupStateCountiesRows[3].CntyNm, for example. 
this.CntyCd								= pCntyCd;
this.CntyNm								= pCntyNm;
}

function LookupStateCountiesCopier	()
{
if	(gLookupStateCountiesXHR.readyState == 4)
	{
	// There is a reported bug that Mozilla sometimes goes to readyState 4 when the request is aborted. 
	// Even if fixed in newer versions of the browser, the user could still have the older, buggy version. 
	// So the following 2 lines prevent us from trying to process responseXML when the request times out: 
	if	(gLookupStateCountiesAborting)
		return;
	// Since we now know that we're NOT aborting, make sure we don't abort AFTER readyState has gone to 4: 
	window.clearTimeout					(gLookupStateCountiesTimeoutId);
	// We also don't want to process responseXML if we didn't get back a 200 OK from the server: 
	if	(gLookupStateCountiesXHR.status == 200)
		{
	//	alert(gLookupStateCountiesXHR.responseText);
		var	sRoot						= gLookupStateCountiesXHR.responseXML.documentElement;
		window.gLookupStateCountiesRows	= new Array();	// window forces reference to be global 
		var	sTopNode					= false;
		var	sTopNodes					= sRoot.childNodes;
		for	(var i = 0; i < sTopNodes.length; i++)
			if	(sTopNodes[i].nodeType == 1)	// Not firstChild, but rather the first ELEMENT. 
				{
				sTopNode				= sTopNodes[i];
				break;
				}
		if	(!sTopNode)
			{
			alert("INTERNAL ERROR. Please report this error: Unable to lookup counties because top node was not found.");
			return;
			}
		if		(sTopNode.nodeName == "I")	alert("INTERNAL ERROR. Unable to lookup counties. Please report this error: "
												+ sTopNode.firstChild.nodeValue);
		else if	(sTopNode.nodeName == "E")	alert("Unable to lookup counties. "
												+ sTopNode.firstChild.nodeValue);
		else if	(sTopNode.nodeName == "R")
			{
			var	sCntyCd,sCntyNm;
			var	sRows					= sTopNode.getElementsByTagName("r");
			var	sRowsLen				= sRows.length;
			LookupStCntyClearDropdown	();
			LookupStCntyAddToDropdown	("", gLookupStateCountiesMenuNotSelText);
			for	(var i = 0; i < sRowsLen; i++)
				{
				sCntyCd = sCntyNm = "";
				var	sData				= sRows[i].childNodes;
			//	var	sDump				= "";
				for	(var j = 0; j < sData.length; j++)
					if	(sData[j].nodeType == 1)
						{
						var	sNode		= sData[j];			// Minimizes indexing.
						var	sName		= sNode.nodeName;
						var	sValue		= sNode.hasChildNodes() ? sNode.firstChild.nodeValue : "";
			//			sDump			+= sName + " is '" + sValue + "'.\n";
						switch (sName)
							{
							case "c":	sCntyCd	= sValue;	break;
							case "C":	sCntyNm	= sValue;	break;
							}
						}
				// window forces reference to be global: 
				window.gLookupStateCountiesRows[window.gLookupStateCountiesRows.length]
					= new LookupStateCountiesRow(sCntyCd, sCntyNm);
				if	(gLookupStateCountiesMenuShowCode)
					LookupStCntyAddToDropdown (sCntyCd, sCntyCd + " - " + sCntyNm);
				else
					LookupStCntyAddToDropdown (sCntyCd, sCntyNm);
			//	alert(sDump);
				}
			}
		else
			alert("INTERNAL ERROR. Unable to lookup counties. Please report this error: Unrecognized top node '"
				+ sTopNode.nodeName + "'.");
		}
	else
		alert("INTERNAL ERROR. Unable to lookup counties. Please report this error: "
			+ "Callback status code " + gLookupStateCountiesXHR.status + ".");
	}
}

function LookupStateCounties			(pStCd, pEltDropdown)
{
if	(gLookupStateCountiesTrace)			alert("LookupStateCounties");
// We don't know how the user inputted the state code, so we can't give the more precise error message generated by EditMask. 
gSilentEditMask						= 1;
if	(!EditMask('', pStCd, 'A', 1, 2, 2))
	{
	if	(!gSilentLookupStateCounties)
		alert("Error. Invalid state code (not alphabetic or not enough letters, for example).")
	gSilentLookupStateCounties			= false;// Always reset to false, just like EditMask always resets gSilentEditMask. 
	return false;
	}
if	(pStCd.length < 2)
	{
	if	(!gSilentLookupStateCounties)
		alert("Error. Invalid state code (must be 2 letters).");
	gSilentLookupStateCounties			= false;
	return false;
	}
if	(gLookupStateCountiesTrace)			alert("Start building the callback.");
// Start building the callback: 
var	sURL								= gLookupStateCountiesCallback + "?StCd=" + escape(pStCd);
gLookupStateCountiesMenu				= pEltDropdown;
if	(gLookupStateCountiesTrace)			alert(sURL);
if	(!gLookupStateCountiesXHR)
	{
	gLookupStateCountiesXHR				= GetXMLHttpRequest();
	if	(!gLookupStateCountiesXHR)
		{
		alert("Unable to do counties lookup.");
		return;
		}
	}
if	(gLookupStateCountiesXHR)
	if	((gLookupStateCountiesXHR.readyState == 0) || (gLookupStateCountiesXHR.readyState == 4))
		{
		// To allow reuse of the XMLHttpRequest object in Internet Explorer, the call to open() must preceed the setting of 
		// onreadystatechange. This bug doesn't exist in other browsers. 
		gLookupStateCountiesXHR.open	("GET", sURL, gLookupStateCountiesAsyncly);
		gLookupStateCountiesAborting	= false;	// In case a previous request was aborted. 
		if	(gLookupStateCountiesAsyncly)
			{
			gLookupStateCountiesXHR.onreadystatechange	= LookupStateCountiesCopier;
			gLookupStateCountiesTimeoutId	= window.setTimeout(LookupStateCountiesAbort, gLookupStateCountiesTimeout);
			gLookupStateCountiesXHR.send("");
			}
		else // In case there was a previous async call, we don't want the onreadystatechange handler to be used in sync mode: 
			{
		//	gLookupStateCountiesXHR.onreadystatechange	= null;	// MSIE complains of type mismatch if we do this. 
			gLookupStateCountiesXHR.send("");
			LookupStateCountiesCopier	()
			}
		}
	else
		alert("Cannot look up counties, because another lookup of counties is pending. "
			+ "This can be caused by double-clicking on a lookup button, for example. Please wait and try again.");
}

// These scripts are called by the JavaScript code generated by the callback routine (see gLookupStateCountiesCallback, 
// above). You would normally never call them yourselves. By defining them in the same file as LookupStateCounties, we make 
// it easier to use. Just add this one file in your scripts and call LookupStateCounties. Shared code does everything else. 

function LookupStCntyAddToDropdown		(pCntyCd, pCntyNm)
{
if	(gLookupStateCountiesTrace)			alert("LookupStCntyAddToDropdown('"
											+ pCntyCd			+ "','"
											+ pCntyNm			+ "')");
var	sMenu								= gLookupStateCountiesMenu;	// dropdown element of most recent LookupStateCounties. 
var	sOpt;
if	(navigator.appName == "Netscape")
	sOpt								= new Option(pCntyNm, pCntyCd);
else
	{
	sOpt								= document.createElement("OPTION");
	sOpt.text							= pCntyNm;
	sOpt.value							= pCntyCd;
	}
var	sOpts								= sMenu.options;
var	sOptsLen							= sOpts.length;	// sOptsLen stays same value after the following (intentional): 
sOpts[sOptsLen]							= sOpt;
// THE FOLLOWING MUST BE DONE ***AFTER*** COPYING sOpt TO sOpts[sOptsLen]. Opera for Windows doesn't preserve the 
// selected property in the copy from sOpt to sOpts[sOptsLen]. It doesn't much matter in MSIE and Netscape, but by 
// coding to the lowest common denominator, we eliminate user complaints in the future. 
for	(var i = 0; i < gLookupStateCountiesMenuSelList.length; i++)
	if	(pCntyCd == gLookupStateCountiesMenuSelList[i])
		{
		sOpts[sOptsLen].selected		= true;
		break;
		}
}

function LookupStCntyClearDropdown		()
{
if	(gLookupStateCountiesTrace)			alert("LookupStCntyClearDropdown");
var	sMenu								= gLookupStateCountiesMenu;	// dropdown element of most recent LookupStateCounties. 
sMenu.options.length					= 0;
}

// End LookupStateCounties.ajax.js


