// XMLapi.js
//
// General utilities for AJAX calls 
//
// To initialize, call initXMLapi();
//
// Author: Mike Bergsma
//
// Modifications:
//
//    $Log: XMLapi.js,v $
//    Revision 1.21  2009-01-24 15:23:56  bergsma
//    Better timeout handling
//
//    Revision 1.20  2008-06-29 18:29:11  bergsma
//    *** empty log message ***
//
//    Revision 1.19  2008-05-24 17:56:55  bergsma
//    no message
//
//    Revision 1.18  2008-02-17 03:54:51  bergsma
//    no message
//
//
// READYstate
// 0 (Uninitialized) The object has been created, but not initialized (the open method has not been called). 
// 1 (Open) The object has been created, but the send method has not been called. 
// 2 (Sent) The send method has been called, but the status and headers are not yet available. 
// 3 (Receiving) Some data has been received.  
// 4 (Loaded) All the data has been received, and is available. 
 
function initXMLapi()
{
  return ;
}

function HttpXMLRequest( )
{
  var self = this ;
  var name = 'unknown' ;
  var success_handler = '' ;
  var timeout_handler = '' ;
  var timer = null ;
  var reqData = null ;
  var STATUS = 0 ;
  var READYstate = 0 ;
  var rspText = "" ;
  var rspXML = null ;
  var request = null ;
  
  if ( window.XMLHttpRequest ) {
    try {
      request = new XMLHttpRequest();
    } 
    catch(e) {
      request = null ;
    }
    // branch for IE/Windows ActiveX version
  } 
  else if ( window.ActiveXObject ) {
    try {
      request = new ActiveXObject("Msxml2.XMLHTTP");
    }
    catch(e) {
      try {
        request = new ActiveXObject("Microsoft.XMLHTTP");
      } 
      catch(e) {
        request = null ;
      }
    }
  } 

  // Define some dynamic functions

  this.setSuccessHandler = function( successHandler )
  {
    success_handler = successHandler ;
  } ;

  this.setTimeoutHandler = function( timeoutHandler )
  {
    timeout_handler = timeoutHandler ;
  } ;

  this.setName = function ( myName )
  {
    name  = myName ;
  } ;

  this.getName = function( )
  {
    return name ;
  } ;

  this.responseText = function()
  {
     return rspText ;
  } ;
   

  this.responseXML = function()
  {
     return rspXML ;
  } ;
   
  this.abort = function() 
  {
    debug('aborting '+name+' request',2);
    try {
      request.abort() ;
    }
    catch(e) {
    }
    self.reset() ;
  } ;

  this.reset = function()
  {
    self.clearTimer() ;
    READYstate = 0 ;
    STATUS = 0 ;
  } ;

  this.getStatus = function()
  {
    return STATUS ;
  }

  this.getReadyState = function()
  {
    return READYstate ;
  }

  this.setTimer = function( ms )
  {
     timer = window.setTimeout( self.timeout, ms ) ;
  } ;

  this.clearTimer = function( ms )
  {
    if ( timer != null ) {
      window.clearTimeout( timer ) ;
      timer = null ;
    }
  } ;

  this.timeout = function()
  {
    if ( timer != null ) {
      debug('%TIMEOUT: on request object named '+name,2);
      self.abort() ;
      if ( timeout_handler != "" ) {
        eval( timeout_handler + '( self )' );
      }
    }
  } ;

  this.change = function() 
  {
    try {
      var RS = request.readyState ;
      READYstate = RS ;
    }
    catch(e) {
      for(var a in e) {
        debug(a + '=' + e[a],1);
      }
      debug('Failed to get request readyState',1);
    }
 

    if ( READYstate != 4 ) return ;

    // DATA has been loaded

    self.clearTimer() ;
    try {
      STATUS = request.status ;      
    }
    catch(e) {
      for(var a in e) {
        debug(a + '=' + e[a],1);
      }
      debug('No request status for '+name,1)
      self.reset() ;
      return ;
    }

    debug( "Ready=4, status="+STATUS+",name="+name,3);

    if ( STATUS != 200 ) { 
      self.reset(); 
      return ; 
    }

    // STATUS == 200

    try {
      rspText = request.responseText ;  
      //debug( rspText,3 );
    } 
    catch(e) {
      for(var a in e) {
        debug(a + '=' + e[a],1);
      }
      rspText = "" ;  
    }
    //debug( "=>"+rspText,3 );
    try {
      rspXML = request.responseXML ;  
    } 
    catch(e) {
      for(var a in e) {
        debug(a + '=' + e[a]);
      }
      rspXML = null ;
    }
    //debug("has xml= "+rspXML,3 );

    if ( success_handler != "" ) {
      debug( "SUCCESS, calling "+success_handler,3);
      self.reset() ;
      eval( success_handler + '( self );' );
    }	
  };

  this.loadXMLDocAsync = function( verb,url,data,ms )
  {
    READYstate = 1 ;

    if ( ms != 0 ) self.setTimer ( ms ) ;

    var url_rand = url + ((url.indexOf("?") == -1) ? "?" : "&" ) + 
    	"rand=" + parseInt(Math.random()*99999999);

    //debug('Opening request channel to '+url_rand,3 );
    request.open(verb, url_rand, true);

    //debug( 'Setting change handler',3 );
    request.onreadystatechange = self.change ;
 
    //debug('Setting Request Headers',3 );

    if ( verb == "POST" ) {
      //debug( 'text/xml',3 );
      request.setRequestHeader("Content-Type", "text/xml") ;
    }
    //request.setRequestHeader ( "Pragma", "no-cache" ) ;
    //request.setRequestHeader ( "Cache-Control", "no-cache" ) ;
    request.setRequestHeader ( "Connection", "keep-alive" ) ;
    request.setRequestHeader ( "Keep-Alive", "300" ) ;
    request.setRequestHeader ( "Proxy-Connection", "keep-alive" ) ;
    //debug('Request headers set',3 );

    /*
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.7.12)...
Accept: text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,...
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
    */

    reqData = data ;

    try {
      request.send( reqData ) ;
    } 
    catch(e) {
      for(var a in e) {
        debug(a + '=' + e[a]);
      }
      request.reset() ;
      //disablePolling ;
    }

  } ;

  this.loadXMLDocSync = function ( verb,url,data,ms )
  {
    READYstate = 1 ;

    if ( ms != 0 ) self.setTimer ( ms ) ;

    var url_rand = url + ((url.indexOf("?") == -1) ? "?" : "&" ) + 
	"rand=" + parseInt(Math.random()*99999999);

    request.open( verb, url_rand, false );

    if ( verb == "POST" ) request.setRequestHeader("Content-Type", "text/xml") ;
    //request.setRequestHeader ( "Pragma", "no-cache" ) ;
    //request.setRequestHeader ( "Cache-Control", "no-cache" ) ;
    request.setRequestHeader ( "Keep-Alive", "300" ) ;
    request.setRequestHeader ( "Proxy-Connection", "keep-alive" ) ;
    request.setRequestHeader ( "Connection", "keep-alive" ) ;

    reqData = data ;

    try {
      request.send( reqData ) ;
    } 
    catch(e) {
      for(var a in e) {
        debug(a + '=' + e[a]);
      }
      request.reset() ;
      //disablePolling ;
      return ;
    }

    self.change() ;
  } ;

  return ;
}
// retrieve text of an XML document element, including
// elements using namespaces
function getElementTextNS(prefix, local, parentElem, index) 
{
  var result = "";
  if (prefix && isIE) {
    // IE/Windows way of handling namespaces
    result = parentElem.getElementsByTagName(prefix + ":" + local)[index];
  } 
  else {
    // the namespace versions of this method 
    // (getElementsByTagNameNS()) operate
    // differently in Safari and Mozilla, but both
    // return value with just local name, provided 
    // there aren't conflicts with non-namespace element
    // names
    result = parentElem.getElementsByTagName(local)[index];
  }
  if (result) {
    // get text, accounting for possible
    // whitespace (carriage return) text nodes 
    if (result.childNodes.length > 1) {
      return result.childNodes[1].nodeValue;
    } 
    else {
      return result.firstChild.nodeValue;    		
    }
  }
  else {
    return "n/a";
  }
}

// retrieve node of an XML document element, including
// elements using namespaces
function getElementNodeNS(prefix, local, parentElem, index) 
{
  var result = null ;
  if (prefix && isIE) {
    // IE/Windows way of handling namespaces
    result = parentElem.getElementsByTagName(prefix + ":" + local)[index];
  } 
  else {
    // the namespace versions of this method 
    // (getElementsByTagNameNS()) operate
    // differently in Safari and Mozilla, but both
    // return value with just local name, provided 
    // there aren't conflicts with non-namespace element
    // names
    result = parentElem.getElementsByTagName(local)[index];
  }
  if ( result ) return result.childNodes ;
}


