// $Id: remote_data_provider.js 122165 2008-03-14 21:06:49Z cohenaa $
/*
File: remote_data_provider.js
Contains the <RemoteDataProvider> class. Documentation is not complete.

To include the latest version,
> <script type="text/javascript" src="/core/lw/1/js/remote_data_provider.js"></script>

Class: RemoteDataProvider
Wraps up xmlHttp properties and methods in an object for convenience.
*/
//=========================================================================================================
/*
Constructor: RemoteDataProvider()
Constructor initializing RemoteDataProvider object, which gives access to cross-browser methods and makes Http scripting more convenient.

Parameters:
sUrl - (String) The URL of the remote data. 

Example:
(start code)
//Initializes wrapper object used for various xmlHttp methods
var oProvider = new RemoteDataProvider('some_data_source.cgi');
(end)
*/


function RemoteDataProvider(sUrl) {
    this.sUrl = sUrl;
    this.bAsync = true;
    this.iTimeout = 0;
    var oHttpObj = null;
}

RemoteDataProvider.iCount = 0;  // counter of active requests

//-------------------------------------------------------------------------------------------------------------
RemoteDataProvider.prototype.x_GetHttpObj = function() {
    oHttpObj = null;
    try {
        oHttpObj = new ActiveXObject("Msxml2.XMLHTTP");
    } catch(e) {
        try {
            oHttpObj = new ActiveXObject("Microsoft.XMLHTTP")
        } catch(oc) {
            oHttpObj = null;
        }
    }
    if (!oHttpObj && typeof XMLHttpRequest != "undefined") {
        oHttpObj = new XMLHttpRequest();
    }
    return oHttpObj; 
}


//-------------------------------------------------------------------------------------------------------------
RemoteDataProvider.prototype.x_onChange = function(oHttpObj, oTimer) {
    if (oTimer.bTimeout) return;  // timeout is occurred
    
    var iStatus;    // added for 'prototype.Abort" support
    try {
        iStatus = oHttpObj.status;
    } catch (e) {
        return;
    }
    if (oHttpObj.readyState == 4 && iStatus == 200) {
        RemoteDataProvider.iCount--;
//        console.info(oHttpObj.readyState, iStatus, "Success, RemoteDataProvider.iCount=", RemoteDataProvider.iCount);
        if (oTimer.oTimer) clearTimeout(oTimer.oTimer);
        this.onSuccess(oHttpObj);
        this.onStop();    
    } else if(oHttpObj.readyState == 4 && iStatus != 200) {
        RemoteDataProvider.iCount--;
//        console.info("Error, RemoteDataProvider.iCount=", RemoteDataProvider.iCount);
        if (oTimer.oTimer) clearTimeout(oTimer.oTimer);
        this.onError(oHttpObj);
        this.onStop();    
    }
}

//-------------------------------------------------------------------------------------------------------------
RemoteDataProvider.prototype.x_Init = function(oTimer) {
    var oHttpObj = this.x_GetHttpObj();
    if (null == oHttpObj) return null;
    
    if (oHttpObj.readyState != 0) oHttpObj.abort();
    
    var oThis = this;
    if (this.bAsync) {
        oHttpObj.onreadystatechange = function () {
            oThis.x_onChange(oHttpObj, oTimer);
        };
    }
    
    RemoteDataProvider.iCount++;
//    console.info("Start, RemoteDataProvider.iCount=", RemoteDataProvider.iCount);
    this.onStart();
    if (this.iTimeout > 0) {
        oTimer.bTimeout = false;
        oTimer.oTimer = setTimeout(function() {
            RemoteDataProvider.iCount--;
//            console.info("Timeout, RemoteDataProvider.iCount=", RemoteDataProvider.iCount);
            oTimer.bTimeout = true;
            oHttpObj.abort();
            oThis.onTimeout(oThis.iTimeout); 
        }, this.iTimeout);
    }
    
    return oHttpObj;
}


//-------------------------------------------------------------------------------------------------------------
// Abort
/*
Method: Abort()
Aborts an xmlHttp request.

Parameters:
None

Example:
> oProvider.Abort();
*/
RemoteDataProvider.prototype.Abort = function() {
    
    if (RemoteDataProvider.iCount > 0) RemoteDataProvider.iCount--;
//    console.info(oHttpObj.readyState, "Abort, RemoteDataProvider.iCount=", RemoteDataProvider.iCount);
    oHttpObj.abort();
}

