//Queries the specified XML for a match of the value in the combobox. If found, returns
//the XML node that matches and sets the hidden field's value to the node's Id attribute.
//Returns null if no matching node is found in XML and sets hidden field to 0;
function FindSelectedItem( oXML, strItemTypeName )
{
	var oNode = oXML.selectSingleNode( "//" + strItemTypeName + "[@Name=\"" + oComboText.value + "\"]" );

	if ( oNode )
		oId.value = oNode.getAttribute( "Id" );
	else
		oId.value = 0;
	
	return oNode;
}


function GetComboTextId ( oXML, strItemTypeName, strName )
{
	var iId = 0;
	var oNode = oXML.selectSingleNode( "//" + strItemTypeName + "[@Name=\"" + strName + "\"]" );

	if ( oNode )
	{
		iId = oNode.getAttribute( "Id" );
	}
		
	return iId;
}


function ConvertXMLToString( strIn )
{
	var strOut;
	if ( !strIn || strIn.toLowerCase() == "null" )
		strOut = "";
	else
		strOut = strIn;
		
	return strOut;
}


function Transform( oTgtEl, oSrcXML, oStyleXSL )
{
	//Transform source XML with the XSL sheet
	oTgtEl.innerHTML = oSrcXML.transformNode(oStyleXSL.XMLDocument);
}


function TransformShows( iDaysToDisplay, iShowFieldset, oTgtEl, oSrcXML, oStyleXSL, oBandXML, oVenueXML, oAgesXML )
{
	var oDaysParam = oStyleXSL.selectSingleNode( "//xsl:param[@name='DaysToDisplay']" );
	var oFieldsetParam = oStyleXSL.selectSingleNode( "//xsl:param[@name='ShowFieldset']" );

	if ( oDaysParam )
		oDaysParam.setAttribute( "select", iDaysToDisplay );							//re-set the XSL Parameter DaysToDisplay to iDaysToDisplay
	if ( oFieldsetParam )
		oFieldsetParam.setAttribute( "select", iShowFieldset );						//re-set the fieldset parameter to iShowFieldset

	//parse Source XML, adding venue and band info for the first iDaysToDisplay days
	ParseShows( oSrcXML, iDaysToDisplay, oBandXML, oVenueXML, oAgesXML );

	//Transform parsed XML with the XSL sheet	
	oTgtEl.innerHTML = oSrcXML.transformNode(oStyleXSL.XMLDocument);
}


function ParseShows ( oSrcXML, iDays, oBandXML, oVenueXML, oAgesXML )
{
	var i = 0;								//loop counter (shows)
	var j = 0;								//loop counter (bands)
	var iBands = 0;						//number of bands per show;
	var oShowList;						//loop list object (list of shows)
	var oCurrNode;						//Node currently being parsed
	var oBandRoot;
	var oBandList;
	var iToday;								//Days between 1/1/1900 and today, used to diff with show date
	var iCurrShowDay;					//Days between 1/1/1900 and current show's date.

	oCurrNode = oSrcXML.selectSingleNode("//ShowList");

	//Get Today's integer value from Show XML;
	iToday = oCurrNode.getAttribute("Today");
	
	//Walk through children of ShowList node (shows)
	oShowList = oCurrNode.childNodes;
	for ( i = 0; i < oShowList.length; i++ )
	{
		//if show is more than iDays after Today, exit loop
		iCurrShowDay = oCurrNode.getAttribute("Days");
		if ( (iCurrShowDay - iToday) > iDays )
			break;
		
		oCurrNode = oShowList[i];																																								//set current node
		GetVenueInfo( oVenueXML, oAgesXML, oCurrNode, oCurrNode.getAttribute("VenueId") );											//Get info from Venue XML and add to Show XML
		GetAgeInfo( oAgesXML, oCurrNode, oCurrNode.getAttribute("AgeId") );

		//parse bands
		oBandRoot = oCurrNode.selectSingleNode("Bands");																												//get "Bands" node object
		oBandList = oBandRoot.childNodes;																																				//create list of it children
		iBands = oBandList.length;																																							//number of bands on the bill
		
		for ( j = 0; j < iBands; j++ )																																					//walk bandlist and info for each band
			GetBandInfo ( oBandXML, oBandList[j], oBandList[j].getAttribute("Id") );
		
		for ( j = 0; j < iBands; j++ )																																					//remove original (bare) nodes from bill
			oBandRoot.removeChild( oBandRoot.childNodes.item(0) );
	}
}


function GetBandInfo ( oBandXML, oSrcNode, iBandId )
{
	var oCurrNode;						//Node currently being parsed
	var oParNode;							//Parent Node of oSrcNode
	var oNewNode;							//temporary node for cloning band information into show tree
	
	oParNode = oSrcNode.parentNode;
	oCurrNode = xmlBands.selectSingleNode("//Band[@Id='" + iBandId + "']");
	oNewNode = oCurrNode.cloneNode(true);					//deep copy
	oParNode.appendChild(oNewNode);
}
				

