

(typeof fw=="undefined"?fw={}:"");
(typeof fw.ajax=="undefined"?fw.ajax={}:"");

fw.ajax.Server=function () {

	this.id = "";
	this.transactions={};
	this.transactionCounter=0;
	this.requestUrl = '';
	this.responseOutputMethod = alert;

	/* If history is required the iframe should not be deleted between transaction. */
	this.iframe = null;

	/**
	 *	
	 *	
	 */
	this.createTransactionId = function () {
		return "id"+(this.transactionCounter++);
	}


	/**
	 *	
	 *	
	 */
	this.setRequestUrl = function (url) {
		this.requestUrl=url;
	}


	/**
	 *	@param dataProperties
	 *		formRef						Reference to <form> object
	 *		url							url or action
	 *		serverValues				querystring formatted data
	 *		clientArgs					js object with keys and values
	 *		formScope					string defining the form item names to include in the request
	 *	@param requestProperties
	 *		method						HTTP request method (GET or POST)
	 *		isFileUpload				boolean, upload file(s) or not
	 *		contentType					expected response content-type
	 *		timeout						how long in seconds to wait to a request before firing a timeout event
	 *		requireHistory				boolean, request should be in the history array or not
	 *		async						boolean, asyncronous request or not
	 *		forceAjaxMethod				defines the ajaxmethod to use (xmlhttp, iframe or script)
	 *	@param callbacks
	 *		success						function reference to call incase of success
	 *		failure						function reference to call incase of failure
	 *		timeout						function reference to call incase of timeout
	 *		abort						function reference to call incase of user abortion
	 *	
	 */
	//this.request = function (method, url, callbacks, serverValues, formRef, isFileUpload, clientArgs, requireHistory, async, contentType, forceAjaxMethod) {
	//this.request = function (dataProperties, callbacks, requireHistory, async, forceAjaxMethod) {
	this.request = function (dataProperties, requestProperties, callbacks) {
		var transId=this.createTransactionId();
		var transaction=new fw.ajax.Transaction(this, transId);
		this.transactions[transId] = transaction;

		dataProperties.formRef=this.p(null, dataProperties.formRef);
		dataProperties.url=this.pnu(this.requestUrl, dataProperties.url);
		dataProperties.serverValues=this.pnu("", dataProperties.serverValues);
		dataProperties.clientArgs=this.pnu({}, dataProperties.clientArgs);
		dataProperties.formScope=this.pnu("", dataProperties.formScope);

		requestProperties.method=this.pnu("POST", requestProperties.method);
		requestProperties.isFileUpload=this.pnu(false, requestProperties.isFileUpload);
		requestProperties.contentType=this.pnu("", requestProperties.contentType);
		requestProperties.timeout=this.pnu(120, requestProperties.timeout);
		requestProperties.requireHistory=this.pnu(false, requestProperties.requireHistory);
		requestProperties.async=this.pnu(true, requestProperties.async);

		transaction.response.setOutputMethod(this.responseOutputMethod);
		transaction.response.setCallbacks(this.p(null, callbacks));
		transaction.response.clientArgs=dataProperties.clientArgs;

		if (requestProperties.requireHistory) {
			this.createIframe();
		}

		transaction.doRequest(dataProperties, requestProperties);

		return transId;
	}


	this.getXMLHttpRequest=function () {


		if (typeof XMLHttpRequest != "undefined") {
			return new XMLHttpRequest();

		} else if (typeof ActiveXObject != "undefined") { //IE < 7.0 = use ActiveX

			var versions = ["MSXML2.XmlHttp.6.0", "MSXML2.XMLHttp.5.0", "MSXML2.XMLHttp.4.0", "MSXML2.XMLHttp.3.0", "MSXML2.XMLHttp", "Microsoft.XMLHttp"];
			if (!fw.ajax.Server.XMLHttpVersion) {
				for (var i=0; i < versions.length; i++) {
					try {
						var obj = new ActiveXObject(versions[i]);
						fw.ajax.Server.XMLHttpVersion = versions[i];
						return obj;
					} catch (e) {
					}
				}
			}

			if (fw.ajax.Server.XMLHttpVersion) {
				return new ActiveXObject(fw.ajax.Server.XMLHttpVersion);
			} else {
				throw new Error("Could not create XML HTTP Request.");
			}
		} else {
			throw new Error("Your browser doesn't support an XML HTTP Request.");
		}
	}

	this.createIframe=function () {

		if (this.iframe == null) {

			var bodyEl = document.getElementsByTagName("BODY")[0];

			this.iframe = {};
			this.iframe.container=document.createElement("DIV");
			this.iframe.container.style.display="block";
			bodyEl.appendChild(this.iframe.container);
			this.iframe.container.innerHTML = '<iframe id="iframeServer'+this.id+'" name="iframeServer'+this.id+'" style="width:100%;height:500px;display:block;"></iframe>';
		}
	}


	this.abort=function (transId, reason) {
		this.transactions[transId].abort(reason);
	}

	fw.ajax.Server.registerServer(this);
}