//-------------------------------------------------------------------------------------------------------------
// GET request
/*
Method: Get()
Handles a get request.

- Creates xmlHtp object
- Initializes request parameters (xmlHttp.open()) 
- Sends request (xmlHttp.send())
- Handles status codes of xmlHttp object

Parameters:
sRequest - (String) The Query string. 

Working Example:
<http://bender.be-md.ncbi.nlm.nih.gov:6224/core/lw/1/doc/get.html>.
*/
RemoteDataProvider.prototype.Get = function(sRequest) {
    var sUrl = this.sUrl + (sRequest ? sRequest : "");
    var oTimer = {};
    var oHttpObj = this.x_Init(oTimer); 
    
    if (oHttpObj) {
        oHttpObj.open("get", sUrl, this.bAsync);
        oHttpObj.send(null);
        if (!this.bAsync) {
            this.x_onChange(oHttpObj, oTimer);
        }
    }
}

//-------------------------------------------------------------------------------------------------------------
// POST request
/*
Method: Post()
Sets up and executes an xmlHttp post.
*/
RemoteDataProvider.prototype.Post = function(sRequest) {
    this.Request(null, sRequest);
}


//-------------------------------------------------------------------------------------------------------------
// GET + Post request
RemoteDataProvider.prototype.Request = function(sGetRequest, sPostRequest) {
    var sUrl = this.sUrl + (sGetRequest ? sGetRequest : "");
    var oTimer = {};
    var oHttpObj = this.x_Init(oTimer); 
    if (oHttpObj) {
        if (typeof sPostRequest != "string" || sPostRequest == "") {
            sPostRequest = "";
        }
        if (sPostRequest > "") {
            oHttpObj.open("post", sUrl, this.bAsync);
            oHttpObj.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 
            oHttpObj.setRequestHeader("Content-length", sPostRequest.length); 
            oHttpObj.send(sPostRequest);
        } else {
            oHttpObj.open("get", sUrl, this.bAsync);
            oHttpObj.send(null);
        }
        if (!this.bAsync) {
            this.x_onChange(oHttpObj, oTimer);
        }
    }
}


//-------------------------------------------------------------------------------------------------------------
/*
Method: onSuccess()
Place-holder method alerts whether request was successful. You should overwrite this prototype method by assigning your own handler to this.

Parameters:
obj - (Object) The xmlHttp object

Example:
(start code)
var oProvider = new RemoteDataProvider('path_to_some_data_source');
// overwrite the prototype method by assigning it to another function
oProvider.onSuccess = myHanlder;
oProvider.Get('somevalue');

function myHandler(obj) {
    // obj parameter is xmlHttp object passed from Get method
    // now do something with obj, maybe responseText...
}
(end)
*/

RemoteDataProvider.prototype.onSuccess = function(obj) {
    alert(["succes:", obj.responseText]);
}

//-------------------------------------------------------------------------------------------------------------
/*
Method: onStart
Place-holder prototype method alerts when request has started. To run a handler when request has started, assign your handler to this method.

Parameters:
None

Example:
(start code)
// overwrite the prototype method by assigning it to another function
oDataProvider.onStart = function() { 
    alert('The request has started and has not completed yet') 
};
provider.Get('somevalue');
(end)
*/
RemoteDataProvider.prototype.onStart = function() {
//    alert(["start:"]);
}

//-------------------------------------------------------------------------------------------------------------
/*
Method: onStop
Place-holder prototype method alerts when request has stopped. To run a handler when request has stopped, assign your handler to this method.

Parameters:
None

Example:
(start code)
oProvider.onStop = myHandler;

function myHandler(obj){
    //do something when request stops
}
(end)
*/
RemoteDataProvider.prototype.onStop = function() {
//    alert(["start:"]);
}

//-------------------------------------------------------------------------------------------------------------
/*
Method: onError
Place-holder prototype method alerts when an error has occured. To run a handler when a request returns error, assign your handler to this method.

Parameter:
obj - (Object) xmlHttp request object

Example:
(start code)
oProvider.onError = genError;

function genError(obj){
    //do something with the error
}
(end)
*/
RemoteDataProvider.prototype.onError = function(obj) {
    alert(["error:", obj.status]);
}

//-------------------------------------------------------------------------------------------------------------
/*
Method: onTimeout
Place-holder prototype method alerts when a timeout has occured. To run a handler when server timeout occurs, assign your handler to this method.

Parameter:
iTime - (Integer) The amount in miliseconds before timeout occurs 

Example:
(start code)
oProvider.onTimeOut = myTimeoutHandler;

function myTimeoutHandler(){
   // do something if timeout occurs 
}

(end)
*/
RemoteDataProvider.prototype.onTimeout = function(iTime) {
    alert(["timeout:", iTime + " ms"]);
}