function GetVenueInfo ( oVenueXML, oAgeXML, oSrcNode, iVenueId )
{
	var oCurrNode = oVenueXML.selectSingleNode( "//Venue[@Id='" + iVenueId + "']" );														//Node currently being parsed
	var iVenueAge = oCurrNode.getAttribute("AgeId");
	var oNewNode;																																																//temporary node
	var oAgeNode = oCurrNode.selectSingleNode( "Age" );

	if ( !oAgeNode )																																														//check to see if Venue already has Age info
		GetAgeInfo( oAgeXML, oCurrNode, iVenueAge );																																//if not, add it
	oNewNode = oCurrNode.cloneNode(true);																																				//deep copy (must include age info)
	oSrcNode.appendChild( oNewNode );																																						//add copied node as source el's child
}


function GetAgeInfo ( oAgeXML, oSrcNode, iAgeId )
{
	var oCurrNode = oAgeXML.selectSingleNode("//Age[@Id='" + iAgeId + "']");
 	var oNewNode = oCurrNode.cloneNode(false);

	oSrcNode.appendChild( oNewNode );
}


function GetXMLValue( oXML, strElementName, strSearchAttributeName, strSearchValue, strTargetAttributeName )
{
	var strRet = "0";
	var oVNode;

	oNode = oXML.selectSingleNode("//" + strElementName+ "[@" + strSearchAttributeName + "='" + strSearchValue + "']");			//find node that matches 
	if ( oNode )
	{
		strRet = oNode.getAttribute( strTargetAttributeName );
	}
	return strRet;
}


//Return true if the file has finished downloading, false if not
function IsXMLLoaded(oXML)
{
	var bRet = oXML.readyState == 4;
//alert("IsXMLLoaded returning " + bRet);	
	return bRet;
}


//Return true if the file has a recognizable document element with at least one child node.
function IsXMLValid(oXML)
{
	bRet = (
		oXML.parseError.errorCode == 0 
		&& null != oXML.documentElement 
		&& oXML.documentElement.childNodes.length > 0
	);
	return bRet;
}


//Given a string, returns Band XML object that should contain it based on its first character
function GetBandXMLObject( strName )
{
	var oRet = null;
	var iFirstCharCode = strName.toUpperCase().charCodeAt(0);
	var iFileIndex = 0;

	if (iFirstCharCode >= 65 && iFirstCharCode <= 90)
	{
		iFileIndex = iFirstCharCode - 64;
	}
	
	return BandXml[iFileIndex].XML;
}


function UpdateBandXMLListStatus()
{
	for (i = 0; i < iXmlFileCount; i++)
	{
		UpdateBandXmlStatus(i);
	}
}


//Use an XML file's ready state to update its status
function UpdateBandXmlStatus(iIndex)
{
	if (oBandXmlStatusDiv)
	{
		var oStatus = document.getElementById("NavColumn_BandXmlStatus_" + iIndex);
		var O = BandXml[iIndex];
//alert("UpdateBandXmlStatus(" + iIndex + ", " + iState + ")\nO.XML null: " + (null == O.XML));
		switch (O.XML.readyState)
		{
			case 1 :
				oStatus.style.color = "orange";
				oStatus.title = "Load attempt #" + O.AttemptedDownloads + " in progress";
				break;
			case 2 :
				oStatus.style.color = "orange";
				oStatus.title = "Load attempt #" + O.AttemptedDownloads + " in progress";
				break;
			case 3 :
				oStatus.style.color = "orange";
				oStatus.title = "Load attempt #" + O.AttemptedDownloads + " in progress";
				break;
			case 4 :
				if (!IsXMLValid(O.XML))
				{
					if (O.IsFinished)
					{
						oStatus.style.color = "red";
						oStatus.title = "Failed to load after " + O.AttemptedDownloads + " attempts";
					}
					else
					{
						oStatus.style.color = "yellow";
						oStatus.title = "Load attempt #" + O.AttemptedDownloads + " in progress";
					}
				}
				else
				{
					O.IsFinished = true;
					oStatus.title = O.XML.documentElement.childNodes.length + " bands, loaded on try #" + BandXml[iIndex].AttemptedDownloads + ".";
					oStatus.style.color = "lightgreen";
				}
				break;
			default :
				oStatus.style.color = "red";
				break;
		}
	}
}


function BuildXMLObject(strFile, bDownload, bLoadAsync)
{
	var O = new Object;
	O.IsFinished = false;
	O.FileName = strFile;
	O.ForceResync = bDownload;
	O.LoadAsync = bLoadAsync;
	O.AttemptedDownloads = 0;
	O.XML = new ActiveXObject("Msxml2.DOMDocument.3.0");

	return O;
}


