/**
 * $Id: adtl.js,v 1.23 2008-01-22 14:58:05 coke Exp $
 * @author Simon Koster <simon@drecomm.nl>
 **/

/************************************
 * Ajax Data Tranfer Library [ADTL] *
 ************************************/


/**
 * Constructor
 **/
function ADTL(p_iDeltaT){
	if (p_iDeltaT) {
		this.m_bTiming = true;
		this.m_iDeltaT = p_iDeltaT;
		this.m_iLastCallTime = 0;
		this.m_iEventAddedTime = 0;
	}
	else {
		this.m_bTiming = false;
	}
	var xmlhttp;
	/*@cc_on
	@if (@_jscript_version >= 5)
		try {
			xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
		} catch (e) {
			try {
				xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
			}
			catch (E) {
				xmlhttp = false;
			}
		}
	@else
	xmlhttp = null;
	@end @*/
	if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
		try {
			xmlhttp = new XMLHttpRequest();
			//xmlhttp.overrideMimeType("text/xml");
		}
		catch (e) {
			xmlhttp = null;
		}
	}
	this.m_oXmlHttp = xmlhttp;
	this.m_aListeners = new Array();
	this.m_sUrl = null;
	this.m_bDebug = false;
	this.m_bAborted = false;
}
/**
 * Error handler method
 *
 * Possible error codes:
 * CODE           MESSAGE
 * -------------------------------------------------------
 * noxml          ERROR: returned XML document is invalid.
 * 404            ERROR: url does not exist
 * error          Unknown error in sending request
 * busy           ERROR: already requesting data
 * unknowntarget  ERROR: Undefined URL
 * noxmlhttp      ERROR: XMLHTTP object is undefined
 **/
ADTL.prototype.errorHandler = function(p_sCode, p_sMsg){
	alert(p_sCode + ": " +  p_sMsg);
}

/**
 * Enable debug output method
 **/
ADTL.prototype.debug = function(p_bEnable){
	if(p_bEnable != null && p_bEnable == false){
		this.m_bDebug = false;
	}else{
		this.m_bDebug = true;
	}
}


/**
 * Add data listener
 **/
ADTL.prototype.addDataListener = function(p_sIdentifier, p_funListener){
	if(this.m_aListeners[p_sIdentifier] != null){
		this.m_aListeners[p_sIdentifier][this.m_aListeners[p_sIdentifier].length] = p_funListener;
	}else{
		this.m_aListeners[p_sIdentifier] = new Array();
		this.m_aListeners[p_sIdentifier][0] = p_funListener;
	}
}


/**
 * Transform XML Data Array to Array
 **/
ADTL.prototype.readOutXmlDataArray = function(p_oXmlData){
	var l_aReturnArray = new Array();
	for(var i=0;i<p_oXmlData.childNodes.length;i++){
		// Get data element
		var l_oDataElementNode = p_oXmlData.childNodes.item(i);
		if(l_oDataElementNode.nodeType == 1){
			// Get key of new array element
			var l_sKey = l_oDataElementNode.getAttribute("key");
			// Get content of new array element
			var l_bNestedArray = false;
			for(var j=0;j<l_oDataElementNode.childNodes.length;j++){
				if(l_oDataElementNode.childNodes.item(j).nodeName == "dataarray"){
					l_bNestedArray = true;
					var l_aValue = this.readOutXmlDataArray(l_oDataElementNode.childNodes.item(j));
				}
			}
			if(l_bNestedArray){
				l_aReturnArray[l_sKey] = l_aValue;
			}else{
				l_sStr = l_oDataElementNode.firstChild.nodeValue;
				l_aReturnArray[l_sKey] = unescapeHTML(l_sStr);
			}
		}
	}
	return l_aReturnArray;
}
/**
 * Fetch data from server
 **/
