
// ------------------------------------------------------------------------------------------------------------
/*
Documentation: http://barney.wallst.com/wsodwiki/index.php/Content_Buffer

ContentBuffer()
generic data buffering object

usage:

var c = new ContentBuffer();
c.load({
	url: "data.asp",
	method: "get",
	onload: a,
	debug: true
});

function a (connection) {
	alert("x:" + connection.getResult());
};

*/
// ------------------------------------------------------------------------------------------------------------

if (typeof Controller == "undefined")
{
	if (typeof dbg != "function")
	{
		var dbg = function () {};
	};
}
else
{
	Controller.require("/includes/jslib/debug.js");
};

function ContentBuffer ()
{
	this.connections = [];
	this.connectionsMax = 100;
	this.connectionsActive = 0;
	this.connectionsPending = [];
	this.debug = false;
	this.context = window;
	this.connectionId = 0;

	if (arguments.length && typeof arguments[0] == "object")
	{
		this.context = arguments[0];
	};
};


// ------------------------------------------------------------------------------------------------------------
// load(contentPackge)
/*

contentPackge:
	.url: page to load in the hidden buffer
	.onload: function reference that gets called on a successful buffer load [optional]
	.onerror: function reference that gets called on an unsuccessful buffer load [optional]
	.method: get|post [optional]
	.postdata: synonym for .data [deprecated]
	.data: {name: value} list [optional]
	.[arbitrary]: optional arbitrary parameters that get passed to .callback; allows for state management with an asynch request

*/
// ------------------------------------------------------------------------------------------------------------
ContentBuffer.prototype.load = function (contentPackage)
{
	if (typeof Controller == "undefined")
	{
		//dbg("Missing Dependency", "Controller.js", "ff0000");
	};


	// data validation
	try
	{
		contentPackage.method = contentPackage.method.toLowerCase();

		if (contentPackage.method != "get" && contentPackage.method != "post")
		{
			contentPackage.method = "get";
		};
	}
	catch (e)
	{
		contentPackage.method = "get";
	};

	if (contentPackage.postdata && !contentPackage.data)
	{
		contentPackage.data = contentPackage.postdata;
	}
	else if (!contentPackage.data)
	{
		contentPackage.data = {};
	};

	// enable cache flushing
	if (document.location.search.match(/\.\.nocache\.\.=on/i))
	{
		contentPackage.data["..nocache.."] = "on";
	};

	// pass debugchartsrv
	var dbgChartSrv = document.location.search.match(/\.\.debugchartsrv\.\.=([a-zA-Z]+)/i);
	if (dbgChartSrv) {
		contentPackage.data["..debugchartsrv.."] = dbgChartSrv[1];
	}

	return new Connection(this, this.connectionId++, contentPackage);
};

