﻿// ###
//  This is the Bellwether Web Solutions (www.bellwetherwebsolutions.com) AJAX JavaScript.
//      It can be used to perform a request and get a response.
//
//  2008 (c) Bellwether Web Solutions
// ###

// This class handles creating AJAX requests
function BellwetherAjax() {
    // The array of AJAX objects that are running
    var m_aAjaxObjects = new Array();
    var m_oTimeoutID = null;

    // This function creates a new AJAX object and processes the URL
    this.AjaxRequest = function(url) {
        // Create a new AJAX object
        var bahAjaxHandler = new BellwetherAjaxHandler();
        bahAjaxHandler.AjaxRequest(url);

        // Add the handler to the request string
        m_aAjaxObjects.push(bahAjaxHandler);
        var objSelf = this;
        if (m_oTimeoutID == null) {
            m_oTimeoutID = setTimeout(function() { objSelf.AjaxCheck() }, 1000);
        }

        // All set
        return;
    }

    // This function creates a new AJAX object and processes the URL using the POST method
    this.AjaxRequest_Post = function(url, postData) {
        // Create a new AJAX object
        var bahAjaxHandler = new BellwetherAjaxHandler();
        bahAjaxHandler.AjaxRequest_Post(url, postData);

        // Add the handler to the request string
        m_aAjaxObjects.push(bahAjaxHandler);
        var objSelf = this;
        if (m_oTimeoutID == null) {
            m_oTimeoutID = setTimeout(function() { objSelf.AjaxCheck() }, 1000);
        }

        // All set
        return;
    }
    
    // This function checks for completed AJAX objects and removes them from memory
    this.AjaxCheck = function() {
        // Loop through and check for completed AJAX objects
        for (var i = 0; i < m_aAjaxObjects.length; i++) {
            if (m_aAjaxObjects[i].HasResponse()) {
                m_aAjaxObjects[i] = null; // we don't need this one anymore as the request has been completed
                m_aAjaxObjects.splice(i, 1);
            }
        }


        // Check if we're done processing
        if (m_aAjaxObjects.length == 0) {
            m_oTimeoutID = null;
        } else {
            // Call this method again
            var objSelf = this;
            m_oTimeoutID = setTimeout(function() { objSelf.AjaxCheck() }, 1000);
        }
    }
} // end BellwetherAjax