fw.ajax.Server.inherits(fw.PwObject);

fw.ajax.Server.ajaxMethods = {
	XMLHTTP: "XML",
	SCRIPT_TAG: "SCR_TAG",
	HIDDEN_IFRAME: "IFRAME"
};
fw.ajax.Server.instances = {};
fw.ajax.Server.counter = 0;
fw.ajax.Server.registerServer = function (instance) {
	var id = "id"+(fw.ajax.Server.counter++);
	instance.id = id;
	fw.ajax.Server.instances[id] = instance;
};



fw.ajax.Request=function() {

	this.method = "POST";
	this.async = true;
	this.requireHistory = false;
}

fw.ajax.Request.inherits(fw.PwObject);


fw.ajax.Response=function() {

	this.clientArgs = {};
	this.outputMethod = alert;

	this.setOutputMethod=function (outputMethod) {
		this.outputMethod = this.pnu(alert,outputMethod);
	}

	this.setCallbacks=function (callbacks) {
		callbacks = this.p({}, callbacks);
		//alert(callbacks.success);
		this.success = this.p(this.success, callbacks.success);
		this.failure = this.p(this.failure, callbacks.failure);
		this.timeout = this.p(this.timeout, callbacks.timeout);
		this.abort = this.p(this.abort, callbacks.abort);
	}

	this.success=function (transId, data, httpRequest) {
		this.outputMethod("The transaction [" + transId + "] succeeded."
			//+"<br/>\n httpRequest.status: "+httpRequest.status
			//+"<br/>\n httpRequest.statusText: "+httpRequest.statusText
			//+"<br/>\n httpRequest.getAllResponseHeaders(): "+httpRequest.getAllResponseHeaders()
			+"<br/>\n this.clientArgs: "+function (o) {
					var str='';
					for (var p in o) {
						str+=p+":"+o[p]+"<br>\n";
					}
					return str;
				}(this.clientArgs)
			+"<br/>\n data: "+data);
	}
	this.failure=function (transId, httpStatus, httpRequest) {
		this.outputMethod("The transaction [" + transId + "] failed."
			+"<br/>\n HTTP Status: "+httpStatus
			+"<br/>\n httpRequest.status: "+httpRequest.status
			+"<br/>\n httpRequest.statusText: "+httpRequest.statusText
			+"<br/>\n httpRequest.getAllResponseHeaders(): "+httpRequest.getAllResponseHeaders());
	}
	this.timeout=function (transId, requestStarted) {
		var timeTaken=new Date().dateDiff(requestStarted);
		this.outputMethod("Time out after " + Date.getReadableTime(timeTaken, "en"));
	}
	this.abort=function (transId, reason) {
		this.outputMethod("The transaction [" + transId + "] was aborted by the user. Reason given: " + reason);
	}
}

fw.ajax.Response.inherits(fw.PwObject);


