
Xaja = {}
Xaja.lastRetryDate = new Date()
// Xaja.mode can be "longlived" or "shortlived"
Xaja.mode = "longlived"

Xaja.lang = new Array
Xaja.lang["error_invalid_message"]="Error in server connection. Invalid message returned."
Xaja.lang["xaja_exception"]="An error occured while processing your request. Please try to refresh your page."
Xaja.lang["xaja_disconnect"]="Warning! Unable to reach the server. It is likely that you have been disconnected from the network. Alternatively, it is possible that the server is down. The page will try to reload automatically. Any work done on this page will be lost."


window._last_message_id = -1;

// DEBUG: every 2s, check the state of the longlived connection
// For some strange reason, we have seen cases were the onComplete event was not launched.
// This timer ensures it is launched.
Xaja.intervalCheck = function() {
	if (!xajaInitComplete || Xaja.isExiting==true) {
		Xaja.log(Xaja.msg('interval_check'));
		return;
	}

	if (!window.XMLHttpRequest  || isBrowserIE() || isBrowserOpera())
	{
		if (isBrowserIE()) {
			if ((Xaja.oldReadyState == "loading" || Xaja.oldReadyState == "interactive") && Xaja.xajaIeIfr.readyState != "loading" && Xaja.xajaIeIfr.readyState != "interactive") {
				Xaja.warn(new Date()+" - WARNING! The ready state of the long-lived iFrame is "+Xaja.xajaIeIfr.readyState+". It is not 'interactive', which means the incoming connection is lost. This should never happen!");
				xajaResponse('');
				// alert("WARNING! The ready state of the long-lived iFrame is "+Xaja.xajaIeIfr.readyState+". It is not 'interactive', which means the incoming connection is lost. This should never happen!");
			}
			else if (Xaja.oldReadyState == "complete" && Xaja.xajaIeIfr.readyState == "complete") {
				Xaja.warn("IFrame content"+Xaja.xajaIeIfr.innerHTML);
				Xaja.warn(new Date()+" - IntervalCheck IE: the connection was closed and not cleanly restarted after 2 seconds: restarting the connection.");
				xajaDisconnectMessage();
			}
			else if (Xaja.mode == "longlived" && Xaja.oldReadyState == "loading" && Xaja.xajaIeIfr.readyState == "loading") {
				// If 2 seconds ago, the state was LOADING and if this is still the same state, then
				// something is wrong with the must be wrong. As soon as the headers are sent, we are sending some data.
				// If none has been sent, then something must be buffering data in the way (antivirus?)
				//alert("Impossible to establish long-lived connection. An anti-virus may be in the way!")
				Xaja.warn(new Date()+" - IntervalCheck IE: No data received, switching to short lived connection.");
				Xaja.askToSwitchToShortLivedConnections()
				Xaja.mode = "shortlived"
			}
			//alert("Mouf!"+Xaja.xajaIeIfr.readyState);
			Xaja.oldReadyState = Xaja.xajaIeIfr.readyState
			
		} else {
			// TODO
		}
	}
	else
	{
		if (Xaja.oldReadyState == 3 && Xaja.xajaAjaxRequest.transport.readyState >= 4) {
			Xaja.warn(new Date()+" - WARNING! The ready state of the long-lived XHR is "+Xaja.xajaAjaxRequest.transport.readyState+", which means it finished loading. This means that the incoming connection is lost. This should never happen!");
			xajaResponse('');
			// alert("WARNING! The ready state of the long-lived XHR is "+Xaja.xajaAjaxRequest.transport.readyState+", which means it finished loading. This means that the incoming connection is lost. This should never happen!");		
		} else if (Xaja.mode == "longlived" && Xaja.oldReadyState == 1 && Xaja.xajaAjaxRequest.transport.readyState == 1) {
			// If 2 seconds ago, the state was OPENED and if this is still the same state, then
			// something is wrong with the must be wrong. As soon as the headers are sent, we are sending some data.
			// If none has been sent, then something must be buffering data in the way (antivirus?)
			//alert("Impossible to establish long-lived connection. An anti-virus may be in the way!")
			Xaja.warn(new Date()+" - IntervalCheck FireFox: No data received, switching to short lived connection.");
			Xaja.askToSwitchToShortLivedConnections()
			Xaja.mode = "shortlived"
		}
		Xaja.oldReadyState = Xaja.xajaAjaxRequest.transport.readyState
			
	}


}