function FindNextUnloadedFile(iStartFileIndex)
{
	//walk through files, starting with the start file, to the end of the file list
	//If we find a file that hasn't been loaded, return its index.
	for (i = iStartFileIndex; i < iXmlFileCount; i++)
	{
		if (!BandXml[i].IsFinished)
		{
			return i;
		}
	}

	//walk through files, starting at the beginning of the list, to the current file (inclusive)
	//If we find a file that hasn't been loaded, return its index.
	for (i = 0; i <= iStartFileIndex; i++)
	{
		if (!BandXml[i].IsFinished)
		{
			return i;
		}
	}
	
	//if no unloaded file was found, return -1 (success);
	return -1;
}


//Find the next file that hasn't loaded yet, attempt to download it, and queue this function to run again in 5 seconds
function LoadNextFile(iStartIndex)
{
	var iFile = FindNextUnloadedFile(iStartIndex);
//alert("LoadNextFile(" + iStartIndex + ")\nNextUnloadedFile: " + iFile);
	if (iFile > -1)
	{
		O = BandXml[iFile];

		//If this isn't the first time attempting to download this file, disable caching on future download attempts.		
		if (O.AttemptedDownloads > 1)
		{
			O.ForceResync = true;
		}
		
		//If we haven't attempted to download this file MaxXmlLoadAttempts times yet, attempt to load it
		//If we have, mark the file Finished and move on.
		if (O.AttemptedDownloads < MaxXmlLoadAttempts)
		{
			O.XML = LoadXML(O.XML, O.FileName, O.ForceResync, O.LoadAsync, O.AttemptedDownloads);
			O.AttemptedDownloads++; 
		}
		else
		{
			O.IsFinished = true;
		}
	}
	
	//If all files are finished (FindNextUnloadedFile returns -1), stop loading files, 
	//call the Status updater one more time, and kill the updater interval.
	//Otherwise keep loading files, adding an extra delay for each download attempt on the file.
	iFile = FindNextUnloadedFile(++iFile);
	if (iFile == -1)
	{
		UpdateBandXMLListStatus();
		clearInterval(StatusUpdateInterval);
	}	
	else
	{
		var iDelay = LoadDelayIncrement * BandXml[iFile].AttemptedDownloads;
		setTimeout("LoadNextFile(" + iFile + ");", iDelay);
	}
}


//Test the specified file to see if it is loaded. If it is, do nothing.
//If it isn't, start loading the file and return true so the outer loop knows to exit.
function LoadNextFileInner(iFileIndex)
{
	var O = BandXml[iFileIndex];
	var bFileFinished = true;
	
//alert("[LoadNextFileInner] iFileIndex = " + iFileIndex + "\nO.AttemptedDownloads: " + O.AttemptedDownloads + "\nO.IsFinished: " + O.IsFinished);
	
	//If the file hasn't loaded successfully, set Loading flag to true and try loading the file.
	if (!O.IsFinished)
	{
		bFileFinished = false

		//force resync on download attempts after the first
		if (O.AttemptedDownloads > 1)
		{
			O.ForceResync = true;
		}
		
		//If we haven't attempted to download this file MaxXmlLoadAttempts times yet, attempt to load it
		//If we have, mark the file Finished and move on.
		if (O.AttemptedDownloads < MaxXmlLoadAttempts)
		{
			O.XML = LoadXML(O.XML, O.FileName, O.ForceResync, O.LoadAsync, O.AttemptedDownloads);
			O.AttemptedDownloads++; 
		}
		else
		{
			bFileFinished = true;
			O.IsFinished = true;
		}
	}
	
	//Tell the outer function whether this file was already loaded or not.
	return bFileFinished;
}


//Loads an XML file into a javascript object for use in a page. Checks to see if the downloaded file
//is valid XML with at least one content node, and if not, attempts to download again.
function LoadXML ( oXML, strFile, bDownload, bLoadAsync, iPreviousAttempts )
{
	var xmlDoc;
	var strFileFull = strXMLFileRoot + strFile;
	var regex = /\d+/;
	var arrParts = regex.exec(strFile);
	var iFileNumber = -1;
	if (arrParts && arrParts.length > 0)
	{
		iFileNumber = arrParts[0];
	}
	
	//Assume this is the first time trying to load unless otherwise specified
	if (!iPreviousAttempts) 
	{
		iPreviousAttempts = 0;
	}
//alert("LoadXML(" + oXML + "\nstrFile: " + strFile + "\nbDownload: " + bDownload + "\nbLoadAsync: " + bLoadAsync + 
//	"\niPreviousAttempts: " + iPreviousAttempts +	"\n\nXML = null: " + (null == oXML));
 	
	//Set xmlDoc to oXML if it exists. If not, create a new object for it.
	if (!oXML)
	{
		xmlDoc = new ActiveXObject("Msxml2.DOMDocument.3.0");
	}
	else
	{
		xmlDoc = oXML;
	}

	//Attempt to load
	xmlDoc.setProperty( "SelectionLanguage", "XPath" );
	xmlDoc.setProperty( "ForcedResync", bDownload );
	xmlDoc.async = bLoadAsync;
	xmlDoc.load( strFileFull );

	return xmlDoc;
}