AJAX = new function() {
	this.xmlBase = '/ajax';
	this.handlerURL = this.xmlBase+'/ajax_core.cfm';
	this.popupURL = this.xmlBase+'/ajax_popup.cfm';
	this.debugMode = true;
	this.queue = [ ];
	this.reportWindow = null;
	
	this.create = function(owner, handler) {
		return OO.create(AJAX.Request, owner, handler);
	}
	
	this.XMLHTTP = (window.XMLHttpRequest) ? function() { return new XMLHttpRequest(); } : function() { return new ActiveXObject("Microsoft.XMLHTTP"); }
	
	this.prepareSend = function(owner, action, params, timeout, alertFn) {
		if (!this.busy) { this.busy = true; return true; }
		this.queue.push({ sendType: 'ajax', owner: owner, action: action, params: params, timeout: timeout, alertFn: alertFn });
		return false;
	}
	
	this.preparePreload = function(owner, file, type, message, params) {
		if (!this.busy) { this.busy = true; return true; }
		this.queue.push({ sendType: 'preload', owner: owner, file: file, params: params, message: message, type: type });
		return false;
	}
	
	this.releaseSend = function() {
		var next = this.queue.shift();
		this.busy = false;
		if (next) switch (next.sendType) {
			case 'ajax'		:	next.owner.send(next.action, next.params, next.timeout, next.alertFn); break;
			case 'preload'	:	next.owner.preload(next.file, next.type, next.message, next.params); break;
		}
	}
}

AJAX.Request = function() {
	this.inherit(OO.Broadcaster);
	this.inherit(OO.Timer);
}
AJAX.Request.prototype = { 
	initSelf: function(owner, handler) {
		this.addListener(owner);
		this.handler = handler;
	},
		
	setHandler: function(handler) {
		this.handler = handler;
	},
	
	preload: function(file, type, message, params) {
		var oThis = this;
		
		if (!AJAX.preparePreload(this, file, type, message, params)) return;

		this.ajaxRequest = AJAX.XMLHTTP();
		this.ajaxRequest.onreadystatechange = function() { if (oThis.ajaxRequest.readyState == 4) { oThis.handlePreload(type, message, params, file);	} }
		this.ajaxRequest.open("POST", file, true);
		this.ajaxRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
		this.ajaxRequest.send('');
	},
	
	send: function(action, params, timeout, alertFn, errorMess) {
		var oThis = this;
		var divider = '';
		var key;
		var paramsStr = '';
		
		if (!AJAX.prepareSend(this, action, params, timeout, alertFn)) return;
		
		params = params || { };
		params = { handler: this.handler, action: action, data: encodeURIComponent(JSON.stringify(params)), SBSID: window.$SBSID };
		
		for (key in params) {
			paramsStr += divider + key + '=' + escape(params[key]);
			divider = '&';
		}
		
		this.ajaxRequest = AJAX.XMLHTTP();
		this.ajaxRequest.onreadystatechange = function() { if (oThis.ajaxRequest.readyState == 4) { oThis.handleResponse();	} }
		this.ajaxRequest.open("POST", AJAX.handlerURL, true);
		this.ajaxRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
		this.ajaxRequest.setRequestHeader('Charset', 'UTF-8');
		this.ajaxRequest.send(paramsStr);
		if (timeout) this.setTimeout('AJAXTimeout', timeout, this.handleTimeout, action);
		
		AJAX.currentRequest = { url: AJAX.handlerURL, handler: this.handler, action: action, data: params.data, alertFn: alertFn, errorMess: errorMess };
		
	},
	
	handlePreload: function(type, message, params, file) {
		CM.delayedMessage(10, type, message, params);
		AJAX.releaseSend();
	},
	
	handleTimeout: function(action) {
		this.sendMessage('ajaxTimeout', action);
		AJAX.releaseSend();
	},
	
	handleResponse: function() {
		var mess, data, ok, ajax = false;
		
		if (!window.AJAX) return;
		this.clearTimeout('AJAXTimeout');
		
		if (this.ajaxRequest.status == 200) {
			try {
				if (window.AJAX && window.AJAX.currentRequest && window.AJAX.currentRequest.alertFn) window.AJAX.currentRequest.alertFn();
				data = this.ajaxRequest.responseText.replace(/^[\n\r]+/, '');
				eval('data = '+data);
				ok = true;
			} catch(e) {
				//printfire('AJAX: Error decoding data');
			}
			if (ok) { 
				if (data.data.messagequeue)
					data.data.messagequeue.forEach(function(item) { try { this.sendMessage('ajaxResponse', item.type, item.message, item.data); } catch (e) { ERROR.handle(e); } }, this);
				else
					try { this.sendMessage('ajaxResponse', item.type, data.message, data.data); } catch (e) { ERROR.handle(e); }
			}
		} else {
			//printfire('Status Error: '+this.ajaxRequest.status);
		}
		if (!ok) { 
			if (mess = window.AJAX.currentRequest.errorMess) {
				this.sendMessage('ajaxResponse', mess.type, mess.message, mess.params);
			} else {
				this.sendMessage('ajaxFail'); 
				this.failureReport(); 
			}
		}
		
		if (ajax = window.AJAX) ajax.releaseSend();
	},
	
	defaultErrorHandler: function(error) {
		var errorText = error.getAttribute('errorText');
		alert('AJAX ERROR: \n' + errorText);
	},

	failureReport: function() {
		var d = new Date();
		var oThis = this;
		var newWindow = false;
		var request = this.ajaxRequest;
		var current = AJAX.currentRequest;
		
		if (AJAX.errorHandler) AJAX.errorHandler(current.url, request.responseText, current.data, current.action, current.handler);
	}
}

