var Ajax = {
	abortRequest: function(XHR) {
		if (XHR != "") {
			delete XHR.onreadystatechange;
			XHR.abort();
			Ajax.hideLoadingIndicator(XHR);
			delete XHR;
		}
	},
	asyncRequest: function(
		method,
		page,
		data,
		callback,
		indicateLoading,
		returnXHR) {
		var XHR;
		if (window.XMLHttpRequest) XHR = new XMLHttpRequest();
		else if (window.ActiveXObject) XHR = new ActiveXObject(
			"Microsoft.XMLHTTP");
		XHR
			.open(
				method,
				page + ((method == "GET") ? ((page.indexOf("?") == -1) ? "?" : "&") + Ajax.constants
					.get() : ""),
				true);
		XHR.onreadystatechange = function() {
			switch (XHR.readyState) {
				case 1:
					if (indicateLoading) {
						Ajax.callStack.push(XHR);
						window.setTimeout(Ajax.showLoadingIndicator, 500);
					}
					break;
				case 4:
					if (indicateLoading) Ajax.hideLoadingIndicator(XHR);
					try {
						if (XHR.status == 200) {
							if (callback) {
								var requestResponse = Ajax
									.createRequestResponse(
										XHR.responseText,
										callback.args);
								if (!callback.hasOwnProperty("scope")) callback
									.success(requestResponse);
								else callback.success.apply(
									callback.scope,
									[requestResponse]);
							}
						}
						else {
							var error = (XHR.status == 500) ? XHR.responseText : XHR.statusText;
							if (callback && callback.hasOwnProperty("failure")) callback
								.failure(error);
							else alert(error);
						}
					}
					catch (e) {
						XHR.abort();
					}
					delete callback;
					delete XHR.onreadystatechange;
					delete XHR;
					break;
			}
		};
		if (method == "POST") {
			var constants = Ajax.constants.get();
			XHR.setRequestHeader(
				"content-type",
				"application/x-www-form-urlencoded");
			XHR
				.send(constants + ((constants != "" && data != "") ? "&" : "") + data);
		}
		else XHR.send(null);
		if (returnXHR) return XHR;
	},
	createRequestResponse: function(response, args) {
		var Obj = {};
		Obj.response = response;
		if (args) Obj.args = args;
		return Obj;
	},
	callStack: [],
	constants: {
		collection: [],
		get: function() {
			var constants = [];
			if (Innecto.agent.IE) constants.push("timestamp=" + Math.random());
			
			function serialize(el) {
				return el.join("=");
			}
			
			if (Ajax.constants.collection.length > 0) constants = constants
				.concat(Ajax.constants.collection.map(serialize));
			return constants.join("&");
		},
		set: function() {
			var constants = [];
			var args = Ajax.constants.set.arguments;
			var len = args.length, i = 0;
			while (i < len) {
				constants.push( [args[i], encodeURIComponent(args[i + 1])]);
				i += 2;
			}
			Ajax.constants.collection = constants;
		}
	},
	hideLoadingIndicator: function(XHR) {
		var i = Ajax.callStack.indexOf(XHR);
		if (i != -1) Ajax.callStack.splice(i, 1);
		if (Ajax.callStack.length == 0) Innecto.style.set(Innecto
			.$("loadingindicator"), "display", "none");
		delete XHR;
	},
	parseRequestResponse: function(str) {
		this.data = JSON.parse(str);
	},
	serialize: function() {
		var args = arguments;
		var data = [];
		var len = args.length, i = 0;
		while (i < len) {
			data.push(args[i] + "=" + encodeURIComponent(args[i + 1]));
			i += 2;
		}
		return data.join("&");
	},
	showLoadingIndicator: function() {
		if (Ajax.callStack.length > 0) Innecto.style.set(Innecto
			.$("loadingindicator"), "display", "block");
	},
	syncRequest: function(method, page, data) {
		var XHR;
		if (window.XMLHttpRequest) XHR = new XMLHttpRequest();
		else if (window.ActiveXObject) XHR = new ActiveXObject(
			"Microsoft.XMLHTTP");
		XHR
			.open(
				method,
				page + ((method == "GET") ? ((page.indexOf("?") == -1) ? "?" : "&") + Ajax.constants
					.get() : ""),
				false);
		if (method == "POST") {
			var constants = Ajax.constants.get();
			XHR.setRequestHeader(
				"content-type",
				"application/x-www-form-urlencoded");
			XHR
				.send(constants + ((constants != "" && data != "") ? "&" : "") + data);
		}
		else XHR.send(null);
		var response = XHR.responseText;
		if (XHR.status == 200) return response;
		delete XHR;
	}
};

Ajax.parseRequestResponse.prototype.datasets = function(dataset) {
	var rows = this.data[dataset];
	if (typeof rows == "undefined") rows = [this.data];
	return {
		rows: function(row) {
			if (row >= 0) {
				var items = rows[row];
				return {
					items: function(item) {
						if (item >= 0) return items.findProperty(item);
						else if (typeof item == "string") return items[item];
						return items;
					}
				};
			}
			rows.count = rows.length;
			return rows;
		}
	};
};