/**
 * This function passes the "message" var, that will be send to the Xaja Controller "xajacontroller_id" to the PHP server.
 */
function perform_request(message) {
	//alert(message.toJSONString());
	var params = "xajacontrollerid="+window._xajacontroller_id+"&message="+encodeURIComponent(Object.toJSON(message));
	
	var myAjax = new Ajax.Request(
			window._revert_url_path+"/xajarequest.php", 
			{
				method: 'post', 
				parameters: params
			});
}

/**
 * This function is called by the body onunload event handler and will send a message to the server informing it that
 * the user is leaving the page.
 */
function xaja_onunload() {
	Xaja.isExiting = true;

	var params = "xajacontrollerid="+window._xajacontroller_id+"&message="+encodeURIComponent(Object.toJSON({message_type:'xajaonunload', widget_id:'_tcm_global'}));
	
	var myAjax = new Ajax.Request(
			window._revert_url_path+"/xajarequest.php", 
			{
				method: 'get', 
				parameters: params,
				asynchronous: false
			});
}

/**
 * This function is called by the user to perform an action on the controller.
 */
Xaja.sendMessageToController = function(type, id, message) {
	var params = "xajacontrollerid="+window._xajacontroller_id+"&message="+encodeURIComponent(Object.toJSON({message_type:'xajaeventforcontroller', widget_id:'_tcm_global', type:type, id:id, message:message}));
	
	var myAjax = new Ajax.Request(
			window._revert_url_path+"/xajarequest.php", 
			{
				method: 'get', 
				parameters: params,
				asynchronous: false
			});
}

/**
 * This function is called by the framework, if no response has been received from the long-lived connection,
 * in order to switch the framework in short-lived connections.
 */
Xaja.askToSwitchToShortLivedConnections = function(type, id, message) {
	var params = "xajacontrollerid="+window._xajacontroller_id+"&message="+encodeURIComponent(Object.toJSON({message_type:'xajaconnectionproblem', widget_id:'_tcm_global'}));
	
	var myAjax = new Ajax.Request(
			window._revert_url_path+"/xajarequest.php", 
			{
				method: 'get', 
				parameters: params,
				asynchronous: false
			});
}

/**
 * Returns the domain to use, depending on the subdomain parameter and whether
 * the URL is a proper DNS name or rather an IP adress or localhost
 */
Xaja.getDomain = function() {
	if (Xaja.use_sub_domains == "no" || Xaja.use_sub_domains == "inside")
		return document.domain;

	if (document.domain == 'localhost')
		return 'localhost'
	
	var ipfilter = /^([1-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])(\.([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])){3}$/;

	if (ipfilter.test(document.domain)) {
		return document.domain
	}
	
	if (Xaja.use_sub_domains == "yes")
		return "xaja"+window._xajacontroller_id+"."+Xaja.main_domain
}

/**
 * Registers functions in this frame to be called the first time from the IE Iframe.
 */
function xajaRegisterIeIFrame(myFrame) {
//alert('registered');
	myFrame.execute = xajaIeExecute.bind(window);
	myFrame.reset = xajaIeReset.bind(window);
}

/**
 * Function called when the IE Iframe resets.
 */
function xajaIeReset() {
//alert('reseting');
	xajaResponse('');
}

/**
 * Adds data to the list of Javascript strings to be executed.
 */
function xajaIeExecute(str) {
	window.eval(str);
}

/**
 * Initializes Xaja.
 * use_sub_domains can be "yes" (use subdomains)
 * "no" (do not use subdomains) or "inside": we are in a subdomain iframe.
 */
