//
// Main function: ajaxCalls_callServer(command, fnToExecuteWithCallbackResult)
//
//-------------------------------------------------------
var gAjaxCalls_DEDICATED_AJAX_WEBPAGE = 'AJAXPage.aspx';
var gAjaxCalls_CallInProgress = false;
var gAjaxCalls_DEFAULT_TIMEOUT_MSEC = 600000; //10 minutes

var gAjaxCalls_ArrayCommands = new Array(); //pending AJAX commands (FIFO list)
var gAjaxCalls_ArrayFnToExecuteWithCallbackResult = new Array(); //functions to execute when AJAX callback results are received
var gAjaxCalls_ArrayOptionalFnToExecuteJustBeforeCalling = new Array();
var gAjaxCalls_ArrayTimeouts = new Array(); //put 0 for default (gAjaxCalls_DEFAULT_TIMEOUT_MSEC)
var gAjaxCalls_ArrayPageNames = new Array(); //put null for default (current Web page) or a different Web page name, e.g. 'Session.aspx' for session control

//The following function can be user-defined, to avoid the standard JavaScript alert provided by default.
//should return
// - true: continue contacting server/retry,
// - false: abort call
var gAjaxCalls_TimeoutExpiredFn = function(commandInfo) { //commandInfo: (parf of) initial command
    return confirm("AJAX CALL FAILED, TIMEOUT EXPIRED.\n(" + commandInfo + ")\n\nWould you like to retry contacting server?");
};

//This flag will call gAjaxCalls_AfterTimeoutExpiredRecoveredOKFn() or not after recovering from a timeout
var gAjaxCalls_MustCallAfterTimeoutExpiredRecoveredOKFn_Flag = false;

//to be called right after recovering from AJAX call timeout
//e.g. after calling gAjaxCalls_TimeoutExpiredFn() and retrying, AJAX succeeds. Then, we could inform user, etc.
var gAjaxCalls_AfterTimeoutExpiredRecoveredOKFn = function() {
};

