// Copyright (C) 2006 Cognos Incorporated. All rights reserved.
// Cognos (R) is a trademark of Cognos Incorporated.

//DISPATCHER CONTROL
function CDispatcher(maxNumSCs)
{
	if (typeof maxNumSCs == "undefined")
		this.m_oQueueManager = new CQueueManager();
	else
		this.m_oQueueManager = new CQueueManager(maxNumSCs);
}

CDispatcher.prototype.createRequest = function(gateway, requestParams, callbackFunction)
{
	return new CRequest(gateway, requestParams, callbackFunction);
}

CDispatcher.prototype.dispatchRequest = function(CRequest)
{
	return this.m_oQueueManager.addRequestToQueue(CRequest);
}

CDispatcher.prototype.getRequestStatus = function(CRequest)
{
	return CRequest.getStatus();
}

CDispatcher.prototype.cancelRequest = function(CRequest)
{
	var isCancelled = this.m_oQueueManager.removeRequestFromQueue(CRequest.getId(), false);
	if (isCancelled >= 1)
		return 1;
	return isCancelled;
}

CDispatcher.prototype.setErrorHandlerFunction = function(errorFunction)
{
	this.m_oQueueManager.setErrorHandlerFunction(errorFunction);
}


//REQUEST CONTROL
function CRequest(gateway, requestParams, callbackFunction)
{
	this.m_sGateway = gateway;
	this.m_sRequestParams = requestParams;
	this.m_fCallbackFunction = callbackFunction;
	this.m_iRequestId = generateUniqueId();
	this.m_sStatus = 0;
	this.m_oSC = null;
	this.m_sResponseType = "HTML";
}

CRequest.prototype.getId = function()
{
	return this.m_iRequestId;
}

CRequest.prototype.setResponseType = function(responseType)
{
	this.m_sResponseType = responseType;
}

CRequest.prototype.getResponseType = function()
{
	return this.m_sResponseType;
}

CRequest.prototype.setStatus = function(statusVal)
{
	try
	{
		this.m_sStatus = statusVal;
	}
	catch (e)
	{
		return false;
	}
	return true;
}

CRequest.prototype.getStatus = function()
{
	return this.m_sStatus;
}

CRequest.prototype.getSC = function()
{
	return this.m_oSC;
}

CRequest.prototype.setSC = function(sSCval)
{
	try
	{
		this.m_oSC = sSCval;
	}
	catch (e)
	{
		return false;
	}
	return true;
}

CRequest.prototype.getGateway = function()
{
	return this.m_sGateway;
}

CRequest.prototype.getRequestParams = function()
{
	return this.m_sRequestParams;
}

CRequest.prototype.getCallbackFunction = function()
{
	return this.m_fCallbackFunction;
}


//QUEUE MANAGER CONTROL
var XMLHttpRequests;
/*	Do not reset this variable if it is already set.
	It could happen if this file is included twice in a page. */
if (typeof XMLHttpRequests == "undefined") {
	XMLHttpRequests = new Array();
}

function CQueueManager(maxNumSCs)
{
	this.m_arQueue = new Array();
	this.m_arSCs = new Array();
	if (typeof maxNumSCs != "undefined")
		this.iMaxNumSCs = maxNumSCs;
	else
		this.iMaxNumSCs = 2;

	for (var i = 0; i < this.iMaxNumSCs; i++)
	{
		var arLen = XMLHttpRequests.length;
		var newSC = new CServerCommunicator(this, arLen);
		XMLHttpRequests[arLen] = new Array(null, newSC);
		this.m_arSCs[this.m_arSCs.length] = newSC;
	}
	this.errorHandlerFunction = null;
}

CQueueManager.prototype.setErrorHandlerFunction = function(errorFunction)
{
	this.errorHandlerFunction = errorFunction;
}

CQueueManager.prototype.addRequestToQueue = function(CRequest)
{
	var returnStatus = -1;
	try
	{
		CRequest.setStatus(1);
		this.m_arQueue[this.m_arQueue.length] = CRequest;
		returnStatus = 0;	
		var requestSuccess = this.sendNextRequest();
		if (requestSuccess == true)
			return 1;
		else
		{
			CRequest.setStatus(-1);
			return returnStatus;
		}
	}
	catch (e)
	{
		CRequest.setStatus(-1);
		if (typeof this.errorHandlerFunction == "function")
			this.errorHandlerFunction("addRequestToQueue", e);
		return returnStatus;
	}
}

CQueueManager.prototype.removeRequestFromQueue = function(requestId, callCallback, response)
{
	try
	{
		var thisArrayEntry = -1;
		for (var i = 0; i < this.m_arQueue.length; i++)
		{
			if (this.m_arQueue[i] != null && this.m_arQueue[i].getId() == requestId)
			{
				thisArrayEntry = i;
				break;
			}
		}
		
		if (callCallback == true)
		{
			var callbackFunction = this.m_arQueue[thisArrayEntry].getCallbackFunction();
			if (typeof callbackFunction == "function")
			{
				try
				{
					callbackFunction(response);
				}
				catch (e)
				{
					if (typeof this.errorHandlerFunction == "function")
						this.errorHandlerFunction("removeRequestFromQueue_1", e);
					return -1;
				}
			}
			this.m_arQueue[thisArrayEntry].setStatus(3);
			delete (this.m_arQueue[thisArrayEntry]);
			return 1;
		}
		else
		{
			if (this.m_arQueue[thisArrayEntry].getStatus() == 2)
			{
				try
				{
					this.m_arSCs[this.m_arQueue[thisArrayEntry].getSC()].cancelRequest();
				}
				catch (e)
				{
					if (typeof this.errorHandlerFunction == "function")
						this.errorHandlerFunction("removeRequestFromQueue_2", e);
					return 0;
				}
			}
			this.m_arQueue[thisArrayEntry].setStatus(-2);
			delete (this.m_arQueue[i]);
		}

		var requestSuccess = this.sendNextRequest();
		if (requestSuccess == false)
			return 3;

		return 2;
	}
	catch (e)
	{
		if (typeof this.errorHandlerFunction == "function")
			this.errorHandlerFunction("removeRequestFromQueue_3", e);
		return -1;
	}
}