function onLoadXajaPage(xajacontroller_id, revert_url_path, use_sub_domains, main_domain) {
	Xaja.log(new Date()+" - onLoadXajaPage: start.");
	
	Xaja.use_sub_domains = use_sub_domains;
	Xaja.main_domain = main_domain;
	window._xajacontroller_id = xajacontroller_id;
	window._revert_url_path = revert_url_path;
	
	if (typeof(Ext) != "undefined") {
		Ext.BLANK_IMAGE_URL = revert_url_path+'/js/ext-2.2/resources/images/default/s.gif';
	}
	
	// If we are in IE, we can't use the longlived AJAX. We fall back to the IFrame trick.
	if (!window.XMLHttpRequest  || isBrowserIE() || isBrowserOpera())
	{
		// Special IE only IFrame trick!
		// Thanks to http://ajaxian.com/archives/event-driven-io-javascript-hack-in-the-new-gtalk-in-gmail and to Michael Carter from Orbited for the tricks!
		if (isBrowserIE()) {
		
			// we were served from child.example.com but have already set document.domain
			//var currentDomain = window.location.hostname;
			var currentDomain = main_domain;
			//var dataStreamUrl = window._revert_url_path+'/longlived.php?method=ieiframe&id='+xajacontroller_id;
			
			var dataStreamUrl = "//"+Xaja.getDomain()+window._revert_url_path+'/longlived.php?method=ieiframe&id='+xajacontroller_id+'&mode='+Xaja.mode;
			var transferDoc
			transferDoc = new ActiveXObject("htmlfile"); // !?!
			// make sure it's really scriptable
			transferDoc.open();
			transferDoc.write("<html>");
			transferDoc.write("<script>document.domain='"+currentDomain+"';</script>");
			transferDoc.write("</html>");
			transferDoc.parentWindow.xajaRegisterIeIFrame = xajaRegisterIeIFrame;
			transferDoc.close();
			
			// set the iframe up to call the server for data
			Xaja.ifrDiv = transferDoc.createElement("div");
			transferDoc.appendChild(Xaja.ifrDiv);
			// start communicating
			Xaja.xajaIeIfr = transferDoc.createElement("iframe");
			Xaja.xajaIeIfr.src=dataStreamUrl;
			Xaja.ifrDiv.appendChild(Xaja.xajaIeIfr);
			transferDoc.parentWindow.xajaRegisterIeIFrame = xajaRegisterIeIFrame;
			
			// Stores the transferDoc somewhere to be sure that it won't be garbage collected.
			Xaja.transferDoc = transferDoc;
			setInterval(Xaja.intervalCheck, 2000)
		} else {
			var url = '<iframe src="'+document.location.protocol+"//"+Xaja.getDomain()+window._revert_url_path+'/longlived.php?method=iframe&id='+xajacontroller_id+'&mode='+Xaja.mode+'" id="xaja_iframe" onload="xajaResponse(\'\')" width="0" height="0" frameborder="0" />';
			new Insertion.Bottom(document.body, url)
			setInterval(Xaja.intervalCheck, 2000)
		}
	}
	else
	{
		if (Xaja.use_sub_domains != "yes") {
			currentXajaStreamAdvance = 0;
			var method;
			if (isBrowserSafari()) {
				method="ajaxsafari";
			} else {
				method="ajax";
			}

			var url = window._revert_url_path+"/longlived.php?method="+method+"&id="+xajacontroller_id+'&mode='+Xaja.mode;
			Xaja.xajaAjaxRequest = new Ajax.Request( url, { method: 'get', onSuccess: xajaResponse, onFailure: xajaLongLivedBroken, onInteractive: xajaInteractive, onException: xajaException });
			setInterval(Xaja.intervalCheck, 2000)
		} else {
		
			var url = '<iframe src="'+document.location.protocol+"//"+Xaja.getDomain()+window._revert_url_path+'/subdomainiframe.php?id='+xajacontroller_id+'" id="xaja_subdomain_iframe" width="0" height="0" frameborder="0" />';
			new Insertion.Bottom(document.body, url);
		}
	}
	
	// Let's add the debugging info at the end of the page.
	new Insertion.Bottom(document.body, 
				'<div id="xaja_debug"></div>');	

	// Now, let's execute all registered onLoad functions (that might be used by widgets for instance).
	for( var i=0; i < window.xajaInitFuncs.length; i++ ){
		if( typeof window.xajaInitFuncs[i] == "function" ) {
			window.xajaInitFuncs[i]();
		} else {
			alert("oups");
		}
	}

	// Once done, the Xaja init is complete. Let's mark that with a variable.
	xajaInitComplete = true
}