// This class handles sending and receiving AJAX requests
function BellwetherAjaxHandler() {
    // This handles the task of communicating with the web server and getting an XML
    var m_objHttpHandler = null;
    // This is a global value to tell if we successfully received data from the request
    var m_bHasResponse = false;
    // The timeout (in mili-seconds) after which the request will be aborted
    var m_nTimeoutMinutes = 3;
    var m_dTimeout = (m_nTimeoutMinutes * 60 * 1000);
    // This keeps track of the date-time when the AJAX request was sent to the web server
    var m_dtRequestSent;
    // We can have multiple AJAX requests at one time, this is the unique identifier
    var m_nGUID;
    // The complete URL for the AJAX request
    var m_szAjaxRequest = "";
    // This is the AJAX response text
    var m_szAjaxResult = "";
    // Indicates if all AJAX responses will be returned as rendered HTML/javascript for us to evaluate and not process
    var m_bEvalResponse = true;

    this.initialize = function() {
        // Resets member variables
        if (window.XMLHttpRequest) {
            // Mozilla, Safari
            m_objHttpHandler = new XMLHttpRequest();
            if (m_objHttpHandler.overrideMimeType) {
                m_objHttpHandler.overrideMimeType("text/xml");
            }
        }
        else if (window.ActiveXObject) {
            // Internet explorer
            try {
                m_objHttpHandler = new ActiveXObject("Msxml2.XMLHTTP");
            }
            catch (e) {
                try {
                    m_objHttpHandler = new ActiveXObject("Microsoft.XMLHTTP");
                }
                catch (e) { m_objHttpHandler = null; }
            }
        }

        m_nGUID = new Date().getTime();
    }

    this.HasResponse = function() {
        return m_bHasResponse;
    }

    this.AjaxResult = function() {
        return m_szAjaxResult;
    }

    this.SynchronousRequest = function(url) {
        // This performs a request just like AJAX, but it is synchronous (so the calling method will
        //      be halted until we receive a result)

        // Check to see if our XML Http Handler has been initialized
        if (!m_objHttpHandler) this.initialize();

        // Reset our handling variables
        m_bHasResponse = false;
        m_dtRequestSent = new Date();
        m_szAjaxRequest = url;

        // Open the connection to the server
        m_objHttpHandler.open("GET", url, false);

        // Send the request
        m_objHttpHandler.send(null);

        // Wait for the response and set the member value
        m_szAjaxResult = m_objHttpHandler.responseText;
    }

    this.AjaxRequest = function(url) {
        // Check to see if our XML Http Handler has been initialized
        if (!m_objHttpHandler) this.initialize();

        // Reset our handling variables
        m_bHasResponse = false;
        m_dtRequestSent = new Date();
        m_szAjaxRequest = url;

        // Open the connection to the server
        m_objHttpHandler.open("GET", url, true);

        // Assign the callback function for after the request has been completed successfully
        var objSelf = this;
        // We created an objSelf because we anticipate multiple ajax requests at once. By declaring
        //  the object, the javascript will be better able to determine which request is being handled
        m_objHttpHandler.onreadystatechange = objSelf.AcceptAjaxResponse;

        // Set the timeout for the request
        var id = m_nGUID;
        setTimeout(function() { objSelf.AjaxRequestTimeout(id) }, m_dTimeout);

        // Send the request
        m_objHttpHandler.send(null);
    }

    this.AjaxRequest_Post = function(url, postData) {
        // Check to see if our XML Http Handler has been initialized
        if (!m_objHttpHandler) this.initialize();

        // Reset our handling variables
        m_bHasResponse = false;
        m_dtRequestSent = new Date();
        m_szAjaxRequest = url;

        // Open the connection to the server
        m_objHttpHandler.open("POST", url, true);

        // Send the proper header information along with the request
        m_objHttpHandler.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        m_objHttpHandler.setRequestHeader("Content-length", postData.length);
        m_objHttpHandler.setRequestHeader("Connection", "close");

        // Assign the callback function for after the request has been completed successfully
        var objSelf = this;
        // We created an objSelf because we anticipate multiple ajax requests at once. By declaring
        //  the object, the javascript will be better able to determine which request is being handled
        m_objHttpHandler.onreadystatechange = objSelf.AcceptAjaxResponse;

        // Send the request
        m_objHttpHandler.send(postData);

        // Set the timeout for the request
        var id = m_nGUID;
        setTimeout(function() { objSelf.AjaxRequestTimeout(id) }, m_dTimeout);
    }

    this.AcceptAjaxResponse = function() {
        // Check to see if we have a response
        if (m_objHttpHandler && m_objHttpHandler.readyState == 4) {
            m_bHasResponse = true;

            // Get the status code for the ajax request. Wrap the work in a try catch b/c in firefox
            //      if the user leaves the page while we're working, we'll get an error
            var nStatusCode = 0;
            try { nStatusCode = m_objHttpHandler.status; }
            catch (e) { nStatusCode = 0; }

            if (nStatusCode != 0 && nStatusCode != 200 && m_objHttpHandler.responseText.length) {
                // We've received a web server error so abort the request and reset our variables
                m_objHttpHandler.onreadystatechange = function() { return false }
                m_objHttpHandler.abort();
                m_nGUID = null;
                m_dtRequestSent = null;
                m_szAjaxResult = "";

                return false;
            }
            else {
                m_szAjaxResult = m_objHttpHandler.responseText;
                // Evaluate the request
                if (m_bEvalResponse && m_szAjaxResult) {
                    eval(m_szAjaxResult);
                }
            }

            return nStatusCode == 200;
        }

        return false;
    }

    this.AjaxRequestTimeout = function(requestId) {
        // This will handle what happens if the Ajax request associated with requestId
        //      where requestId = BellwetherAjax.m_nGUID

        // This function will ALWAYS be called as the timeout for it is never reset. It is always
        //      called so it can cleanup some of the working and member variables for re-use

        // First, we make sure the request that has timed out is this request
        if (requestId != m_nGUID) return;
        // Check to make sure we haven't gotten a response and that we've sent the request
        if (m_bHasResponse || !m_dtRequestSent || !m_objHttpHandler) return;

        // The timeout period has elapsed, so we will abort the request
        m_objHttpHandler.onreadystatechange = function() { return false }
        m_objHttpHandler.abort();
        m_nGUID = null;
        m_dtRequestSent = null;
        m_bHasResponse = false;
        m_szAjaxRequest = "";

        // Let the user know
        alert("Request timed out. Please try again.");
    }
}  // end BellwetherAjaxHandler