/*
  AJAX utility - version 0.1
  by Diagonal Software, Inc.
  http://www.diagonalsoftware.com/

  The AjaxRequest class provides cross-platform support for making
  multiple asynchronous XMLHttpRequests per browser window and for
  executing Javascript code upon completion of the requests.

  Asynchronous calls can be interrupted by window-close and
  page-reload events, creating errors and communication problems with
  the server. Javascript's callback function style of programming and
  lack of explicit threading make it difficult to poll multiple
  requests to determine if they have completed and that it's safe to
  execute more code. This library provides a mechanism for doing this.

  Detailed Features: 
  - an AjaxRequest class for asynchronous XMLHttpRequest sending
  - user-defineable 'onData' and 'onError' response handlers.
  - 'afterRequestsDo(...)' interface for delaying further execution

  Simple Example:
  
    // define prototype function to handle the XMLHttpRequest response
    AjaxRequest.prototype.onData  = function(req) { 
        alert('got data:'+req.responseText); 
    };

    // Instantiate the request. Done.
    var r = new AjaxRequest("POST","http://localhost/","foo=bar");

  Example of waiting for requests to complete:

    // after the 'Simple Example' code above, add a function
    // that contains the code you want to execute. It must take 
    // a single argument (which your code can ignore if it wants).

    function doMore(doMoreArg) {
        var url = doMoreArg.url;
        var foo = doMoreArg.foo; // do nothing with it!
        location.href = url;
    }

    // wrap the function and argument you defined, along with a
    // timeout (in millis) setting, and it's guaranteed not to be
    // executed until all your requests come back or the timeout is
    // hit.
    AjaxRequest.afterRequestsDo(doMore,doMoreArg,3000);

        // Usually you would put all this in an event handler, such as:

    <input type="button" value="Reload" 
           onclick="AjaxRequest.afterRequestsDo(doMore,doMoreArg,3000)">

        // or if all that's too much typing for you...

    function doMore() {
            var doMoreArg = { url : '...', foo : '...' };
        AjaxRequest.afterRequestsDo(function(a) { location.href = a.url; },doMoreArg,3000);
    }
    ...
    <input type="button" value="Reload" onclick="doMore()">
*/

/*
  The main AJAX Request Class Definition.
*/

function AjaxRequest(rMethod, rUrl, rBody) {
        this.method = rMethod;
        this.url    = rUrl;
        this.body   = rBody;
        this.id = AjaxRequest.addRequest(this);
        this.load();
}

// instance variables

AjaxRequest.prototype.method    = "GET";
AjaxRequest.prototype.url       = undefined;
AjaxRequest.prototype.body      = undefined;
AjaxRequest.prototype.onData    = undefined; // processor method (passed in)
AjaxRequest.prototype.onError   = function(req) { };
AjaxRequest.prototype.error     = undefined;
AjaxRequest.prototype.req       = undefined;
AjaxRequest.prototype.id        = undefined;

// instance methods

AjaxRequest.prototype.load = function() {
        this.req = this.getXMLHttpRequest();
        var arObj = this;
        this.req.onreadystatechange = function() { arObj.statechange(); };
        this.req.open(this.method, this.url, true);
        if (this.method == "POST")
                this.req.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
        this.req.send(this.body);
};

AjaxRequest.prototype.getXMLHttpRequest = function() {
        if (this.req != undefined)
                return this.req;

    if (window.ActiveXObject) {
        try {
                this.req = new ActiveXObject("Msxml2.XMLHTTP");
        } catch(e) {
                try {
                        this.req = new ActiveXObject("Microsoft.XMLHTTP");
                } catch(e) {
                        this.req = undefined;
                }
                }
    } else if (window.XMLHttpRequest) {
                try {
                        this.req = new XMLHttpRequest();
        } catch(e) {
                        this.req = undefined;
        }
        }
        return this.req;
};

AjaxRequest.prototype.statechange = function() {
        try {
                if (this.req.readyState == 4) {
                        if (this.req.status == 200) {
                                this.onData(this.req);
                                AjaxRequest.delRequest(this.id);
                        } else {
                                this.onError(this.req);
                                this.error = "ERROR: Request status code: "+this.req.status;
                                AjaxRequest.delRequest(this.id);
                        }
                } 
        } catch (reqE) {
                this.onError(this.req);
                this.error = "ERROR: "+reqE.name+". Message: "+reqE.message;
                AjaxRequest.delRequest(this.id);
        }
};

AjaxRequest.prototype.abort = function() {
        var obj = AjaxRequest.activeRequests[this.id];
        if (obj.req)
                req.abort();
        AjaxRequest.delRequest(this.id);
};

// class vars and methods

AjaxRequest.activeRequests = new Array();

AjaxRequest.addRequest = function(r) {
        AjaxRequest.activeRequests.push(r);
        return AjaxRequest.activeRequests.length - 1;
};

AjaxRequest.delRequest = function(i) {
        AjaxRequest.activeRequests.splice(i,1);
};

AjaxRequest.afterRequestsDo = function(doFunc,doFuncArg,timeoutMillis) {
        var d = new Date();
        AjaxRequest.intervalTimeout = d.getTime() + timeoutMillis;
        AjaxRequest.intervalFunction = doFunc;
        AjaxRequest.intervalFunctionObj = doFuncArg;
        AjaxRequest.intervalID = setInterval(AjaxRequest.intervalFunctionWrapper,500);
};

// private
AjaxRequest.intervalFunctionWrapper = function() {
        var curDate = new Date();
        if (AjaxRequest.activeRequests.length == 0 || 
                    curDate.getTime() > AjaxRequest.intervalTimeout) {
                clearInterval(AjaxRequest.intervalID);
                AjaxRequest.intervalFunction(AjaxRequest.intervalFunctionObj);
        }
}