//-------------------------------------------------------
function ajaxCalls_callServer(command, fnToExecuteWithCallbackResult, optionalFnToExecuteJustBeforeCalling, optionalTimeoutMSec, optionalPageName) {
    try {
        gAjaxCalls_ArrayCommands.push(command);
        gAjaxCalls_ArrayFnToExecuteWithCallbackResult.push(fnToExecuteWithCallbackResult);
        gAjaxCalls_ArrayOptionalFnToExecuteJustBeforeCalling.push(optionalFnToExecuteJustBeforeCalling);
        gAjaxCalls_ArrayTimeouts.push(optionalTimeoutMSec);
        gAjaxCalls_ArrayPageNames.push(optionalPageName);
    }
    catch (e) {
        //Try again, possible concurrency issue
        setTimeout(function() {
        ajaxCalls_callServer(command, fnToExecuteWithCallbackResult, optionalFnToExecuteJustBeforeCalling, optionalTimeoutMSec);
        }, 10);
    }
}
//-------------------------------------------------------
function ajaxCalls_aux_execAJAXcalls() {
    try {
        if (!gAjaxCalls_CallInProgress && gAjaxCalls_ArrayCommands.length > 0) {
            var ajaxCommand = gAjaxCalls_ArrayCommands[0];
            gAjaxCalls_ArrayCommands.splice(0, 1);

            var optionalFnToExecuteJustBeforeCalling = gAjaxCalls_ArrayOptionalFnToExecuteJustBeforeCalling[0];
            gAjaxCalls_ArrayOptionalFnToExecuteJustBeforeCalling.splice(0, 1);

            var ajaxCallTimeoutMSec = gAjaxCalls_ArrayTimeouts[0];
            gAjaxCalls_ArrayTimeouts.splice(0, 1);

            var ajaxPageName = gAjaxCalls_ArrayPageNames[0];
            gAjaxCalls_ArrayPageNames.splice(0, 1);

            if (optionalFnToExecuteJustBeforeCalling)
                optionalFnToExecuteJustBeforeCalling();

            ajaxCalls_doCallServer(ajaxCommand, ajaxCallTimeoutMSec, ajaxPageName);
            setTimeout(ajaxCalls_aux_execAJAXcalls, 1);
            return;
        }
    }
    catch (e) {
        //possible concurrency issue, will try again
    }

    setTimeout(ajaxCalls_aux_execAJAXcalls, 10);
}
ajaxCalls_aux_execAJAXcalls();
//-------------------------------------------------------
//Defined on server-side: ajax_callServer(arg); //, context
//-------------------------------------------------------
function ajax_receiveCallBackResult(result, context) {
    ajaxCalls_receiveCallBackResult(result, context);
}
//-------------------------------------------------------
function ajaxCalls_doCallServer(command, ajaxCallTimeoutMSec, ajaxPageName) {
    gAjaxCalls_CallInProgress = true;

    if (ajaxPageName)
        ajaxCalls_callServer_specificPage(command, ajaxPageName);
    else
        ajax_callServer(command); //, context

    if (!ajaxCallTimeoutMSec)
        ajaxCallTimeoutMSec = gAjaxCalls_DEFAULT_TIMEOUT_MSEC;

    ajaxCalls_checkTimeout(command, ajaxCallTimeoutMSec, ajaxCallTimeoutMSec, ajaxPageName);
}
//-------------------------------------------------------
function ajaxCalls_checkTimeout(command, timeout, originalTimeout, ajaxPageName) {
    if (gAjaxCalls_CallInProgress) {
        if (timeout <= 0) {
            gAjaxCalls_MustCallAfterTimeoutExpiredRecoveredOKFn_Flag = true;
            
            var trimmedArg = (command.length < 1000) ? command : (command.substring(0, 1000) + '...');

            if (!gAjaxCalls_TimeoutExpiredFn(trimmedArg)) {
                ajaxCalls_receiveCallBackResult(0, 0);
                gAjaxCalls_CallInProgress = false;
                return;
            }
            else
                ajaxCalls_doCallServer(command, originalTimeout, ajaxPageName);
        }

        if (timeout > 0) {
            var timeoutStep = 10;

            setTimeout(
                function() {
                    ajaxCalls_checkTimeout(command, timeout - timeoutStep, originalTimeout, ajaxPageName);
                },
                timeoutStep);
        }
    }
}
//-------------------------------------------------------
function ajaxCalls_receiveCallBackResult(result, context) {
    try {
        if (gAjaxCalls_MustCallAfterTimeoutExpiredRecoveredOKFn_Flag) {
            gAjaxCalls_MustCallAfterTimeoutExpiredRecoveredOKFn_Flag = false;

            if (gAjaxCalls_AfterTimeoutExpiredRecoveredOKFn)
                gAjaxCalls_AfterTimeoutExpiredRecoveredOKFn();
        }
    
        if (!result){
            gAjaxCalls_ArrayFnToExecuteWithCallbackResult.splice(0, 1);
            gAjaxCalls_CallInProgress = false;
            return;
        }

        gAjaxCalls_CallInProgress = false;
        
        var indexSeparator = result.indexOf('|');
        var initialCommand = (indexSeparator > 0) ? result.substring(0, indexSeparator) : result;

        var fnToExecuteWithCallbackResult = gAjaxCalls_ArrayFnToExecuteWithCallbackResult[0];
        gAjaxCalls_ArrayFnToExecuteWithCallbackResult.splice(0, 1);
        
        if (!initialCommand.indexOf('AJAX_FG_'))
            fgProcessCallbackResult(result, context);
        else {
            var indexSeparator2 = result.indexOf('|', indexSeparator + 1);
            var actualResult = (indexSeparator > 0 && indexSeparator2 > 0) ? result.substring(++indexSeparator2) : result.substring(indexSeparator + 1);

            if (fnToExecuteWithCallbackResult) {
                if (initialCommand.indexOf('AJAX_EXCEPTION') == 0)
                    alert('***** EXCEPTION *****\n\n' + actualResult);
                else if (initialCommand.indexOf('SESSION_EXPIRED') == 0) {
                    setTimeout(function() {
                        alert('Your session has expired.\n\nRedirection to login page after clicking OK button...');

                        try {
                            document.location.reload();
                        }
                        catch (e) {
                            alert('ERROR: Unable to reload page automatically.');
                        }

                    }, 0);
                }
                else
                    fnToExecuteWithCallbackResult(actualResult, initialCommand);
            }
        }
    }
    catch (e) {
        alert('EXCEPTION - ajaxCalls_receiveCallBackResult(): ' + e.message);
    }
    
    return false;
}
//-------------------------------------------------------
function ajaxCalls_initHttpRequestObject() {
    if (window.XMLHttpRequest) { // For Mozilla, Safari, Opera, IE7+
        gAjaxCalls_SpecificPage_HttpRequest = new XMLHttpRequest();
        if (gAjaxCalls_SpecificPage_HttpRequest.overrideMimeType) {
            gAjaxCalls_SpecificPage_HttpRequest.overrideMimeType('text/plain');
            //Change MimeType to match the data type of the server response.
            //Examples: "text/xml", "text/html", "text/plain"
        }
    }
    else if (window.ActiveXObject) { // For IE6
        try {
            gAjaxCalls_SpecificPage_HttpRequest = new ActiveXObject("Msxml2.XMLHTTP");
        }
        catch (e) {
            try {
                gAjaxCalls_SpecificPage_HttpRequest = new ActiveXObject("Microsoft.XMLHTTP");
            }
            catch (e) {
            }
        }
    }

    if (!gAjaxCalls_SpecificPage_HttpRequest)
        alert('ERROR - ajaxCalls_initHttpRequestObject(): Your browser does not support AJAX!');
}
//-------------------------------------------------------
function ajaxCalls_callServer_specificPage(command, ajaxPageName) {
    ajaxCalls_initHttpRequestObject();
    
    if (!gAjaxCalls_SpecificPage_HttpRequest)
        return;
    
    gAjaxCalls_SpecificPage_HttpRequest.onreadystatechange = function() {
        ajaxCalls_gotServerResponse_specificPage();
    };
    
    gAjaxCalls_SpecificPage_HttpRequest.open('POST', ajaxPageName + '?CommandAndArgs=' + command, true);
    gAjaxCalls_SpecificPage_HttpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
    gAjaxCalls_SpecificPage_HttpRequest.send('');
}
//-------------------------------------------------------
function ajaxCalls_gotServerResponse_specificPage() {
    if (gAjaxCalls_SpecificPage_HttpRequest.readyState == 4) {
        if (gAjaxCalls_SpecificPage_HttpRequest.status == 200) 
            ajaxCalls_receiveCallBackResult(gAjaxCalls_SpecificPage_HttpRequest.responseText);
    }
}
//-------------------------------------------------------
ajaxCalls_initHttpRequestObject();

