var Ajax = {
	getTransport: function() {
		return Try(
			function() {return new XMLHttpRequest()},
			function() {return new ActiveXObject('Msxml2.XMLHTTP')},
			function() {return new ActiveXObject('Microsoft.XMLHTTP')}
		) || false;
	}
}

Ajax.Events = ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];

Ajax.Request = function (url, options)
{
	this.options = {
		method:	'post',
		async: 	true,
		type:	'application/x-www-form-urlencoded',
		params:	'',
		passback: null,
		stream: false
	};
	this.timer = null;
	this.transport = Ajax.getTransport();
	this.options.extend(options || this.options);
	
	var params = this.options.params || '';
    if (params.length > 0) params += '&_=';

    try {
		this.url = url;
    	if (this.options.method == 'get' && params.length > 0)
			this.url += (this.url.match(/\?/) ? '&' : '?') + params;

	//	Ajax.Responders.dispatch('onCreate', this, this.transport);
	
		this.transport.open(this.options.method, this.url, this.options.async);

		if (this.options.async) {
			this.transport.onreadystatechange = this.onStateChange.bind(this);
			this.timer = setInterval((function() {this.respondToReadyState(1)}).bind(this), 10);
		}
		
		this.setRequestHeaders();

		this.transport.send(this.options.method == 'post' ? (this.options.post || params) : null);

	} catch (e) {
		throw(e);
	}
}

Ajax.Request.prototype.setRequestHeaders = function() {
	var requestHeaders = ['X-Requested-With', 'XMLHttpRequest', 'Accept', 'text/javascript, text/html, application/xml, text/xml, */*'];

	if (this.options.method == 'post') {
		requestHeaders.push('Content-type', this.options.type);

		/* Force "Connection: close" for Mozilla browsers to work around
		* a bug where XMLHttpReqeuest sends an incorrect Content-length
		* header. See Mozilla Bugzilla #246651. */
		
		if (this.transport.overrideMimeType) requestHeaders.push('Connection', 'close');
	}

	if (this.options.requestHeaders)
		requestHeaders.push.apply(requestHeaders, this.options.requestHeaders);

	for (var i = 0; i < requestHeaders.length; i += 2)
		this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]);
}

Ajax.Request.prototype.onStateChange = function() {
	var readyState = this.transport.readyState;
	if (readyState != 1)
		this.respondToReadyState(this.transport.readyState);
}

Ajax.Request.prototype.responseSuccess = function() {
	return this.transport.status == undefined || this.transport.status == 0 || (this.transport.status >= 200 && this.transport.status < 300);
}

Ajax.Request.prototype.respondToReadyState = function(readyState) {
	var event = Ajax.Events[readyState];
	var transport = this.transport;
		
	if (this.options.stream)
		this.streamData(this.transport.responseText);
		
	if (event == 'Complete') {
    	
		status = this.options['on' + this.transport.status] || null;
		handle = this.options['on' + (this.responseSuccess() ? 'Success' : 'Failure')] || null;
		
		if (typeof(status) == 'function')
			status();
		else
			eval(status);
		
		if (typeof(handle) == 'function')
			handle(this.transport, this.options.passback || null);
		else
			eval(handle);
		/*
		try {
			((typeof(this.options['on' + this.transport.status]) == 'function' ? this.options['on' + this.transport.status]() : this.options['on' + this.transport.status])
			|| typeof(this.options['on' + (this.responseSuccess() ? 'Success' : 'Failure')]);
		} catch (e) {
			throw(e);
		}
		*/
		/* This is for if i want to return JS
		if ((this.header('Content-type') || '').match(/^text\/javascript/i))
			this.evalResponse();
		*/
	}

	/* Dont know what this does.
	try {
		(this.options['on' + event] || return)(transport);
		Ajax.Responders.dispatch('on' + event, this, transport, json);
	} catch (e) {
		this.dispatchException(e);
	}
	*/
	
	/* Avoid memory leak in MSIE: clean up the oncomplete event handler */
	if (event == 'Complete') {
		this.transport.onreadystatechange = null;
		clearInterval(this.timer);
		window.status = "Connection Closed...";
	}
}

function Try () {
	var returnValue;
	for (var i = 0; i < arguments.length; i++)
		try {
			returnValue = arguments[i]();
			break;
		} catch (e) {}
	return returnValue;
}

Object.prototype.extend = function(source) {
	for (property in source) this[property] = source[property];
	return this;
}

Function.prototype.bind = function() {
	var __method = this, args = Array.from(arguments), object = args.shift();
	return function() {
		return __method.apply(object, args.concat(Array.from(arguments)));
	}
}

Array.from = function(iterable) {
	var results = [];
	if (iterable)
		if (iterable.toArray) return iterable.toArray();
		else for (var i = 0; i < iterable.length; i++) results.push(iterable[i]);
	return results;
}
