

g_fOriginalErrorHandler = window.onerror;
window.onerror = remoteCallJavascriptErrorHandler;

function remoteCallJavascriptErrorHandler(sMessage, sURL, nLine)
{
  try
  {
    // répération de la stack trace
    var sStackTrace = getStackTrace(1);
    // envoi de l'erreur sur le serveur dans le but de l'insérer dans le log
    remoteCall("custom::remote::js_remote_log",
               "logError",
               sMessage,
               sURL,
               nLine,
               navigator.userAgent,
               sStackTrace);
    
    pDBConsole.error("Message:"+sMessage+"\n"+
                     "URL:"+sURL+"\n"+
                     "Line:"+nLine+"\n"+
                     "StackTrace:\n"+sStackTrace);
  }
  // que faire si on ne peut pas logger l'erreur sur le serveur ?
  catch(ex)
  {
  }
  // renvoyer cette erreur
  if( g_fOriginalErrorHandler )
    g_fOriginalErrorHandler(sMessage, sURL, nLine);
}

/**
 * Appel d'un "remote" resalys, en formatant les paramètres
 *  afin qu'ils soient pris en compte dans le remote.
 */
function remoteCall(sClassName)
{
  var aArgs = remoteCall.arguments;
  // on prépare les paramètres en les récupérant des paramétres passés à cette fonction
  var aParams = new Array();
  for(var i=1;i<aArgs.length;i++)
  {
    var sArg = aArgs[i];
    
    var sCompressedArg = '';
    // si c'est un XML je compresse
    try
    {
      if( window.pConfig && pConfig.getVarValue('use_browser_compression') > 0 &&
          getRegExp( /^<\?xml/ ).exec( sArg ) )
      {
        var sGzipArg = compressContent( sArg );
        if( sGzipArg != null )
          sCompressedArg = "_gzip:" + sGzipArg;
      }
    }
    catch(ex){}
    
    if( sCompressedArg != null && sCompressedArg != '' )
      aParams.push( sCompressedArg );
    else
      aParams.push( sArg );
  }

  var sURL = createRemoteCallURL(sClassName, aParams);
  var sResponse = AJAXCallURL( sURL );
  return evalRemoteCallResponse(sResponse);
}

function remoteCallWait(sClassName, pCallBackInstance, pCallBackFunction, pCallBackErrorInstance, pCallBackError, sWaitMessage, bCanCancel)
{
  var aArgs = remoteCallWait.arguments;
  // on prépare les paramètres en les récupérant des paramétres passés à cette fonction
  var aParams = new Array();
  for(var i=7;i<aArgs.length;i++)
  {
    var sArg = aArgs[i];
    
    var sCompressedArg = '';
    // si c'est un XML je compresse
    try
    {
      if( pConfig && pConfig.getVarValue('use_browser_compression') > 0 &&
          getRegExp( /^<\?xml/ ).exec( sArg ) )
      {
        var sGzipArg = compressContent( sArg );
        if( sGzipArg != null )
          sCompressedArg = "_gzip:" + sGzipArg;
      }
    }
    catch(ex){}
    
    if( sCompressedArg != null && sCompressedArg != '' )
      aParams.push( sCompressedArg );
    else
      aParams.push( sArg );
  }
  
  var sURL = createRemoteCallURL(sClassName, aParams);

  var pAJAXRequest = AJAXCallURL( sURL, getRemoteCallAsyncCallBack(pCallBackInstance, pCallBackFunction, pCallBackErrorInstance, pCallBackError) );
  
  showWaitLayer('wait_layer', sWaitMessage);
  // recherche du bouton stop pour annuler la requête en cours
  var pStopButton = getDOMObject('cancel_request_button');
  if( pStopButton )
  {
    if( bCanCancel )
    {
      pStopButton.onclick = getCancelRequestHandlerFunction(pAJAXRequest, pCallBackInstance, pCallBackFunction, pCallBackErrorInstance, pCallBackError);
      pStopButton.style.visibility = 'visible';
    }
    else
      pStopButton.style.visibility = 'hidden';
  }
}

function createRemoteCallURL(sClassName, aParams)
{
  var sURL = serverURL+'&mime_type=text/plain&';
  sURL += 'class=' + sClassName + '&';
  for( var i=0 ; i < aParams.length ; i++ )
  {
    if(aParams[i] === false)
      aParams[i] = 0;
    if(aParams[i] === true)
      aParams[i] = 1;
    var iIndex = i+1;
    sURL += 'arg' + iIndex + '=' + ( aParams[i] != null ? encodeURIComponent(aParams[i]) : '' ) + '&';
  }
  sURL += 'num_args=' + (aParams.length);
  return sURL;
}

function evalRemoteCallResponse(sResponse)
{
  // eval the server response
  var pRet;
  try
  {
    eval( String(sResponse) );
  }
  catch(e)
  {
    throw new RemoteCallException(e, sResponse);
  }

  if( pRet === undefined )
    throw new RemoteCallException(null, 'Invalid remote call response: '+sResponse);
  
  if( pRet instanceof RemoteCallException ||
      pRet instanceof CheckerException )
    throw pRet;

  return pRet;
}

