/*!\brief	HTTP class that fetches a URL and executes the specified
 *		CustomEvent with the resulting text.  Supports request queue.
 */
BS.com.HTTP = function ()
{
	var x = null;

	try { x = new ActiveXObject('Msxml2.XMLHTTP'); }
	catch (e) {
		try { x = new ActiveXObject('Microsoft.XMLHTTP'); }
		catch (e2) { }
	}

	if (!x && typeof XMLHttpRequest != 'undefined')
		x = new XMLHttpRequest();

	if (!x) throw 'missing XMLHttpRequest';

	this.http = x;

	this.cbT = BS.utl.func.bind(this._parseCB, this);

	this.busy = false;
	this.reqA = [];
	this.hA = [];

	this.mm = new BS.com.Delete;
	this.openE = this.mm.ceNew('openE', this);
	this.openE.addCB(this._openCB);
};

BS.com.HTTP.prototype = {
	CT:		'application/x-www-form-urlencoded; charset=utf-8',

	_delete: function ()
	{
		delete this.http.onreadystatechange;
		this.mm._delete();
		this.cbT = this.http = null;
	},

	/*!\brief	Execute CustomEvent and adjust queue.  The CustomEvent
	 *		args array will contain the following:
	 *		args[0]		response
	 *		args[1]		request URL
	 *		args[2]		POST array (optional)
	 *		args[3]		data
	 */
	_execCE: function (d)
	{
		var			t = this.reqA[0];

		try { t[3].exec(d, t[1], t[2], t[4]); }
		catch (e) { var eE = e; }

		this.reqA.shift();

		if (this.reqA.length) this.openE.setTimeout(0);
		else this.busy = false;

		if (typeof eE != 'undefined') throw eE;
	},

	/*!\brief	Callback that executes CustomEvent.
	 * \param	s		synchronous (default false)
	 * \note	s === true (distinguishes between event as argument)
	 */
	_parseCB: function (s)
	{
		if (!this || !this.http || this.http.readyState != 4) return;

		if (!this.http.responseText) throw 'Text missing error';

		if (s === true) return this.http.responseText;
		this._execCE(this.http.responseText);
	},

	/*!\brief	Queue AJAX request and initiate if not busy
	 * \param	method		request method
	 * \param	url		request URL
	 * \param	p		POST array (optional)
	 * \param	ce		CustomEvent
	 * \param	d		data (optional)
	 */
	_queue: function (method, url, p, ce, d)
	{
		this.reqA.push([method, url, p, ce, d]);
		if (!this.busy) this._openCB();
	},

	/*!\brief	Callback that opens next item in queue. */
	_openCB: function ()
	{
		var t = this.reqA[0];
		this._open(t[0], t[1], t[2]);
	},

	/*!\brief	Open AJAX connection based on request queue.
	 * \param	method		request method
	 * \param	url		request URL
	 * \param	p		POST array (optional)
	 * \param	s		synchronous (default false)
	 */
	_open: function (method, url, p, s)
	{
		this.busy = true;
		this.http.open(method, url, !s);
		if (!s) this.http.onreadystatechange = this.cbT;

		if (p) this.http.setRequestHeader('Content-Type', this.CT);

		for (var i=0, l=this.hA.length; i<l; i++)
			this.http.setRequestHeader(this.hA[i][0],
						   this.hA[i][1]);

		this.http.send(p ? BS.utl.array.urlencode(p) : null);

		if (s) return this._parseCB(s);
	},

	/*!\brief	Open GET connection to URL and execute CustomEvent.
	 * \param	url		URL
	 * \param	ce		CustomEvent
	 * \param	d		data (optional)
	 */
	get: function (url, ce, d) { this._queue('GET', url, null, ce, d); },

	/*!\brief	Open POST connection to URL and execute CustomEvent.
	 * \param	url		URL
	 * \param	p		POST array
	 * \param	ce		CustomEvent
	 * \param	d		data (optional)
	 */
	post: function (url, p, ce, d) { this._queue('POST', url, p, ce, d); },

	/*!\brief	Open wrapper in synchronous mode.
	 * \param	method		request method
	 * \param	url		request URL
	 * \param	p		POST array (optional)
	 */
	_openS: function (method, url, p)
	{
		if (this.busy) throw 'AssertErr BS.com.HTTP.busy';
		return this._open(method, url, p, true);
	},

	/*!\brief	Return synchronous GET from URL.
	 * \param	url		URL
	 */
	getS: function (url) { return this._openS('GET', url); },

	/*!\brief	Return synchronous POST from URL.
	 * \param	url		URL
	 * \param	p		POST array
	 */
	postS: function (url, p) { return this._openS('POST', url, p); }
};