ADTL.prototype.fetchData = function(p_aVars, p_sUrl, p_aRef){

	var	l_bMakeCall = false;
	if (this.m_bTiming) {
		var	l_oDate = new Date();
		var	l_iTime = l_oDate.getTime();
		if (l_iTime - this.m_iLastCallTime >= this.m_iDeltaT) {
			if (this.m_iLastCallTime) {
				this.abort();
			}
			var xmlhttp;
			/*@cc_on
			@if (@_jscript_version >= 5)
				try {
					xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
				} catch (e) {
					try {
						xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
					}
					catch (E) {
						xmlhttp = false;
					}
				}
			@else
			xmlhttp = null;
			@end @*/
			if (!xmlhttp && typeof XMLHttpRequest != 'undefined') {
				try {
					xmlhttp = new XMLHttpRequest();
					//xmlhttp.overrideMimeType("text/xml");
				}
				catch (e) {
					xmlhttp = null;
				}
			}
			delete this.m_oXmlHttp;
			this.m_oXmlHttp = xmlhttp;
			l_bMakeCall = true;
			this.m_iLastCallTime = l_iTime;
		}
	}
	else {
		l_bMakeCall = true;
	}
	if (!l_bMakeCall) return false;
	// Define target URL
	var l_sTargetUrl = new String();
	if(p_sUrl != null){
		l_sTargetUrl = p_sUrl;
	}else{
		l_sTargetUrl = this.m_sUrl;
	}
	// Prepare and encode the vars that need to be posted with the HTTP request
	var l_sUrlEncodedVars = this.encodeDataToUrl(p_aVars);

	// Check if XmlHttp exists
	if(this.m_oXmlHttp != null){
		// Only Proceed when target URL is defined
		if(l_sTargetUrl != null){
			// Only proceed when XMLHTTP is not in the process of loading a document already
			if(this.m_oXmlHttp.readyState == 0 || this.m_oXmlHttp.readyState == 4 || this.m_oXmlHttp.readyState == null){
				try {
					this.m_oXmlHttp.open("POST", l_sTargetUrl, true);
					this.m_oXmlHttp.setRequestHeader("Content-Type","application/x-www-form-urlencoded; charset=UTF-8");
					/**
					 * This sets the onreadystatechange function. NOTE: Within this method it is not
					 * possible to use the THIS reference to get the ADTL instance.
					 **/
					var l_oSelf = this;
					l_oSelf.p_aRef = p_aRef;
					this.m_oXmlHttp.onreadystatechange = function() {
						// readState 4 means the document has been fully loaded
						if (l_oSelf.m_oXmlHttp.readyState == 4) {
							if (!l_oSelf.m_bAborted) {
								if(l_oSelf.m_oXmlHttp.status != 404) {
									var l_oXmlDoc = l_oSelf.m_oXmlHttp.responseXML;
									var l_oDataTranferNode;
									if(l_oXmlDoc != null){
										// Get datatransfer node
										for(var i=0;i<l_oXmlDoc.childNodes.length;i++){
											if(l_oXmlDoc.childNodes.item(i).nodeName == "datatransfer"){
												var l_oDataTranferNode = l_oXmlDoc.childNodes.item(i);
												// Loop through dataarrays
												for(var j=0;j<l_oDataTranferNode.childNodes.length;j++){
													if(l_oDataTranferNode.childNodes.item(j).nodeName == "dataarray" &&
													   l_oDataTranferNode.childNodes.item(j).getAttribute("identifier") != null){
														var l_sIdentifier = l_oDataTranferNode.childNodes.item(j).getAttribute("identifier");
														var l_oDataArrayNode = l_oDataTranferNode.childNodes.item(j);
														var l_aDataArray = l_oSelf.readOutXmlDataArray(l_oDataArrayNode);
														if(!l_oSelf.loginNeeded(l_sIdentifier, l_aDataArray)) {
															if(l_oSelf.m_aListeners[l_sIdentifier] != null){
																for(var l_iKey in l_oSelf.m_aListeners[l_sIdentifier]){
																	l_oSelf.m_aListeners[l_sIdentifier][l_iKey](l_aDataArray, l_oSelf.p_aRef);
																}
															}
														}
													}
												}
											}
										}
									}else{
										l_oSelf.errorHandler('noxml','Het ontvangen XML document is ongeldig.');
									}
								}else{
									// Error in loading document
									l_oSelf.errorHandler('404','URL bestaat niet.');
								}
							}
							else {
								l_oSelf.m_bAborted = false;
							}
						}
					}
					this.m_oXmlHttp.send(l_sUrlEncodedVars);
					//_e('abba').innerHTML = l_sUrlEncodedVars;
					//window.open(l_sTargetUrl+'?'+l_sUrlEncodedVars);
				}
				catch(e){
					// Error in loading document
					if(e.message == undefined){
						this.errorHandler('error', e);
					}else{
						this.errorHandler('error', e.message);
					}
				}
			}else{
				// XMLHTTP object is already loading in XML document
				this.errorHandler('busy', 'Er wordt nog gewacht op een antwoord van de server...');
			}
		}else{
			// No url provided
			this.errorHandler('unknowntarget', 'Ongeldige locatie.');
		}
	}else{
		// XMLHTTP object is undefined
		this.errorHandler('noxmlhttp', 'XMLHTTP object is niet gedefinieerd.');
	}
	return true;
}
/**
 * Encode data from array to be used in URL
 **/
