<!-- ----------------------------------------------------------------------------------
//
//	Author: Dan Carlson
//
//	Description: General routines for marshalling data between client and database 
//				 asynchronously. Data retrieved from the database is stored in an 
//				 XML document, which can be manipulated via the routines in this file. 
//
// Date			Developer			Modification
// --------   	------------------	----------------------------------------------
// 10/01/06		Dan Carlson			Initial version created.
//
//--------------------------------------------------------------------------------- -->

//-------------------------------------------------------------------------------------
// Attach events.
//-------------------------------------------------------------------------------------
window.onload = InitPage;

//-------------------------------------------------------------------------------------
// Module level variables.
//-------------------------------------------------------------------------------------
var moDOMDocument;	//Reference to W3C-DOM XML Document.//var moXSL = new ActiveXObject("Microsoft.XMLDOM");

try {
    var moXSL = this.parent.moMain.moXSL;
}
catch(e) {
}    

//Load sorting module here, so sorting can be non-asynchronous.
//moXSL.async = true;
//moXSL.load("stylesheets/Sort.xsl");
var msOrderBy;var mbDescending;var mbIsSorted = true;var mbError = false;var mbIsBusy = false;

function FilterCriteria(sAttribute, sValue) {

	//Convert to string.
	sValue += "";
    
    this.Attribute = sAttribute;
    this.Value = sValue;
}

//-------------------------------------------------------------------------------------
// Applies the XSL sorting template to the XML document data.
//-------------------------------------------------------------------------------------
function ApplySort() {

	//If XSL document is not completely loaded, get outta here.
	if (moXSL.readyState != 4) {
    	moXSL.onreadystatechange = ApplySort;
	    return;
	}    
	
    moXSL.onreadystatechange = new Function();
	
	//Set the XSL order-by value.
	if (mbDescending) {
		moXSL.selectSingleNode("//@order-by").nodeValue = "-@" + msOrderBy;
	}
	else {
		moXSL.selectSingleNode("//@order-by").nodeValue = "@" + msOrderBy;
	}	

	//Create a new XML document to hold the sorted records.
	var oXMLDocument = new ActiveXObject("Microsoft.XMLDOM");

	//Assign data type to attribute before sorting.
	AssignDataType(msOrderBy);
		
	//Apply the stylesheet to the document.
	moDOMDocument.transformNodeToObject(moXSL, oXMLDocument);
	
	//Assign sorted records to original document.
	moDOMDocument = oXMLDocument;
	mbIsSorted = true;
}

//-------------------------------------------------------------------------------------
// Assigns the data type of the node. Required before sorting.
//-------------------------------------------------------------------------------------
function AssignDataType(sFieldName) {

	var sDataType = GetDataType(sFieldName);
	var oDataList = DataNodeList();
	
	for (i=0; i<oDataList.length; i++) {
		try {
			var oAttribute = oDataList.item(i).getAttributeNode(sFieldName)
			oAttribute.dataType = sDataType;
		}
		catch (oAttribute) {
			//Attributes with NULL values are missing from data.
		}	
	}
}

//-------------------------------------------------------------------------------------
// Returns an array of attributes from the schema.
//-------------------------------------------------------------------------------------
function Attributes(sAttribute) {

	var oAttributeTypes = SchemaNodeList().item(0).childNodes;
	var aAttributes = new Array();		
	
	for(i=0; i<oAttributeTypes.length-1; i++) {
		aAttributes.push(oAttributeTypes.item(i).getAttribute(sAttribute));
	}

	return aAttributes;
}

//-------------------------------------------------------------------------------------
// 	Creates a new node element in the data node list.
//-------------------------------------------------------------------------------------
function CreateRow() {

	var NODE_ELEMENT = 1;
	var sValue;
	
	//Create node element to hold record.
	var oNode = moDOMDocument.createNode(NODE_ELEMENT, "z:row", "#RowsetSchema");

	//Get array of attributes this node will need to have.
	var aryAttributeNames = Attributes("name");

	//Create the attributes.
	for (i=0; i<aryAttributeNames.length; i++) {
		oNode.setAttribute(aryAttributeNames[i], "");
	}
	
	//Append the node to the document.
	DataNode().appendChild(oNode);
	
	//Return reference to node just created.
	return oNode;
}

//-------------------------------------------------------------------------------------
// Gets a reference to the data node. 
//-------------------------------------------------------------------------------------
function DataNode() {

	if (moDOMDocument.childNodes.length == 0) return;
	
	try {
		var oDataNode = moDOMDocument.documentElement.childNodes.item(1);
	}
	catch (e) {
		//Return empty node.
		var oDataNode = moDOMDocument.createNode(NODE_ELEMENT, "z:row", "#RowsetSchema");
	}	
	finally {
		return oDataNode;
	}
}