AJAX.asyncRequest = function(handler, action, params)

{
	var ajaxRequest = AJAX.XMLHTTP();
	var key, divider = '', paramsStr = '';
	
	AJAX._asyncRequests = AJAX._asyncRequests||[];
	params = params || { };
	params = { handler: handler, action: action, data: encodeURIComponent(JSON.stringify(params)), SBSID: window.$SBSID };
	for (key in params) { paramsStr += divider + key + '=' + escape(params[key]); divider = '&'; }
	
	AJAX._asyncRequests.push({ request: ajaxRequest, url: AJAX.handlerURL, handler: handler, action: action, data: params.data });
	ajaxRequest.onreadystatechange = AJAX.asyncOnReadyStateChange;
	ajaxRequest.open("POST", AJAX.handlerURL, true);
	ajaxRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
	ajaxRequest.setRequestHeader('Charset', 'UTF-8');
	ajaxRequest.send(paramsStr);

}

AJAX.asyncOnReadyStateChange = function() {
	var ok = false;
	var current, i = 0;
	
	if (this.readyState!=4) return;
	if (this.status != 200) return;
	
	for (i in AJAX._asyncRequests) {
		current = AJAX._asyncRequests[i];
		if (current.request == this) {
			AJAX._asyncRequests.splice(i, 1);
			break;
		}
	}
	try { 
		eval('data = '+this.responseText.replace(/^[\n\r]+/, '')); ok = true;
	} catch(e) {
		//printfire('AJAX: Error decoding data');
	}
	if (ok) { 
		if(data.data.messagequeue)
			data.data.messagequeue.forEach(function(item) { try { $CM(item.type, item.message, item.data); } catch (e) { ERROR.handle(e); } }, this);
		else
			try { $CM(item.type, data.message, data.data); } catch (e) { ERROR.handle(e); }
	}
	if (!ok) {
		if (AJAX.errorHandler) AJAX.errorHandler(current.url, this.responseText, current.data, current.action, current.handler);
	}
}

AJAX.defaultErrorHandler = AJAX.errorHandler = function(url, responseText, data, action, handler, showWin) {
	showWin = showWin||confirm('AJAX SERVER ERROR:\nDo you want to display the error report?');
	if (showWin) {								
		var newWindow = true;
		AJAX.reportWindow = window.open(AJAX.popupURL+'?ajaxHandler='+escape(url),'_blank');
		
		AJAX.reportWindow.displayErrorText = responseText;
		AJAX.reportWindow.ajaxURL = url;
		AJAX.reportWindow.ajaxData = data;
		AJAX.reportWindow.ajaxAction = action;
		AJAX.reportWindow.ajaxHandler = handler;
		AJAX.reportWindow.SBSID = window.$SBSID;
		AJAX.reportWindow.focus(); 
		
		AJAX.reportWindow.displayError();
	}
}

AJAX.Fetch = function(o, fn, url, data, params, type) {
	var request = AJAX.XMLHTTP();
	var paramsStr = '';
	
	type = (type == 'post') ? 'POST':'GET';
	params = params || { };
	
	for (key in params) {
		paramsStr += divider + key + '=' + escape(params[key]);
		divider = '&';
	}
	
	responseData = { o: o, fn: fn, data: data }
	request.onreadystatechange = U.FN(request, AJAX.FetchResponse, responseData);
	request.open(type, url, true);
	request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
	request.send('');
}

AJAX.FetchResponse = function(responseData) {
	if (responseData && (this.readyState==4)) responseData.fn.call(responseData.o, responseData.data);
}