// function to hold all init functions
xajaInitFuncs = new Array();
xajaOnLoadTagFuncs = new Array();
xajaOnLoadTagState = new Array();
xajaInitComplete = false;

function registerInitFunction(my_func) {
	window.xajaInitFuncs[window.xajaInitFuncs.length] = my_func;
}

function executeWhenLoaded(tagId, my_func) {
	if (window.xajaOnLoadTagFuncs[tagId] == null)
		window.xajaOnLoadTagFuncs[tagId] = new Array();
		
	window.xajaOnLoadTagFuncs[tagId][window.xajaOnLoadTagFuncs[tagId].length] = my_func;
}

/**
 * Executes my_func immediately, unless the script whose identifier is tagId is not loaded.
 * If so, wait for the script to load and execute after
 */
function delayUntilLoad(tagId, my_func) {
	if (xajaOnLoadTagState[tagId] == 1)
	{
		// No wait (Firefox)
		my_func();
	}
	else
	{
		// Wait (IE)
		executeWhenLoaded(tagId, my_func);
	}
}

function xajaOnTagLoaded(tagId) {
	// Now, let's execute all registered onLoad functions (that might be used by widgets for instance).*
	
	xajaOnLoadTagState[tagId] = 1;
	if (window.xajaOnLoadTagFuncs[tagId] != null) {
		for( var i=0; i < window.xajaOnLoadTagFuncs[tagId].length; i++ ){
			if( typeof window.xajaOnLoadTagFuncs[tagId][i] == "function" ) {
				window.xajaOnLoadTagFuncs[tagId][i]();
			} else {
				alert("oups that's not a function");
			}
		}
	}
}


/**
 * Returns true if IE is running. Useful to distinguish between IE7 (that does not support onInteractive method)
 * and Firefox and Safari (that supports it).
 */
function isBrowserIE() {
	//Detect IE5.5+
	version=0
	if (navigator.appVersion.indexOf("MSIE")!=-1) {
		return true;
		//temp=navigator.appVersion.split("MSIE")
		//version=parseFloat(temp[1])
	}
	return false;
}

/**
 * Returns true if Safari is running. Useful to distinguish between Firefox ansd Safari,
 * since Safari requires 256 bytes to be sent before handling Javascript.
 */
function isBrowserSafari() {
	//Detect Safari
	version=0
	if (navigator.vendor && navigator.vendor.indexOf("Apple")!=-1) {
		return true;
	}
	return false;
}

/**
 * Returns true if Opera is running.
 * It is unclear whether Opera supports XHR or not (test shows it doesn't).
 */
function isBrowserOpera() {
	//Detect Opera
	if (navigator.userAgent.indexOf("Opera") > -1) {
		return true;
	}
	return false;
}


function xajaInteractive(originalRequest)
{
	// Always: currentXajaStreamAdvance is always pointing at the beginning of the length of the message.
	
	if (originalRequest.responseText == undefined)
		return;
	
	var response_length = originalRequest.responseText.length;
	
	while (currentXajaStreamAdvance != response_length) {
		// full_ajax_message contains the length and the message to be executed
		var full_ajax_message = originalRequest.responseText.substr(currentXajaStreamAdvance);
		var length_delimitor_pos = full_ajax_message.indexOf("\n");
		// We haven't received yet the full length!
		if (length_delimitor_pos == -1)
			return;
		
		var message_length = parseInt(full_ajax_message.substr(0, length_delimitor_pos));
		
		if (isNaN(message_length)) {
			alert(Xaja.msg("error_invalid_message"))
			Xaja.warn("Error in server connection. Invalid message returned:\n"+full_ajax_message);
			return
		}
		
		// TODO: verify that the length of \n is 1 on all systems!
		// If the message is not fully arrived, let's return.
		if (response_length < currentXajaStreamAdvance + length_delimitor_pos + 1 + message_length) {
			return
		}
		
		// Otherwise, that's cool, let's go for the message.
		var message = full_ajax_message.substr(length_delimitor_pos + 1, message_length);

		// When receiving data, it seems that Firefox does not convert the data to UTF-8
		// (maybe because it is partly loaded only)
		// The line below is a hack to convert received data to UTF-8.
		message = decodeURIComponent(escape(message));
		
		if (Xaja.use_sub_domains != "inside")	
			window.eval(message);
		else
			window.parent.eval(message);
			
		currentXajaStreamAdvance += length_delimitor_pos + 1 + message_length;
	}
}