//-------------------------------------------------------------------------------------
// Gets a reference to the data child nodes. 
//-------------------------------------------------------------------------------------
function DataNodeList() {

	try {
		var oDataNodeList = moDOMDocument.documentElement.childNodes.item(1).childNodes;
	}
	catch (e) {
		//Return empty array, so length property will be equal to zero.
		oDataNodeList = new Array();			
	}	
	finally {
		return oDataNodeList;
	}
}

//-------------------------------------------------------------------------------------
// Indicates if an error occurred while loading data from the database.
//-------------------------------------------------------------------------------------
function Error() {

	return mbError;
}

//-------------------------------------------------------------------------------------
// Filters the data rows by the specified attributes and values.
//-------------------------------------------------------------------------------------
function FilterByCriteria(aFilters) {
    
    var sCriteria = "";

    for (var i=0; i<aFilters.length; i++) {
        sCriteria += "@" + aFilters[i].Attribute + " = '" + aFilters[i].Value + "' && ";
    }
    
    //Trim off excess.
    sCriteria = sCriteria.substr(0, sCriteria.length - 4);
    
	//Get all rows matching the criteria.
	var oNodeList = DataNode().selectNodes("z:row[" + sCriteria + "]");
	
	return oNodeList;
}

//-------------------------------------------------------------------------------------
// Filters the data rows by the specified attribute and value.
//-------------------------------------------------------------------------------------
function FilterRows(sAttribute, sValue) {

	var oNodeList;
	
	//Convert to string.
	sValue += "";
	
	if (sValue.length > 0) {		//Get all rows where the attribute has this value.
		oNodeList = DataNode().selectNodes("z:row[@" + sAttribute + " = '" + sValue + "']");
	}	
	else {
		//Get all rows.
		oNodeList = DataNodeList();
	}	
	
	return oNodeList;
}

//-------------------------------------------------------------------------------------
// Gets the data type of the specified field from the schema. 
//-------------------------------------------------------------------------------------
function GetDataType(sFieldName) {

	var oElementType = SchemaNodeList().item(0);

	var oAttributeType = oElementType.selectSingleNode("s:AttributeType[@name='" + sFieldName + "']");

	try {
		return oAttributeType.childNodes.item(0).getAttribute("dt:type");
	}
	catch(e) {
		return "number";
	}
}

//-------------------------------------------------------------------------------------
// Applies the specified filter/pattern to the data node's context and returns the first 
// matching node. If no filter is specified, the first node is returned.
//-------------------------------------------------------------------------------------
function GetRow(sAttribute, sValue) {

	try {
		if (sAttribute == null) {
			var oNode = DataNode().firstChild;
		}
		else {
			var oNode = DataNode().selectSingleNode("z:row[@" + sAttribute + " = '" + sValue + "']");
		}
	}
	catch(e) {
	}

	return oNode;
}

//-------------------------------------------------------------------------------------
// Gets the string of XML from the document. 
//-------------------------------------------------------------------------------------
function GetXML() {

    if (moDOMDocument == null) {
        return "";
    }
    else {
        return moDOMDocument.xml;
    }        
}

//-------------------------------------------------------------------------------------
// Initializes the page, fires immediately after the browser loads page. 
//-------------------------------------------------------------------------------------
function InitPage() {
	
	if (document.readyState != "complete") {
		//Wait until document is completely loaded.
		setTimeout(InitPage, 500);
	}	
	
	var bRC;
	
	if (frmDB.ReturnData.value == "Y") {
		//Create XML document to hold data retrieved from server.
		moDOMDocument = new ActiveXObject("Microsoft.XMLDOM");		
	    moDOMDocument.async = false;
		
		try {
			if (frmDB.UseCustomCOM.value != "Y") {
 				bRC = moDOMDocument.loadXML(document.all.XML.innerHTML);
   			}
			else {
			    var sXML = this.parent.moMain.GoldRamGadgets.DecompressString(document.all.XML.innerText);
				bRC = moDOMDocument.loadXML(sXML);
            }

			//Document is parsed and loaded.
			//Clear the label used to get the XML document to the client.
			document.all.XML.innerHTML = "";
		}
		catch (e) {
			//Fall through, and let callback function handle the error.
		}	
	}	

	//Display error message, if an error occurred.
	if (ErrorDetail.innerText.length) {
	    if (ErrorDetail.innerText.indexOf("WaitTime=|") != -1) {

	    	//Parse wait time.
	    	var asTemp = ErrorDetail.innerText.split("|"); 
	    	miWaitTime = parseInt(asTemp[1]);
	    	
	    	//Set busy flag.
	    	mbIsBusy = true;
	    }	
	    else {
	        if (frmDB.ErrorMsg.value.length) {
				var sMsg = ErrorDetail.innerText;
				
				//Strip-off SQL Server error number prefix if present.
				if ((sMsg.indexOf("-") == 0) && (sMsg.indexOf(":") == 11)) sMsg = sMsg.substring(13);
				
				//Strip-off SQL Server error number suffix if present.
				if (sMsg.indexOf("(Error=") > 0) sMsg = sMsg.substring(0, sMsg.indexOf("(Error=") - 1);
				
				//Append generic error message to error details.
				var sMsg = frmDB.ErrorMsg.value + "\r\r" + "Details: " + sMsg;
				
				//Display the error in the custom error dialog. If it fails, use the built-in
				//alert dialog provided by the scripting interface.
		        try {
					var oErrorDialog = eval(frmDB.ErrorDialog.value);
					var sLeft = frmDB.ErrorDialogLeft.value;
					var sTop = frmDB.ErrorDialogTop.value;
					
					var sHeight = parseInt((sMsg.length/35) * 20);
					var sWidth = "240";
					//var sWidth = (sMsg.length > 200) ? 260 : 200;
					//var sHeight = (sMsg.length > 200) ? 150 : 100;
					
					oErrorDialog.ShowError(sMsg, sLeft, sTop, sWidth, sHeight);
				}
				catch (e) {
					alert(sMsg);
				}
		    }
		        
   	    	mbIsBusy = false;
		}
		
		//Set error flag.
        mbError = true;
	}
	else {
   	    mbError = false;
	}

    //Execute the specified function in the calling frame.
	if (frmDB.Callback.value.length > 0) eval(frmDB.Callback.value);
}