fw.ajax.Transaction=function(server, transId) {

	this.server=server;
	this.id=transId;
	this.request=new fw.ajax.Request();
	this.response=new fw.ajax.Response();
	this.XMLHttpRequest = null;

	this.ajaxClasses = {};
	this.ajaxClasses[fw.ajax.Server.ajaxMethods.XMLHTTP] = {create: "createXMLHttp", destroy: null};
	this.ajaxClasses[fw.ajax.Server.ajaxMethods.SCRIPT_TAG]	= {create: "createScriptTag", destroy: "destroyResource"};
	this.ajaxClasses[fw.ajax.Server.ajaxMethods.HIDDEN_IFRAME] = {create: "createHiddenIframe", destroy: "destroyResource"};
	
	this.ajaxMethod = fw.ajax.Server.ajaxMethods.XMLHTTP;

	this.resourceContainer=null;
	this.timer=0;
	this.patience=120 * 1000;
	this.patienceTimer=0;
	this.creationTimeStamp=new Date();


	//this.doRequest = function(method, url, serverValues, formRef, isFileUpload, requireHistory, async, contentType, forceAjaxMethod) {
	//this.doRequest = function(dataProperties, requireHistory, async, forceAjaxMethod) {
	this.doRequest = function(dataProperties, requestProperties) {

		var formRef = dataProperties.formRef;
		var url = dataProperties.url;
		var serverValues = dataProperties.serverValues;
		var formScope = dataProperties.formScope;

		var method = requestProperties.method;
		var isFileUpload = requestProperties.isFileUpload;
		var contentType = requestProperties.contentType;
		var timeout = requestProperties.timeout;
		var requireHistory = requestProperties.requireHistory;
		var async = requestProperties.async;
		var forceAjaxMethod = requestProperties.forceAjaxMethod;

		this.request.method = method;
		this.request.async = async;
		this.request.requireHistory = requireHistory;

		this.patience = 1000 * timeout;

		this.ajaxMethod = this.decideAjaxMethod(method, serverValues, isFileUpload, requireHistory, async, contentType, forceAjaxMethod);
		//alert("this.doRequest"
		//	+"\n method: "+method
		//	+"\n ajaxMethod: "+this.ajaxMethod
		//	+"\n url: "+url
		//	+"\n isFileUpload: "+isFileUpload
		//	+"\n async: "+async);

		//server.responseOutputMethod("this.ajaxMethod: "+this.ajaxMethod);

		//if (confirm("this.ajaxMethod: "+this.ajaxMethod)) {

			switch (this.ajaxMethod) {
				case fw.ajax.Server.ajaxMethods.SCRIPT_TAG:
					this.createScriptTag(url, serverValues, formRef, formScope, contentType);
					break;
				case fw.ajax.Server.ajaxMethods.HIDDEN_IFRAME:
					this.createHiddenIframe(method, url, serverValues, formRef, formScope, isFileUpload, requireHistory, contentType);
					break;
				default:
					this.createXMLHttp(method, url, serverValues, formRef, formScope, isFileUpload, async, contentType);
					break;
			}
		//}

	}

	this.decideAjaxMethod = function(method, serverValues, isFileUpload, requireHistory, async, contentType, forceAjaxMethod){

		forceAjaxMethod = this.pnu(fw.ajax.Server.ajaxMethods.XMLHTTP, forceAjaxMethod);

		function supportsXMLHttpRequest() {
			return (typeof ActiveXObject != "undefined" || typeof XMLHttpRequest != "undefined");
		}

		//alert(""
		//	+"\n async: "+async
		//	+"\n typeof ActiveXObject != \"undefined\": "+(typeof ActiveXObject != "undefined")
		//	+"\n typeof XMLHttpRequest != \"undefined\": "+(typeof XMLHttpRequest != "undefined")
		//	+"\n isFileUpload: "+isFileUpload
		//	+"\n requireHistory: "+requireHistory);

		if ((!async || supportsXMLHttpRequest()) && !isFileUpload && !requireHistory && (forceAjaxMethod == fw.ajax.Server.ajaxMethods.XMLHTTP)
				|| (method.toUpperCase() == "POST" && (forceAjaxMethod == fw.ajax.Server.ajaxMethods.SCRIPT_TAG))) {
			return fw.ajax.Server.ajaxMethods.XMLHTTP;
		} else if (method.toUpperCase() == "GET" && serverValues.length <= 1000 && !requireHistory && (forceAjaxMethod != fw.ajax.Server.ajaxMethods.HIDDEN_IFRAME)) {
			return fw.ajax.Server.ajaxMethods.SCRIPT_TAG;
		} else {
			return fw.ajax.Server.ajaxMethods.HIDDEN_IFRAME;
		}
	}

	this.addParametersToUrl=function (url, params) {
		if (url.indexOf("?") > -1) {
			url += "&" + params;
		} else {
			url += "?" + params;
		}
		return url;
	}

	/**
	 *	
	 *	
	 */
	this.getGetUrl=function (url, serverValues, formRef, formScope) {
		serverValues = fw.FormFactory.encodeURIParameterString(serverValues, formScope);
		this.addParametersToUrl(url, serverValues);
		if (formRef != null) {
			url += "&" + fw.FormFactory.getFormValues(formRef, formScope, formScope);
		}
		return url;
	}

	/**
	 *	
	 *	
	 */
	this.getPostData=function (url, serverValues, formRef, formScope) {
		serverValues = fw.FormFactory.encodeURIParameterString(serverValues, formScope);
		postData = serverValues;
		if (formRef != null) {
			postData += "&" + fw.FormFactory.getFormValues(formRef, formScope);
		}
		if (postData.charAt(0) == '&') {
			postData = postData.slice(1);
		}
		return postData;
	}

	/**
	 *	
	 *	
	 */
	this.createXMLHttp = function (method, url, serverValues, formRef, formScope, isFileUpload, async, contentType) {

		var response = this.response;
		var httpRequest = this.server.getXMLHttpRequest();

		var extraParams = "";
		extraParams += "Headers.Content-Type=" + this.p("text/html", contentType);
		extraParams += "&Fw.Ajax.Type=XMLHttpRequest";
		extraParams += "&Fw.Ajax.ServerId=" + server.id;
		extraParams += "&Fw.Ajax.TransactionId=" + this.id;

		this.XMLHttpRequest = httpRequest;
		var postData = null;

		url = this.addParametersToUrl(url, extraParams);

		if (method.toUpperCase() == "GET") {
			url = this.getGetUrl(url, serverValues, formRef, formScope);

		} else if (method.toUpperCase() == "POST") {
			postData = this.getPostData(url, serverValues, formRef, formScope);
		}
		//alert(""
		//	+"\n method: "+method
		//	+"\n url: "+url
		//	+"\n async: "+async
		//	+"\n postData: "+postData);

		httpRequest.open(method, url, async);
		//httpRequest.setRequestHeader("Content-Type", this.pnu("text/plain", contentType));
		httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
		this.patienceTimer=setTimeout('fw.ajax.Server.instances.' +server.id + '.transactions.' + this.id + '.endPatience();', this.patience);

		if (async) {
			httpRequest.onreadystatechange=function() {
				if (httpRequest.readyState == 4) {
					server.transactions[transId].handleResponse(httpRequest);
				}
			}
			httpRequest.send(postData);

		} else {
			this.handleResponse(httpRequest.send(postData));
		}
	}

	/**
	 *	
	 *	
	 */
	this.createScriptTag = function (url, serverValues, formRef, formScope, formScope) {

		var contentType = "text/javascript";
		var extraParams = "";
		extraParams += "Headers.Content-Type=" + contentType;
		extraParams += "&Fw.Ajax.Type=ScriptTag";
		extraParams += "&Fw.Ajax.ServerId=" + server.id;
		extraParams += "&Fw.Ajax.TransactionId=" + this.id;

		this.resourceContainer=document.createElement("SCRIPT");
		this.resourceContainer.type=contentType;
		document.getElementsByTagName("HEAD")[0].appendChild(this.resourceContainer);
		this.creationTimeStamp=new Date();
		this.patienceTimer=setTimeout('fw.ajax.Server.instances.' +server.id + '.transactions.' + this.id + '.endPatience();', this.patience);

		url = this.addParametersToUrl(url, extraParams);
		url = this.getGetUrl(url, serverValues, formRef, formScope);
		this.resourceContainer.src=url + "";
		this.response.outputMethod('<a href="' + url + '">' + url + '</a>');
	}

	/**
	 *	
	 *	
	 */
	this.createHiddenIframe = function (method, url, serverValues, formRef, formScope, isFileUpload, requireHistory) {

		var contentType = "text/html";
		var extraParams = "";
		extraParams += "Headers.Content-Type=" + contentType;
		extraParams += "&Fw.Ajax.Type=HiddenIframe";
		extraParams += "&Fw.Ajax.ServerId=" + server.id;
		extraParams += "&Fw.Ajax.TransactionId=" + this.id;

		var bodyEl = document.getElementsByTagName("BODY")[0];
		this.resourceContainer=document.createElement("DIV");
		this.resourceContainer.style.display="block";
		bodyEl.appendChild(this.resourceContainer);

		var frameName = 'iframeServer'+server.id;
		if (!requireHistory) {

			this.resourceContainer.innerHTML = '<iframe id="iframe'+this.id+'" name="iframe'+this.id+'" style="width:100%;height:500px;display:block;"></iframe>';
			frameName = 'iframe'+this.id;
		}

		this.creationTimeStamp=new Date();
		this.patienceTimer=setTimeout('fw.ajax.Server.instances.' +server.id + '.transactions.' + this.id + '.endPatience();', this.patience);

		// FIXME: File Upload Support!

		if (method.toUpperCase() == "GET") {
			var queryString = url.split("?")[1];
			if (typeof queryString != "undefined") {
				serverValues = extraParams + "&" + queryString + "&" + serverValues;
				if (formRef != null) {
					serverValues += "&" + fw.FormFactory.getFormValues(formRef, formScope);
				}
				url = url.split("?")[0];
			}

		} else if (method.toUpperCase() == "POST") {
			url = this.addParametersToUrl(url, extraParams);
			serverValues = this.getPostData(url, serverValues, formRef, formScope);
		}
		//alert(""
		//	+"\n method: "+method
		//	+"\n url: "+url
		//	+"\n serverValues: "+serverValues);

		if (isFileUpload && formRef != null) {

			var frm = fw.FormFactory.copyForm(formRef, bodyEl, url, method, frameName, "multipart/form-data", document, formScope);
			frm.style.display="none";
			frm.submit();
			this.resourceContainer.appendChild(frm);
			// container, url, parameterString, method, target, contentType, doc
			//fw.FormFactory.submitUrl(bodyEl, url, serverValues, method, frameName, "multipart/form-data", document);
		} else {
			fw.FormFactory.submitUrl(bodyEl, url, serverValues, method, frameName, "", document, formScope);
		}

	}

	this.abort=function (reason) {

		this.killTimer();
		if (this.ajaxMethod == fw.ajax.Server.ajaxMethods.XMLHTTP) {
			this.XMLHttpRequest.abort(reason);
			response.abort(this.id, reason);
		} else {
			this.destroyResource();
		}
	}

	this.handleResponse=function (data) {
		this.killTimer();
		switch (this.ajaxMethod) {

			case fw.ajax.Server.ajaxMethods.HIDDEN_IFRAME:
				this.response.success(this.id, data);
				if (!this.request.requireHistory) {
					this.cancelIframeResource();
					this.destroyResource();
				}
				break;

			case fw.ajax.Server.ajaxMethods.SCRIPT_TAG:
				this.response.success(this.id, data);
				this.destroyResource();
				break;

			default:
				var httpRequest = this.XMLHttpRequest;
				try{
					if(typeof httpRequest.status != "undefined" && httpRequest.status != 0){
						httpStatus=httpRequest.status;
					}else{
						httpStatus=13030;
					}
				}catch(e){
					httpStatus=13030;
				}
				if(httpStatus >= 200 && httpStatus < 300){
					this.response.success(this.id, httpRequest.responseText, httpRequest);
				}else{
					this.response.failure(this.id, httpStatus, httpRequest);
				}
				break;
		}
	}


	// Fix bug in firefox. It doesn't finish the loading.
	this.cancelIframeResource = function () {

		//alert(this.resourceContainer.innerHTML);
		var iframe=frames['iframe'+this.id];
		//iframe.stop();
		//window.stop();
		//iframe.src="about:blank";
		//iframe=document.getElementById('iframe'+this.id);
		//var parentNode=iframe.parentNode;
		//parentNode.removeChild(iframe);
	}

	/**
	 *	
	 *	
	 */
	this.destroyResource = function () {
		this.killTimer();
		var parentNode=this.resourceContainer.parentNode;
		parentNode.removeChild(this.resourceContainer);
	}

	/**
	 *	
	 *	
	 */
	this.endPatience=function () {

		this.destroyResource();
		this.response.timeout(this.id, this.creationTimeStamp);
	}

	/**
	 *	
	 *	
	 */
	this.killTimer=function(){
		if (this.timer) {
			clearTimeout(this.timer);
			this.timer=0;
		}
		if (this.patienceTimer) {
			clearTimeout(this.patienceTimer);
			this.patienceTimer=0;
		}
	}

}

fw.ajax.Transaction.inherits(fw.PwObject);