// Exception handling is executed when leaving the page!
function xajaException(conn,ex) {
	Xaja.warn(new Date()+" - Exception:"+ex)
	if (!Xaja.isExiting)
		alert(Xaja.msg("xaja_exception"))
}

/**
 * If an Ajax connection is broken
 */
function xajaLongLivedBroken(originalRequest) {
	Xaja.warn(new Date()+" - xajaLongLivedBroken");
	// do as if the connection had been purposely closed and try again to connect.
	window._xaja_isConnectionClosed = true;
	xajaResponse('');
}

function xajaDisconnectMessage() {
	Xaja.warn(new Date()+" - Warning! Unable to reach the server. It is likely that you have been disconnected from the network. Alternatively, it is possible that the server is down. The page will try to reload automatically. Any work done on this page will be lost.")
	alert(Xaja.msg("xaja_disconnect"))
	window.location.href = unescape(window.location.pathname)
}

/**
 * Resume the connection when it gets closed
 */
function xajaResponse(originalRequest)
{
	Xaja.log(new Date()+" - Entering Xaja response")
	//$('xaja_debug').innerHTML += 'Long-lived request to server closed! Restoring...';
	var messageIdRestore;
	if (Xaja.use_sub_domains == "inside") {
		messageIdRestore = window.parent._last_message_id + 1;
	} else {
		messageIdRestore = window._last_message_id + 1;
	}

	// The Xaja.isExiting is used instead (more powerful since it allows for reconnects on network failure).
	if (Xaja.isExiting != true) {
		Xaja.warn(new Date()+" - Xaja is not exiting, let's reconnect")

		// Let's track if we have made a retry in the last 10 seconds.
		// If we have been doing a retry, let's display an error message (unless we are in short-lived mode).
		var now = new Date()
		if (Xaja.mode == "longlived" && now.getTime() - Xaja.lastRetryDate.getTime() < 10000) {
			Xaja.warn(new Date()+" - xajaResponse: Warning! Connection must be broken. Last retry was on "+Xaja.lastRetryDate.getTime()+" and current retry is on "+now.getTime());
			xajaDisconnectMessage();
		}

		Xaja.lastRetryDate = now;
	
		// If we are in IE, we can't use the longlived AJAX. We fall back to the IFrame trick.
		if (!window.XMLHttpRequest || isBrowserIE() || isBrowserOpera())
		{
			// Special IE only IFrame trick!
			// Thanks to http://ajaxian.com/archives/event-driven-io-javascript-hack-in-the-new-gtalk-in-gmail and to Michael Carter from Orbited for the tricks!
			if (isBrowserIE()) {
				//xajaIeIfr.src = window._revert_url_path+"/longlived.php?method=iframe&restore="+messageIdRestore+"&id="+window._xajacontroller_id;
				//xajaIeIfr.src = window._revert_url_path+"/../../temp/response.php?method=iframe&restore="+messageIdRestore+"&id="+window._xajacontroller_id;
				/*Xaja.ifrDiv.removeChild(Xaja.xajaIeIfr);
				Xaja.xajaIeIfr = Xaja.transferDoc.createElement("iframe");
				Xaja.xajaIeIfr.src=window._revert_url_path+"/longlived.php?method=ieiframe&restore="+messageIdRestore+"&id="+window._xajacontroller_id;
				Xaja.ifrDiv.appendChild(Xaja.xajaIeIfr);*/





				/*var transferDoc = null;
				Xaja.transferDoc = null;
				Xaja.ifrDiv = null;
				Xaja.xajaIeIfr = null;
				CollectGarbage();
*/
				Xaja.warn(new Date()+" - Starting IE reconnect")

				
/*				var currentDomain = Xaja.main_domain;
	*/			
				var dataStreamUrl = "//"+Xaja.getDomain()+window._revert_url_path+'/longlived.php?method=ieiframe&restore='+messageIdRestore+'&id='+window._xajacontroller_id+'&mode='+Xaja.mode;
/*				transferDoc = new ActiveXObject("htmlfile"); // !?!
				// make sure it's really scriptable
				transferDoc.open();
				transferDoc.write("<html>");
				transferDoc.write("<script>document.domain='"+currentDomain+"';</script>");
				transferDoc.write("</html>");
				transferDoc.close();
				transferDoc.parentWindow.xajaRegisterIeIFrame = xajaRegisterIeIFrame;
				
				// set the iframe up to call the server for data
				Xaja.ifrDiv = transferDoc.createElement("div");
				transferDoc.appendChild(Xaja.ifrDiv);
*/				// start communicating

				// Added:
				var transferDoc = Xaja.transferDoc;
				Xaja.ifrDiv.removeChild(Xaja.xajaIeIfr);

				Xaja.xajaIeIfr = transferDoc.createElement("iframe");
				Xaja.xajaIeIfr.src=dataStreamUrl;
				Xaja.ifrDiv.appendChild(Xaja.xajaIeIfr);
				transferDoc.parentWindow.xajaRegisterIeIFrame = xajaRegisterIeIFrame;
				
				// Stores the transferDoc somewhere to be sure that it won't be garbage collected.
				Xaja.transferDoc = transferDoc;
				
				Xaja.warn(new Date()+" - Ending IE reconnect")
				
			} else {
				$('xaja_iframe').setAttribute('src', "//"+Xaja.getDomain()+window._revert_url_path+"/longlived.php?method=iframe&restore="+messageIdRestore+"&id="+window._xajacontroller_id+'&mode='+Xaja.mode);
			}	
		}
		else
		{
			// First, let's end the request handling (if needed).
			xajaInteractive(originalRequest);
			currentXajaStreamAdvance = 0;
			var method;
			if (isBrowserSafari()) {
				method="ajaxsafari";
			} else {
				method="ajax";
			}
			var url = window._revert_url_path+"/longlived.php?method="+method+"&restore="+messageIdRestore+"&id="+window._xajacontroller_id+'&mode='+Xaja.mode;
			Xaja.xajaAjaxRequest = new Ajax.Request( url, { method: 'get', onInteractive: xajaInteractive, onComplete: xajaResponse });
		}
	}
}


