// Simple x-browser function to add an event listener
function addEvent(obj, evType, fn)
{ 
    if (obj.addEventListener)
    { 
        obj.addEventListener(evType, fn, false); 
        return true; 
    } 
    else if (obj.attachEvent)
    { 
        var r = obj.attachEvent("on" + evType, fn); 
        return r; 
    } 
    else 
    { 
        return false; 
    } 
}


// compileScript makes a script globally available
function compileScript(script)
{
    // Internet Explorer
    if (window.execScript)
    {
        window.execScript(script);
    }
    else // Firefox, at least
    {
        window.setTimeout(script,0);
    }
}


// scripts generated server-side and particularly those included as part of
// innerHTML for a parent element are not enabled by default. This function
// finds all script tags in the parent element and enables their script
function enableScripts(parentObj)
{
    var scripts = parentObj.getElementsByTagName("script");
    for(i=0;i<scripts.length;i++)
    {
        // enable the script for global use in the window
        compileScript(scripts[i].text);
    }
}


// createMSXMLObject is called when postRequest fails to create a native
// XMLHttpRequest object, typically in IE versions lower than IE7.
function createMSXMLObject()
{
	// MSXML IDs that you want to support (in order of preference). Note: Only 6.0 and 3.0 get concerted,
	// continuing development support from Microsoft. 6.0 is supported in IE7
	// but shouldn't be needed since IE7 has native XMLHTTP support like Firefox
	var msxmlIDs = ["6.0", "3.0"];
	
	// Loop through the IDs until you hit one that is supported
	for (var i = 0, l = msxmlIDs.length; i < l; i++) 
	{
		try 
		{
			// Create the object
			var msxmlObj = new ActiveXObject("Msxml2.XMLHTTP." + msxmlIDs[i]);
			
			// Return it to the calling code. This will break out
			//  of the loop, ensuring only that version is created
			return msxmlObj;
		}
		catch (e) 
		{ 
			
		}
	}	
	
	// If no object was created return null
	return null;
}


// Simple function to report errors - could be modified to do something else than alerts,
// which would be recommended in a production environment.
function errorHandler(errorStr)
{
    alert("Error Handler: " + errorStr);
}


/*****
* postRequest will attempt to instantiate an XMLHttp request and post the provided
* parameters to the designated URL. Parameters need to be constructed in to emulate
* a FORM post string, i.e. "param1=value&param2=another value&param3=yet another value"
* Note: the param string will be URI encoded INSIDE this function. DO NOT encode it beforehand
*
* Usage: var paramStr = "dir=" + dir; // paramStr
*        paramStr += "style=" + style // adding a param
*        postRequest(paramStr, "directoryList.aspx", processRequest, errorHandler, 10, true);
*
*   Note: timeout is in seconds, not milliseconds!
*****/
function postRequest(paramStr, serverURL, callbackFunction, errorHandlerFunction, timeout, showProgressIndicator) 
{
	try 
	{
	    appendActivityIndicator();
	
		var httpRequest;

		try 
		{
			// First, try to instantiate a native XMLHttpRequest object (e.g. Firefox, IE7)
			httpRequest = new XMLHttpRequest();
		} 
		catch (e)
		{	
            // If native object instantiation fails, try creating ActiveX MSXML object
			httpRequest = createMSXMLObject();
			
			// If that fails, no options left so throw an exception
			if(!httpRequest)
			{
			    throw new Error("Request object could not be created.");
			}
		}


        // Particularly because postRequest is operating asynchronously, we need onreadystatechange monitoring
        // via a function. In this case, we test for success and then send the responseText to the callback
        // function. If there is a failure, it is sent to the errorHandlerFunction 
        httpRequest.onreadystatechange = function() 
        { 
            try 
            {
                if (httpRequest.readyState == 4) 
                {
                    if (httpRequest.status == 200) 
                    {
                        // Only send responseText to callback function. Any other issue should be handled with
                        // some sort of error handler function 
                     
						 // Test that an actual function has been assigned before calling it.
						 // (NOTE: This also allows postRequest to be used with no callback function, e.g. null
						 if(typeof(callbackFunction) == "function") 
						{
							callbackFunction(httpRequest.responseText); 
						}
                        // Now that the request has been received, hide the activity indicator (if one is in use)
                        if(activityIndicator)
                        {
                            activityIndicator.style.visibility = "hidden";
                        }
                    } 
                    else 
                    {
                        // if the status is something else, throw an exception
                        throw new Error("status: " +httpRequest.status);
                    }
                }
            }
            catch(e) 
            {
                // hide the activity indicator (if one is in use)
                if(activityIndicator)
                {
                    activityIndicator.style.visibility = "hidden";
                }

                // Refer the problem to the error handling function
                errorHandlerFunction("There was a problem with the response. \n\n\t" + e.name + " - " + e.message);
            }
  
        };

        // Open the request as a "POST", asynchronously
		httpRequest.open("POST", serverURL, true);

        // Check to see if we should show an activity indicator
        if(showProgressIndicator == true)
        {
            // Get the activityIndicator as an object
            var activityIndicator = document.getElementById("activityIndicatorUI");
         
            // Make it visible
            activityIndicator.style.visibility = "visible";
        }
        
        // Set the request header so server knows to expect form-style data
		httpRequest.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
		
		// Encode the param string so that it gets sent properly
		paramStr = encodeURI(paramStr);

		httpRequest.setRequestHeader('Content-length', paramStr.length);
  		//httpRequest.setRequestHeader('Connection','close');



		// Send the request parameters
		httpRequest.send(paramStr);

        // Set a timeout (in seconds) in case the request takes to long or hangs
        window.setTimeout( function(){ httpRequest.abort(); httpRequest = null; }, timeout*1000);

	}
	catch (e) 
	{
        // If an error has occurred, the request is dead so hide the activityIndicator (if any)
        if(activityIndicator)
        {
            activityIndicator.style.visibility = "hidden";
        }
              
        // Refer the problem to the error handling function
		errorHandlerFunction("There was a problem within the postRequest function. \n\n\t " + e.name + " - " + e.message);
	}
}



/*****
* appendActivityIndicator() is a convenient function for adding a ready-made graphical activity indicator
* to a web page using the xmlhttp functions. It requires an animated gif file. One is supplied or you can
* create one and substitute it. This indicator will always be centered on the page (even on resize).
*****/
function appendActivityIndicator()
{
    //Check first that the indicator hasn't already been added
    var activityIndicatorUI = document.getElementById("activityIndicatorUI"); 
   
    // If the object doesn't exist, create it
    if(activityIndicatorUI == null)
    {
    
        var activityIndDiv = document.createElement('div');

        activityIndDiv.id = "activityIndicatorUI";

        activityIndDiv.style.visibility = "hidden";
        activityIndDiv.style.zIndex = "10000";
        activityIndDiv.style.position = "absolute";
        activityIndDiv.style.left = "49%";
        activityIndDiv.style.top = "49%";

        document.body.appendChild(activityIndDiv);
        activityIndDiv.innerHTML = "<img src='js/activityIndicator.gif' height='48' width='48' />";
    }
}

// For convenience sake, go ahead and append an activity indicator to the page
// This also prevents it from having to be constructed on every request
addEvent(window, 'load', appendActivityIndicator);