function getCancelRequestHandlerFunction(pAJAXRequest, pCallBackInstance, pCallBackFunction, pCallBackErrorInstance, pCallBackError)
{
  return function()
  {
    // on note que cette requete est annulée car lorsque l'on va appeler
    //  la méthode abort, le système va appeler le ready-state handler et
    //  ce dernier ne doit pas rappeler les callback en cas d'annulation
    pAJAXRequest.setCanceled(true);
    
    var pRequest = pAJAXRequest.getRequest();
    pRequest.abort();
    
    // on cache la layer
    hideWaitLayer('wait_layer');

    // on appel le callback
    //  en lui signalant l'annulation
    try
    {
      if(pCallBackInstance)
        pCallBackFunction.call(pCallBackInstance, '', true );
      else
        pCallBackFunction( '', true );
    }
    catch(ex)
    {
      pCallBackError.call(pCallBackErrorInstance, ex);
    }
    // retourne false pour éviter que le bonton n'efectue l'appel de
    //  son lien par défaut (href)
    return false;
  };
}

function getRemoteCallAsyncCallBack(pCallBackInstance, pCallBackFunction, pCallBackErrorInstance, pCallBackError)
{
  return function(sRequestResult, pAJAXRequest)
  {
    // si pas annulé (en cas d'annulation tout a déjà été géré par le onClick)
    if( !pAJAXRequest.isCanceled() )
    {
      hideWaitLayer('wait_layer');
  
      var nTime = getCurrentDate().getTime();
      try
      {
        var pRequest = pAJAXRequest.getRequest();
        if( pRequest.status == 200 )
        {
          if(pCallBackInstance)
            pCallBackFunction.call(pCallBackInstance, evalRemoteCallResponse(sRequestResult), false );
          else
            pCallBackFunction( pAJAXRequest.isCanceled() ? '' : evalRemoteCallResponse(sRequestResult), false );
        }
        else
          pCallBackError.call(pCallBackErrorInstance, new Error("Invalid server response status: "+pRequest.status));
      }
      catch(ex)
      {
        pCallBackError.call(pCallBackErrorInstance, ex);
      }
      //alert(new Date().getTime() - nTime);
    }
  }
}

/**
 * RemoteCallException
 */

RemoteCallException.prototype = new CheckerException();
RemoteCallException.prototype.constructor = RemoteCallException;
RemoteCallException.superclass = CheckerException.prototype;

function RemoteCallException(pException, sScriptError)
{
  this.toString = RemoteCallException_toString;
  this.getErrorNumber = RemoteCallException_getErrorNumber;
  this.getStackTrace = RemoteCallException_getStackTrace;
  this.getSessionInfo = RemoteCallException_getSessionInfo;
  this.getMessage = RemoteCallException_getMessage;
  this.sScriptError = sScriptError;
  this.sMessage = sScriptError;
  this.nErrorNumber = 0;
  this.sStackTrace = "";
  this.sSessionInfo = "";
}

function RemoteCallException_toString()
{
  return this.nErrorNumber + ": " + this.sMessage;
}

function RemoteCallException_getMessage()
{
  return this.getSessionInfo()+"\n"+RemoteCallException.prototype.getMessage.call(this)+"\n"+this.getStackTrace();
}

function RemoteCallException_getErrorNumber()
{
  return this.nErrorNumber;
}

function RemoteCallException_getStackTrace()
{
  return this.sStackTrace;
}

function RemoteCallException_getSessionInfo()
{
  return this.sSessionInfo;
}

/*
 *  AJAX stuff
 *
 *  Originally ripped from an IBM tutorial:
 *  http://www-128.ibm.com/developerworks/library/j-ajax1/?ca=dgr-lnxw01Ajax
 */

/*
 * Returns a new XMLHttpRequest object, or false if this browser
 * doesn't support it
 */
function newXMLHttpRequest()
{
  var xmlreq = false;

  if( window.XMLHttpRequest )
  {
    // Create XMLHttpRequest object in non-Microsoft browsers
    xmlreq = new XMLHttpRequest();
  }
  else if( window.ActiveXObject )
  {
    // Create XMLHttpRequest via MS ActiveX
    try
    {
      // Try to create XMLHttpRequest in later versions of Internet Explorer
      xmlreq = new ActiveXObject("Msxml2.XMLHTTP");
    }
    catch( e1 )
    {
      // Failed to create required ActiveXObject
      try
      {
        // Try version supported by older versions of Internet Explorer
        xmlreq = new ActiveXObject("Microsoft.XMLHTTP");
      }
      catch( e2 )
      {
        // Unable to create an XMLHttpRequest with ActiveX
      }
    }
  }

  return xmlreq;
}

/*
 * Returns a function that waits for the specified XMLHttpRequest
 * to complete, then passes its XML response to the given handler function.
 *   pRequest         : The XMLHttpRequest whose state is changing
 *   pResponseHandler : Function to pass the XML response to
 *   bCheckStatus     : Throws an error for bad statuses
 *   nTimeoutID       : Index of the timeout timeout
 *   bUseXML          : Returns an XML object instead of text
 */