/*
* Load a css file
*/
function cssLoading(fileName) {
	Ext.onReady(function () {
		//var url = '<link rel="stylesheet" href="' + fileName + '" type="text/css"></link>';
		var lnk = document.createElement('link');
	    lnk.setAttribute('type', "text/css" );
	    lnk.setAttribute('rel', "stylesheet" );
	    lnk.setAttribute('href', fileName );
	    document.getElementsByTagName("head").item(0).appendChild(lnk);
		//new Insertion.Bottom(document.getElementsByTagName("head")[0], url);
	});
}

/**
 * simple sprintf function, supporting %s and %d, courtesy of
 * http://24ways.org/2007/javascript-internationalisation
 */
Xaja.sprintf = function(s) {
	var bits = s.split('%');
	var out = bits[0];
	var re = /^([ds])(.*)$/;
	for (var i=1; i<bits.length; i++) {
		p = re.exec(bits[i]);
		if (!p || arguments[i]==null) continue;
		if (p[1] == 'd') {
			out += parseInt(arguments[i], 10);
		} else if (p[1] == 's') {
			out += arguments[i];
		}
		out += p[2];
	}
	return out;
}

/**
 * Used to internationalize messages
 */
Xaja.msg = function(index) {
	var msg = Xaja.lang[index]
	if (msg == null) {
		return "???"+index+"???"
	}
	arguments[0] = msg
	return Xaja.sprintf.apply(this, arguments)
}

/**
 * Used to send logs to the JS console
 */
Xaja.log = function(msg) {
	console.log(msg)
}

/**
 * Used to send logs to the JS console and potentially back to the server
 */
Xaja.warn = function(msg) {
	console.log(msg)
	
	var params = "xajacontrollerid="+window._xajacontroller_id+"&message="+encodeURIComponent(msg);
	
	var myAjax = new Ajax.Request(
			window._revert_url_path+"/clientlog.php", 
			{
				method: 'post', 
				parameters: params
			});
}
