function PPSCXHRLib()
{
}

// -- callCount
//
// keeps a count of how many XHR calls there have been
PPSCXHRLib.callCount = 0;

// -- callStack
//
// stores the currently active XHR calls
PPSCXHRLib.callStack = new Array();


PPSCXHRLib.bodyId = "bodyElement";


// -- makeXHRCall
//
// general way to make a new XHR call.  a new xmlhttp browser object is created.
PPSCXHRLib.makeXHRCall = function (xhrCallArg)
{
	if (typeof xhrCallArg != "object")
		return;
		
	var dateNow = new Date();
	
	xhrCallArg.callStarted = dateNow.getTime();
	
	if (xhrCallArg.async) // we only need it on the stack if it's async
		PPSCXHRLib.callStack.push(xhrCallArg);

	// give this call a unique id		
	xhrCallArg.callNumber = PPSCXHRLib.callCount++;

    xhrCallArg.xmlhttp.open("POST", xhrCallArg.url, xhrCallArg.async);

    xhrCallArg.xmlhttp.setRequestHeader("Content-Type", "text/plain");
    
    if (xhrCallArg.async)
    {
        xhrCallArg.xmlhttp.onreadystatechange = function () {  // setup the requestHandler in it's own context so "this" works.
			
			xhrCallArg.requestHandler();
			
			if (xhrCallArg.xmlhttp.readyState == 4)
			{
				if (xhrCallArg.oncomplete && typeof(xhrCallArg.oncomplete) == "function")
				{
					xhrCallArg.oncomplete();
				}
				if (xhrCallArg.floater)
				{
					xhrCallArg.floater.KillMe();
				}
				
				// remove our call from the stack.
				for (var i = 0; i < PPSCXHRLib.callStack.length; i++)
				{
					if (PPSCXHRLib.callStack[i].callNumber == xhrCallArg.callNumber)
					{
						// delete our element and break loop
						PPSCXHRLib.callStack.splice(i, 1);
						break;
					}
				}
			}
        };        
    }
    
    if (xhrCallArg.message && xhrCallArg.message != "")
    {
		// this immiediately shows the message - we may need to change this.
		xhrCallArg.floater = new Floater(PPSCXHRLib.bodyId, "PPSCXHRLibFloaters" + xhrCallArg.callNumber, xhrCallArg.message);
    }
    
    if (typeof(xhrCallArg.jsonStrOrJsObj) == "object")
        var req = JSON.stringify(xhrCallArg.jsonStrOrJsObj);
    else
        var req = xhrCallArg.jsonStrOrJsObj;
    
    xhrCallArg.xmlhttp.send(req);
    
    // if it is asyn, setup a check to remove it from the callStack after 300 seconds if it fails.
    if (xhrCallArg.async)
    {
		setTimeout("PPSCXHRLib.removeCallFromStack(" + xhrCallArg.callNumber + ");", 60000);
    }
    
    // if it's not asyncrohnous, process now.
    if (!xhrCallArg.async)
    {
        try
        {
			var decodedResponse = JSON.parse(xhrCallArg.xmlhttp.responseText);
        }
        catch (ex)
        {
            var decodedResponse = { isError : true, errorCode : 50, message : "Unknown API response." };
        }
        return decodedResponse;
    }
}



// -- getXmlhttpRequestObject
//
// creates an xmlhttprequest object depending on browser.
PPSCXHRLib.getXmlHttpRequestObject = function()
{
    var xmlhttp = false;
    
    try 
    {
        xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
    }
    catch (e) 
    {
        try 
        {
            xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
        } 
        catch (E) 
        {
            xmlhttp = false;
        }
    }
    
    if (!xmlhttp && typeof XMLHttpRequest!='undefined') 
    {
        xmlhttp = new XMLHttpRequest();
    }

    return xmlhttp;
}


// -- runWhenCallStackClear
//
//
PPSCXHRLib.runWhenCallStackClear = function (func)
{
	if (PPSCXHRLib.callStack.length == 0)
	{
		func();
	}
	else
	{
		setTimeout(function () { PPSCXHRLib.runWhenCallStackClear(func); }, 100);
	}
}


// -- removes an entry from the call stack
//
//
PPSCXHRLib.removeCallFromStack = function (callNumber)
{
	// remove our call from the stack.
	for (var i = 0; i < PPSCXHRLib.callStack.length; i++)
	{
		if (PPSCXHRLib.callStack[i].callNumber == callNumber)
		{
			// delete our element and break loop
			PPSCXHRLib.callStack.splice(i, 1);
			break;
		}
	}
}