CQueueManager.prototype.sendNextRequest = function()
{
	try
	{
		var theNextSC = -1;
		for (var i = 0; i < this.m_arSCs.length; i++)
		{
			if (this.m_arSCs[i].getBusy() <= 0)
			{
				theNextSC = i;
				break;
			}
		}

		if (theNextSC > -1)
		{
			var theNextRequest = -1;
			for (var i = 0; i < this.m_arQueue.length; i++)
			{
				if (this.m_arQueue[i] != null && this.m_arQueue[i].getStatus() == 1)
				{
					this.m_arQueue[i].setStatus(2);
					theNextRequest = i;
					break;
				}
			}
			
			if (theNextRequest > -1)
			{
				this.m_arQueue[theNextRequest].setSC(theNextSC);
				this.m_arSCs[theNextSC].sendRequest(this.m_arQueue[theNextRequest]);
			}
			else
			{
				//This will empty the queue if there's nothing left in it
				var activeRequests = false;
				for (var i = 0; i < this.m_arQueue.length; i++)
				{
					if (this.m_arQueue[i] != null && (this.m_arQueue[i].getStatus() == 1 || this.m_arQueue[i].getStatus() == 2))
					{
						activeRequests = true;
						break;
					}
				}
				if (activeRequests == false)
					this.m_arQueue = new Array();
			}
		}
	}
	catch (e)
	{
		if (typeof this.errorHandlerFunction == "function")
			this.errorHandlerFunction("sendNextRequest", e);
		return false;
	}
	return true;
}


//SERVER COMMUNICATOR CONTROL
function CServerCommunicator(CQueueManager, XMLHttpRequestArrayIndex)
{
	this.m_bIsBusy = -1;
	this.m_oQueueManager = CQueueManager;
	this.m_oRequest = null;
	this.m_oXMLHttpRequestIndex = XMLHttpRequestArrayIndex;
}

CServerCommunicator.prototype.sendRequest = function(CRequest)
{
	this.setBusy(1);
	this.m_oRequest = CRequest;
	if (typeof ActiveXObject != "undefined")
	{
		XMLHttpRequests[this.m_oXMLHttpRequestIndex][0] = new ActiveXObject("Msxml2.XMLHTTP");
	}
	else
	{
		XMLHttpRequests[this.m_oXMLHttpRequestIndex][0] = new XMLHttpRequest();
	}
	XMLHttpRequests[this.m_oXMLHttpRequestIndex][0].onreadystatechange = XMLHttpRequestReadyStateChanged;
	XMLHttpRequests[this.m_oXMLHttpRequestIndex][0].open("POST", CRequest.getGateway(), true);
	XMLHttpRequests[this.m_oXMLHttpRequestIndex][0].setRequestHeader("Content-Type", "text/html");
	XMLHttpRequests[this.m_oXMLHttpRequestIndex][0].send(CRequest.getRequestParams());
}

CServerCommunicator.prototype.getStatus = function()
{
	return XMLHttpRequests[this.m_oXMLHttpRequestIndex][0].status;
}

CServerCommunicator.prototype.getBusy = function()
{
	return this.m_bIsBusy;
}

CServerCommunicator.prototype.setBusy = function(busyVal)
{
	try
	{
		this.m_bIsBusy = busyVal;
	}
	catch (e)
	{
		return false;
	}
	return true;
}

CServerCommunicator.prototype.cancelRequest = function()
{
	return XMLHttpRequests[this.m_oXMLHttpRequestIndex][0].abort();
}


// Ready State Function
function XMLHttpRequestReadyStateChanged()
{
	for (var i = 0; i < XMLHttpRequests.length; i++)
	{
		if (XMLHttpRequests[i] && XMLHttpRequests[i][0] && XMLHttpRequests[i][0].readyState == 4)
		{
			try
			{
				XMLHttpRequests[i][1].setBusy(0);
				var responseType = XMLHttpRequests[i][1].m_oRequest.getResponseType();
				var removeSuccess = -1;
				if (responseType == "HTML")
					removeSuccess = XMLHttpRequests[i][1].m_oQueueManager.removeRequestFromQueue(XMLHttpRequests[i][1].m_oRequest.getId(), true, XMLHttpRequests[i][0].responseText);
				else if (responseType == "XML")
					removeSuccess = XMLHttpRequests[i][1].m_oQueueManager.removeRequestFromQueue(XMLHttpRequests[i][1].m_oRequest.getId(), true, XMLHttpRequests[i][0].responseXML);
				else if (responseType == "XMLHTML")
					removeSuccess = XMLHttpRequests[i][1].m_oQueueManager.removeRequestFromQueue(XMLHttpRequests[i][1].m_oRequest.getId(), true, new Array(XMLHttpRequests[i][0].responseXML, XMLHttpRequests[i][0].responseText));
				XMLHttpRequests[i][0] = null;
				if (removeSuccess >= 1)
					XMLHttpRequests[i][1].m_oQueueManager.sendNextRequest();
				else
					return false;
			}
			catch (e)
			{
				return false;
			}
			return true;
		}
	}
}


// Utility Functions
function generateUniqueId()
{
	return (Date.parse((new Date()).toString()) / 1000000) + Math.random();
}