// ------------------------------------------------------------------------------------------------------------
// loadXMLHTTP()
// ------------------------------------------------------------------------------------------------------------
ContentBuffer.prototype._loadXMLHTTP = function (connection) {

    var thisConnection = connection;
    var contentPackage = thisConnection.contentPackage;

	function stateMonitor () {
		thisBuffer._monitorConnectionState(thisConnection);
	};

	this.connectionsActive++;

    /*
	if (!this.connections.length) {
		if (!this.initConnection()) {
			if (this.debug || contentPackage.debug) {
				dbg("ContentBuffer initialization error", "unsupported", "red");
			};
			return;
		};
	};
    */

	var dataPackage = null;
	var thisBuffer = this;

	thisConnection.active = true;
	//contentPackage.connectionId = this.connectionId++; // necessary?

	if (typeof contentPackage.contentType == "string") {
		contentPackage.data["..contenttype.."] = contentPackage.contentType;
	};

	// uniquely identify contentbuffer requests
	contentPackage.data["..requester.."] = "ContentBuffer";

	if (contentPackage.method == "post") {

		dataPackage = "";

		for (var i in contentPackage.data) {
			dataPackage += (dataPackage.length ? "&" : "") + this.encode(i) + "=" + this.encode(contentPackage.data[i]);
		};

		if (this.debug || contentPackage.debug) {
			dbg("ContentBuffer post data", dataPackage);
		};

	} else {
		for (var i in contentPackage.data) {
			contentPackage.url += (contentPackage.url.indexOf("?") == -1 ? "?" : "&") + this.encode(i) + "=" + this.encode(contentPackage.data[i]);
		};
	};

	if (this.debug || contentPackage.debug) {
		dbg("ContentBuffer loading [" + thisConnection.connectionId + "]", contentPackage.url + " [" + contentPackage.method + "]");
	};

	if (this.debug || contentPackage.debug) {

		var debugUrl = contentPackage.url;

		if (dataPackage) {
			debugUrl += (debugUrl.indexOf("?") == -1 ? "?" : "&") + dataPackage;
		};

		debugUrl = debugUrl.replace(/\&?\.\.[^\=\&]*\.\.\=[^\&]*/g, "");

		if (debugUrl.indexOf("/") != 0 && debugUrl.indexOf("http") != 0) {
			var path = String(window.location).replace(/https*:\/\//, "");
			debugUrl = path.substr(path.indexOf("/"), path.lastIndexOf("/") + 1 - path.indexOf("/")) + debugUrl;
		}

		dbg("ContentBuffer URL", "<a href=\"" + debugUrl + "\"  target=\"_blank\">" + debugUrl + "</a>");
	};

	try {
		// netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
    	thisConnection.c.open(contentPackage.method.toUpperCase(), contentPackage.url, true);
		thisConnection.c.onreadystatechange = stateMonitor;
	} catch (e) {
		// alert(e);
	};

	if (contentPackage.method == "post") {
		thisConnection.c.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
	};

	//thisConnection.contentPackage = contentPackage;
	//dbg(thisConnection.c.send(), "trying connectionId");

	thisConnection.c.send(dataPackage);

	//return thisConnection;
};

// ------------------------------------------------------------------------------------------------------------
// monitorConnectionState()
// ------------------------------------------------------------------------------------------------------------
ContentBuffer.prototype._monitorConnectionState = function (connection) {

	try {

		if (connection.c.readyState == 4) {

			if (connection.c.status != 200) {

				if (this.debug || connection.contentPackage.debug) {
					dbg("ContentBuffer load error", connection.c.status, "red");
					dbg("ContentBuffer result [" + connection.connectionId + "]", connection.c.responseText);
				};

				try {
					var result = connection.c.responseText;
				} catch (e) {
					var result = null;
				};

				connection.contentPackage.result = result;

				if (typeof connection.contentPackage.onerror == "function") {
					connection.contentPackage.onerror.apply(connection.context, [connection]);
				};

				return;
			};

			var responseType = connection.contentPackage.contentType || connection.c.getResponseHeader("Content-Type");
			var result = null;

			if (responseType == "text/html" || responseType == "text/plain") {
				result = connection.c.responseText;
			} else if (responseType == "text/xml") {
				result = connection.c.responseXML;
			} else if (responseType == "text/javascript") {
				try {
					result = connection.c.responseText;

					if (!connection.contentPackage.preventEval) {

                       connection.context.__evalBuffer = function() {
                           eval(result);
                       }

                       connection.context.__evalBuffer();

					};

				} catch (e) {
					if (this.debug || connection.contentPackage.debug) {
						dbg("ContentBuffer javascript eval error", e.message, "red");
						if (typeof dbgObject != "undefined"){ dbgObject(e); }
					};
				};
			};

			connection.contentPackage.result = result;

			if (this.debug || connection.contentPackage.debug) {
				// dbg("ContentBuffer result [" + connection.contentPackage.connectionId + "]", result.replace(/\</g, "&lt;").replace(/\>/g, "&gt;"));
			};

			if (typeof connection.contentPackage.onload == "function") {
				connection.contentPackage.onload.apply(connection.context, [connection]);
			};

			this.finishConnection(connection);
		};

	} catch (e) {
		if (this.debug || connection.contentPackage.debug) {
			dbg("state monitoring error", e.message, "red");
			if (typeof dbgObject != "undefined"){ dbgObject(e); }
		};

		this.finishConnection(connection);
	};
};

// ------------------------------------------------------------------------------------------------------------
// isActive
// ------------------------------------------------------------------------------------------------------------
ContentBuffer.prototype.isActive = function() {
	for (var i=0; i<this.connections.length; i++) {
		if (this.connections[i].active) {
			return true;
		}
	}

	return false;
}

// ------------------------------------------------------------------------------------------------------------
// abortRequests()
// ------------------------------------------------------------------------------------------------------------
ContentBuffer.prototype.abortRequests = function () {
	for (var i = 0; i < this.connections.length; i++) {
		this.connections[i].abort();
	};
}

// ------------------------------------------------------------------------------------------------------------
// abortRequests()
// ------------------------------------------------------------------------------------------------------------
ContentBuffer.prototype.abortRequests = function () {
	for (var i = 0; i < this.connections.length; i++) {
		this.connections[i].abort();
	};
}

// ------------------------------------------------------------------------------------------------------------
// encode()
// ------------------------------------------------------------------------------------------------------------
ContentBuffer.prototype.encode = function(str) {
	//return escape(str);

	/* escape() doesn't account for the + symbol, which Serializer() sometimes includes in its Base64 encoding.  encodeURIComponent() includes everything escape() does, and includes the + symbol */
	return encodeURIComponent(str);
}

ContentBuffer.prototype.finishConnection = function(connection)
{
	if(connection.active)
	{
		this.connectionsActive--;
		connection.active = false;
	}

	if(this.connectionsPending.length)
	{
		this._loadXMLHTTP(this.connectionsPending.shift());
	}

	for (var x=0; x < this.connections.length; x++){
		if (connection === this.connections[x]){
			this.connections.splice(x,1);
			break;
		}
	}
}


// ------------------------------------------------------------------------------------------------------------
// Connection class
// ------------------------------------------------------------------------------------------------------------
function Connection(contentBuffer, id, contentPackage) {
	this.active = false;
	this.parent = contentBuffer;
	this.connectionId = id;
	this.contentPackage = contentPackage;
	this.context = contentPackage.context || this.parent.context;
	this._init();
};

Connection.prototype._init = function() {
    var c = false;

	try {
		c = new ActiveXObject("Msxml2.XMLHTTP");
	} catch (e) {
		try {
			c = new ActiveXObject("Microsoft.XMLHTTP");
		} catch (f) {
			c = false;
		};
	};

	if (!c && typeof XMLHttpRequest != "undefined") {
		c = new XMLHttpRequest();
	};

	if (c) {
		this.c = c;
	} else {
	   dbg("Content Buffer initialization error.", "Not supported by this browser", "red");
	};

    if (this.parent.connectionsActive < this.parent.connectionsMax) {
        this.parent.connections.push(this);
        this.parent._loadXMLHTTP(this);
    } else {
        dbg("queuing request");
        this.parent.connectionsPending.push(this);
    };
};

Connection.prototype.getResult = function() {
    return this.contentPackage.result;
};

Connection.prototype.status = function() {
	return (this.c.readyState == 4 && this.c.status == 200);
};

Connection.prototype.abort = function() {
	if (this.active) {
		try {
			this.c.onreadystatechange = function() {};
			this.c.abort();
		} catch (e) {
			dbg("connection abort failed", e, "red");
		};

		this.parent.finishConnection(this);
	};
};