ADTL.prototype.encodeDataToUrl = function(p_aVars){
	var l_sUrlEncodedVars = "";
	for(l_sKey in p_aVars){
		// Escape special characters in key and then unescape the brackets to allow for nested arrays in strings
		var l_sEscapedKey = escape(l_sKey);
		l_sEscapedKey = l_sEscapedKey.replace(/%5B/g, "[");
		l_sEscapedKey = l_sEscapedKey.replace(/%5D/g, "]");

		if(typeof p_aVars[l_sKey] == "object" || typeof p_aVars[l_sKey] == "array"){
			l_sUrlEncodedVars += this.encodeDataToUrlWalkArray(p_aVars[l_sKey], l_sEscapedKey);
		}else
		if (l_sKey!= 'toJSONString')
		{
			var l_sEscapedElement = escape(p_aVars[l_sKey]);
			l_sEscapedElement = l_sEscapedElement.replace(/[+]/g, "%2B");

			l_sUrlEncodedVars += l_sEscapedKey + '=' + l_sEscapedElement + '&';
		}
	}
	return l_sUrlEncodedVars;
}

/**
 * Walk the array recursively to encode the data capture inside
 **/
ADTL.prototype.encodeDataToUrlWalkArray = function(p_aVars, p_sArrayPrefix){
	var l_sUrlEncodedVars = "";
	for(l_sKey in p_aVars){
		// Escape special characters in key and then unescape the brackets to allow for nested arrays in strings
		var l_sEscapedKey = escape(l_sKey);
		l_sEscapedKey = l_sEscapedKey.replace(/%5B/g, "[");
		l_sEscapedKey = l_sEscapedKey.replace(/%5D/g, "]");

		// Check if p_aVars[l_sKey] is an array
		if(typeof p_aVars[l_sKey] == "object" || typeof p_aVars[l_sKey] == "array"){
			l_sUrlEncodedVars += this.encodeDataToUrlWalkArray(p_aVars[l_sKey], p_sArrayPrefix + "[" +l_sEscapedKey + "]");
		}else
		if (l_sKey!= 'toJSONString')
		{
			var l_sEscapedElement = escape(p_aVars[l_sKey]);
			l_sEscapedElement = l_sEscapedElement.replace(/[+]/g, "%2B");

			l_sUrlEncodedVars += p_sArrayPrefix + "[" + l_sEscapedKey + "]" + '=' + l_sEscapedElement + '&';
		}
	}
	return l_sUrlEncodedVars;
}

ADTL.prototype.abort = function() {
	if (this.m_oXmlHttp.readyState == 1) {
		this.m_bAborted = true;
		this.m_oXmlHttp.abort();
	}
}

ADTL.prototype.loginNeeded = function(l_sIdentifier, l_aDataArray) {
	if (l_sIdentifier == 'loginNeeded') {
		alert("Your session has expired. Please login again.");
		return true;
	} else {
		return false;
	}
}
