/// @file spwChat.js
/// @brief Class for Javascript with AJAX technology\n
///        needs a backend. \n
///
/// @verbatim
/// @endverbatim
///
/// @author Leo Eibler
/// @date 20051217 le@sprossenwanne.at \n
///                created \n
/// @date 20051218 le@sprossenwanne.at \n
///                bugfix \n
/// @date 20051219 le@sprossenwanne.at \n
///                queuing system for requests ... nothing get loose ;-) \n
///                now this is a "class" \n
///                bugfix (only update if new input) \n
///                replaced "bla = innerHTML + bla" with prepending new dom-nodes
/// @date 20060303 le@sprossenwanne.at \n
///                added timeout handler \n
///                customizeable auto-refresh-function \n
///                doxygen comments for all functions and variables \n
/// @date 20060410 le@sprossenwanne.at \n
///                bugfixing timeout handler \n
/// @date 20060415 le@sprossenwanne.at \n
///                added variablelist to pass thru to response function using  spw_chat_addRequestAdvanced function \n
///
/// thanx goes to alpha600 - http://alpha.rrs.at and apple - http://developer.apple.com/internet/webcontent/xmlhttpreq.html
///
/// This Software is for free use. Distributet under GPL.
///
/// got from: http://www.eibler.at/
///

function spwChat( RpcUrl, outputEl ) {
    /// @brief if browser is Internet Explorer this is true
    var reqIsIE = false;
    
    /// @brief XMLHttpRequest Object
    var reqObj = false;
    /// @brief if a request is already in progress, this is true
    var requestInProgress = false;
    /// @brief url to connect to
    var javaRpcUrl = RpcUrl;
    /// @brief Request-queue array
    var requestQueue = new Array();
    /// @brief Number of requests in queue
    var requestQueueCount = 0;
    /// @brief Start default timeout handler spw_DefaultTimeoutHandler after timeout milliseconds
    var requestTimeout = 1000;
    /// @brief If response was successfull (readyState=4, status=200) process handler only if valid XML (false) or always (true)
    /// true ..... Always process handler
    /// false .... Process handler only if valid xml
    var dontCareAboutXMLValid = false;
    /// @brief unused at the moment
    var outputElement = outputEl;
    /// @brief if auto refresh is on (call spw_chat_refreshme()) this function is started every reqRefreshRate milliseconds
    var reqRefreshRate = 1000;
    /// @brief if auto refresh is on (call spw_chat_refreshme()) a http request is done to the url javaRpcUrl+periodicRefreshAction
    var periodicRefreshAction = "";
    
    /// @brief sets the outputElement
    this.setOutputElement = function( outputEl ) {
        outputElement = outputEl;
    }
    
    /// @brief sets the url to connect to
    this.setRpcUrl = function( RpcUrl ) {
        javaRpcUrl = RpcUrl;
    }
    
    /// @brief sets the auto-refresh-rate to refreshrate milliseconds
    this.setReqRefreshRate = function( refreshrate ) {
        reqRefreshRate = refreshrate;
    }
    
    /// @brief sets the action to call the javaRpcUrl with (if auto refresh is on)
    this.setPeriodicRefreshAction = function( refreshAction ) {
        periodicRefreshAction = refreshAction;
    }
    
    /// @brief sets standard timeout to timeout seconds
    this.setTimeout = function( timeout ) {
        requestTimeout = timeout*1000;
    }
    
    this.setDontCareAboutValidXML = function( yes ) {
       dontCareAboutXMLValid  = yes;
    }
   
    /// @brief creates an instance of XMLHttpRequest and sets the reqIsIE flag
    /// @return instance of XMLHttpRequest or false if browser don't know what it is
    function spw_chat_getReqObject() {
        // branch for native XMLHttpRequest object
        if( window.XMLHttpRequest ) {
          try {
            reqObj = new XMLHttpRequest();
            reqObj.onreadystatechange = spw_DefaultResponseHandler;
            reqIsIE = false;
          } catch(e) {
            reqObj = false;
          }
        // branch for IE/Windows ActiveX version
        } else if( window.ActiveXObject ) {
            reqIsIE = true;
            try {
              reqObj = new ActiveXObject("Msxml2.XMLHTTP");
            } catch(e) {
              try {
                  reqObj = new ActiveXObject("Microsoft.XMLHTTP");
              } catch(e) {
                  reqObj = false;
              }
            }
            if( reqObj ) {
                reqObj.onreadystatechange = spw_DefaultResponseHandler;
            }
        }
        return reqObj;
    }
    
    /// @brief adds requests to a sending queue ...
    this.spw_chat_addRequest = function( action, handler, postData ) {
        if( requestQueueCount > 0 ) {
            // check if we have exactly this request in our queue (as last element)
            if( ( requestQueue[requestQueueCount-1]["action"] == action ) &&
                ( requestQueue[requestQueueCount-1]["handler"] == handler ) &&
                ( requestQueue[requestQueueCount-1]["postData"] == postData ) ) {
                // yes, we don't need to process it twice ;-)
                return false;
            }
        }
        requestQueue[requestQueueCount] = new Array();
        requestQueue[requestQueueCount]["action"] = action;
        requestQueue[requestQueueCount]["handler"] = handler;
        requestQueue[requestQueueCount]["postData"] = postData;
        requestQueue[requestQueueCount]["timeout"] = requestTimeout;
        requestQueue[requestQueueCount]["timeoutHandler"] = spw_Nothing;
        requestQueue[requestQueueCount]["parameterlist"] = "";
        requestQueueCount++;
        return requestQueueCount;
    }
    
    /// @brief adds requests to a sending queue and use user time out handler and timeout in seconds ...
    this.spw_chat_addRequestAndTimeout = function( action, handler, postData, timeout, timouthandler ) {
        reqCount = this.spw_chat_addRequest( action, handler, postData );
        if( reqCount ) {
            requestQueue[reqCount-1]["timeout"] = timeout*1000;
            requestQueue[reqCount-1]["timeoutHandler"] = timouthandler;
            return reqCount;
        }
        return false;
    }
    
    /// @brief adds requests to a sending queue and use user time out handler and timeout in seconds and parameterlist...
    this.spw_chat_addRequestAdvanced = function( action, handler, postData, timeout, timouthandler, parameterlist ) {
        reqCount = this.spw_chat_addRequestAndTimeout( action, handler, postData, timeout, timouthandler );
        if( reqCount ) {
            requestQueue[reqCount-1]["parameterlist"] = parameterlist;
            return reqCount;
        }
        return false;
    }
    
    /// @brief sends a xmlhttp request to our rpc script \n
    // got from apple developer sites http://developer.apple.com/internet/webcontent/xmlhttpreq.html
    this.spw_chat_sndReq = function( ) {
        if( requestInProgress ) {
            // if a request is already in progress ... skip
            // we store all (different) requests in a queue ... 
            return;
        }
        if( requestQueueCount <= 0 ) {
            // we have no requests in queue ... skip
            return;
        }
        if( !spw_chat_getReqObject() ) {
            // sorry, this machine doesn't know what xmlHttpRequest is ...
            return;
        }
        // we process our requests with FIFO principle ... so index 0 is the first request
        var postData = requestQueue[0]["postData"];
        var url = javaRpcUrl+requestQueue[0]["action"];
        if( reqObj ) {
            requestQueue[0]["timeoutCode"] = setTimeout( spw_DefaultTimeoutHandler, requestQueue[0]["timeout"] );
            if( !reqIsIE ) {
                // native xmlhttprequest object
                if( postData == "" ) {
                    // we have no POST data ... do a GET call
                    reqObj.open( "GET", url, true );
                    reqObj.send( null );
                } else {
                    // there is some POST data ... do a POST call
                    reqObj.open( "POST", url );
                    reqObj.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );
                    reqObj.send( postData );
                }
            } else {
                // IE/Windows xmlhttprequest object
                if( postData == "" ) {
                    // we have no POST data ... do a GET call
                    reqObj.open( "GET", url, true );
                    reqObj.send( );
                } else {
                    // there is some POST data ... do a POST call
                    reqObj.open( "POST", url );
                    reqObj.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' );
                    reqObj.send( postData );
                }
            }
            requestInProgress = true;
        } 
    }
    
    /// @brief gets the XMLHttpRequest object
    this.getReqObj = function() {
        return reqObj;
    }
    
    /// @brief return the parameterlist for current request (set with spw_chat_addRequestAdvanced)
    this.getParameterlist = function() {
        return requestQueue[0]["parameterlist"];
    }
    
    /// @brief called by XMLHttpRequest object after request is done. \n
    /// clears the timeout handler and call the user specified request response handler
    function spw_DefaultResponseHandler() {
        // only if reqObj shows "loaded"
        if( reqObj.readyState == 4) {
            // only if "OK"
            if( reqObj.status == 200) {
                if( dontCareAboutXMLValid || reqObj.responseXML ) {
                    clearTimeout( requestQueue[0]["timeoutCode"] );
                    //try {
                    requestQueue[0]["handler"]();
                    //} catch(e) {}
                } 
                if( requestQueueCount > 0 ) {
                    requestQueueCount--;
                }
                requestQueue.shift();
            }
            requestInProgress = false;
        }
    }
    
    function spw_Nothing() {
    }
    
    /// @brief called after timout milliseconds if no response or bad response (e.g. 404 not found) \n
    /// starts user specified time out handler
    function spw_DefaultTimeoutHandler() {
        try {
            if( requestQueue[0]["timeoutHandler"] ) {
                requestQueue[0]["timeoutHandler"]();
            }
        } catch(e) {}
    }
    
    /// @brief example how to deal with xml response
    function spw_chat_postProcess( ) {
        var length;
        var sub;
        var i;
        length = reqObj.responseXML.getElementsByTagName("dataroot").length;
        for( i=0; i<length; i++ ) {
            sub = reqObj.responseXML.getElementsByTagName("dataroot").item(i).firstChild.nodeValue;
            if( sub.length > 0 ) {
                // do something
            }
        }
    }
    
    /// @brief auto-refresh-function ... calls spw_chat_sndReq() every reqRefreshRate milliseconds. \n
    /// Is used for periodically refreshes (you have to set periodicRefreshAction)
    var spw_chat_refreshme = function () {
        // we want to hear what's new on the line ...
        if( periodicRefreshAction != "" ) {
            spw_chat_addRequest( periodicRefreshAction, spw_chat_postProcess, "" );
        }
        // always send request
        spw_chat_sndReq();
        setTimeout( spw_chat_refreshme, reqRefreshRate );
    }
    
    /// @brief key handler for some special keys
    function spw_chat_pushme( e ) {
        if( !e ) {
            e = window.event;
        }
        if( e.keyCode == 13 ) {
            // if code for ENTER received ... send our text
        }
        if( e.keyCode == 9 ) {
            // tab key
        }
    }  
}