//-------------------------------------------------------------------------------------
// 	Inserts a new node element in the data node list.
//-------------------------------------------------------------------------------------
function InsertRow(oRefChild) {

	var NODE_ELEMENT = 1;
	var sValue;
	
	//Create node element to hold record.
	var oNode = moDOMDocument.createNode(NODE_ELEMENT, "z:row", "#RowsetSchema");

	//Get array of attributes this node will need to have.
	var aryAttributeNames = Attributes("name");

	//Create the attributes.
	for (i=0; i<aryAttributeNames.length; i++) {
		oNode.setAttribute(aryAttributeNames[i], "");
	}
	
	//Insert the node into the document.
	DataNode().insertBefore(oNode, oRefChild);
	
	//Return reference to node just created.
	return oNode;
}

//-------------------------------------------------------------------------------------
//  Determines if a "busy" condition exists on the database server.
//-------------------------------------------------------------------------------------
function IsBusy() {

	return mbIsBusy;
}

//-------------------------------------------------------------------------------------
// Indicates if sorting the XML document is complete.
//-------------------------------------------------------------------------------------
function IsSorted() {
	
	return mbIsSorted;
}

//-------------------------------------------------------------------------------------
// 	Removes a node element in the data node list.
//-------------------------------------------------------------------------------------
function RemoveRow(sAttribute, sValue) {

	var oNode = GetRow(sAttribute, sValue);

	//Remove the node from the document.
	if (oNode != null) {
		DataNode().removeChild(oNode);
	}	
}

//-------------------------------------------------------------------------------------
// Removes all nodes in the data node list.
//-------------------------------------------------------------------------------------
function RemoveRows() {

    var oNodes = DataNodeList();

    while(oNodes.length) {
   		DataNode().removeChild(oNodes.item(0));
    }
}

//-------------------------------------------------------------------------------------
// Gets a reference to the schema child nodes. 
//-------------------------------------------------------------------------------------
function SchemaNodeList() {

	return moDOMDocument.documentElement.childNodes.item(0).childNodes;
}

//-------------------------------------------------------------------------------------
// Loads the XML Document with the supplied XML string.
//-------------------------------------------------------------------------------------
function SetXMLDocument(sXML) {

	//Create a new XML document.
	var oXMLDocument = new ActiveXObject("Microsoft.XMLDOM");

	oXMLDocument.async = false;
		
	//Load the XML document using the supplied string.
	var bRC = oXMLDocument.loadXML(sXML);
	
	//Assign to original document.
	moDOMDocument = oXMLDocument;
}

//-------------------------------------------------------------------------------------
// Sorts the row data by the specified attribute.
//-------------------------------------------------------------------------------------
function SortData(sOrderBy, bDescending) {

    if (moDOMDocument.xml.length == 0) return;

	//Save sort args in member-level variables.
	msOrderBy = sOrderBy;
	mbDescending = bDescending;
	mbIsSorted = false;
	
	ApplySort();
}

//-------------------------------------------------------------------------------------
//  Returns the wait time, if a "busy" condition exists on the database server.
//-------------------------------------------------------------------------------------
function WaitTime() {

	return miWaitTime;
}