function getReadyStateHandler( pAJAXRequest, pResponseHandler, bCheckStatus, nTimeoutID, bUseXML )
{
  if( !pAJAXRequest )
    throw new Error( "Error, asynchronous call back called without valid XMLHTTP object" );
  if( !pResponseHandler )
    throw new Error( "Error, asynchronous call back called without valid callback function" );
  
  // Return an anonymous function that listens to the XMLHttpRequest instance
  return function ()
  {
    var pRequest = pAJAXRequest.getRequest();
    // If the request's status is "complete"
    if( pRequest.readyState == 4 )
    {
      if( nTimeoutID )
        window.clearTimeout( nTimeoutID );
      
      try
      {
        // Check that a successful server response was received
        if( !bCheckStatus || pRequest.status == 200 )
        {
          // Pass the XML/Text payload of the response to the handler function
          pResponseHandler( bUseXML ? pRequest.responseXML : pRequest.responseText, pAJAXRequest );
        }
        else
        {
          // An HTTP problem has occurred
          throw new Error( "HTTP error: " + pRequest.status );
        }
      }
      catch( ex )
      {
        // pRequest.status n'est pas défini parfois
        //throw new Error( "Error while retrieving the response from the server" );
      }
    }
  }
}

/*
 * Returns a function to cancel the remote call
 *   pRequest : The XMLHttpRequest whose state is changing
 */
function getTimeoutHandler( pRequest )
{
  // Return an anonymous function that listens to the XMLHttpRequest instance
  return function ()
  {
    // pas la peine de vérifier le reste?
    if( pRequest == null || pRequest.readyState == 4 )
      return;
    else
      pRequest.abort();
  }
}

/*
 * Shortcut for AJAXCall with a single URL
 */
function AJAXCallURL( sFullUrl, pCallBackFunction, nTimeOut, bCheckStatus, bUseXML )
{
  // construct URL
  var aURLParts = new String(sFullUrl).split('?');
  var sURL    = aURLParts[0];
  var sParams = aURLParts[1];
  
  return AJAXCall( sURL, sParams, pCallBackFunction, nTimeOut, bCheckStatus, bUseXML );
}

/*
 * Call a remote script and returns its result as an XML document or a text value.
 * 
 *   sURL              : Server location to call
 *   sParams           : Parameters to pass to the server
 *   pCallBackFunction : Function to pass the response to
 *   nTimeOut          : Time in second to wait before abording the request
 *   bCheckStatus      : Throws an error for bad statuses
 *   bUseXML           : Returns an XML object instead of text
 */
function AJAXCall( sURL, sParams, pCallBackFunction, nTimeOut, bCheckStatus, bUseXML )
{
  // Obtain an XMLHttpRequest instance
  var pRequest = newXMLHttpRequest();

  // Asynchronous
  var bAsynchronous = pCallBackFunction != null;
  
  var pAJAXRequest = new AJAXRequest(pRequest);
  
  if( bAsynchronous )
  {
    var nTimeoutID = null;
    if( nTimeOut ) // plus vraiment asynchrone en fait :/
    {
      var hTimeout = getTimeoutHandler( pRequest );
      nTimeoutID = window.setTimeout( hTimeout, nTimeOut * 1000 );
    }

    // Set the handler function to receive callback notifications from the request object
    var hFunction = getReadyStateHandler( pAJAXRequest, pCallBackFunction, bCheckStatus, nTimeoutID );
    pRequest.onreadystatechange = hFunction;
  }

  // Open an HTTP POST connection to the server
  // Third parameter specifies request is asynchronous.
  pRequest.open( "POST", sURL, bAsynchronous ? true : false );
  
  // Specify that the body of the request contains form data
  pRequest.setRequestHeader( "Content-Type", "application/x-www-form-urlencoded" );
  
  // Bug potentiel avec l'IE, à decommenter s'il se produit
  //sParams += "hash=" + Math.random();
  
  // Send form encoded data
  pRequest.send( sParams );
  
  if( bAsynchronous )
  {
    return pAJAXRequest;
  }
  else
  {
    return bUseXML ? pRequest.responseXML : pRequest.responseText;
  }
}

function AJAXRequest(pRequest)
{
  this.getRequest = AJAXRequest_getRequest;
  this.setCanceled = AJAXRequest_setCanceled;
  this.isCanceled = AJAXRequest_isCanceled;
  
  this.pRequest = pRequest;
  this.bCanceled = false;
  
}

function AJAXRequest_getRequest()
{
  return this.pRequest;
}

function AJAXRequest_setCanceled(bCanceled)
{
  this.bCanceled = bCanceled;
}

function AJAXRequest_isCanceled()
{
  return this.bCanceled;
}

function compressContent( sContent )
{
  //console.time( 'compress' );
  var sEncodedContent = encodeURIComponent( sContent );
  var sCompressedContent = compressJS( sEncodedContent );
  //console.timeEnd( 'compress' );
  
  return sCompressedContent;
}

