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

function remoteCallJavascriptErrorHandler(sMessage, sURL, nLine)
{
  try
  {
    // répération de la stack trace
    var sStackTrace = getStackTrace(1);
    if( window.console )
      window.console.log("Message:"+sMessage+"\n"+
                        "URL:"+sURL+"\n"+
                        "Line:"+nLine+"\n"+
                        "StackTrace:\n"+sStackTrace);
    // 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);
  }
  // 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);
}

/**
 * RemoteCallException
 */
function RemoteCallException( pException, sScriptError )
{
  this.sScriptError = sScriptError;
  this.sMessage = sScriptError;
  this.nErrorNumber = 0;
  this.sStackTrace = "";
  this.sSessionInfo = "";
}

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

RemoteCallException.prototype.toString = function()
{
  return this.nErrorNumber + ": " + this.sMessage;
};

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

RemoteCallException.prototype.getErrorNumber = function()
{
  return this.nErrorNumber;
};

RemoteCallException.prototype.getStackTrace = function()
{
  return this.sStackTrace;
};

RemoteCallException.prototype.getSessionInfo = function()
{
  return this.sSessionInfo;
};

/**
 * 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 aDecodedData = createRemoteCallOptions(sClassName, aParams);//getDecodedDatas( sURL );
  var sSimpleURL = getSimpleURL( /*sURL*/ serverURL );
  
  var options = {
      url: sSimpleURL,
      async: false,
      global: false,
      type: "POST",
      dataType: "text",
      data: aDecodedData
  };
  var xhr = getAjaxCallWindow().jQuery.ajax( options );

  return evalRemoteCallResponse(xhr.responseText, options);
}

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 aDecodedData = createRemoteCallOptions(sClassName, aParams);//getDecodedDatas( sURL );
  var sSimpleURL = getSimpleURL( /*sURL*/serverURL );
  
  var pAJAXRequest = getAjaxCallWindow().jQuery.ajax({
      url: sSimpleURL,
      global: false,
      type: "POST",
      data: aDecodedData,
      dataType: "text",
      //error: getRemoteCallWaitErrorHandler( pCallBackInstance, pCallBackFunction, pCallBackErrorInstance, pCallBackError),
      //success: getRemoteCallWaitSuccessHandler( pCallBackInstance, pCallBackFunction, pCallBackErrorInstance, pCallBackError)
    error: function(xml, textStatus, errorThrown){
      hideWaitLayer('wait_layer');
      pCallBackError.call(pCallBackErrorInstance, errorThrown);
      return false;
    },
    success: function(msg){
      hideWaitLayer('wait_layer');
      try {
        var evalMsg = evalRemoteCallResponse(msg);
        pCallBackFunction.call( pCallBackInstance, evalMsg, false );
      } catch(ex) {
        if ( pCallBackError )
        {
          pCallBackError.call(pCallBackErrorInstance, ex);
        }
        else
        {
          alert( ex );
        }
      }
      return false;
    }
    } );
  
  showWaitLayer('wait_layer', sWaitMessage);
  // recherche du bouton stop pour annuler la requête en cours
  var pStopButton = getDOMObject('cancel_request_button');
  if( pStopButton && bCanCancel )
  {
    pStopButton.onclick =
      function()
      {
        // on cache la layer
        hideWaitLayer('wait_layer');
  
        // on appel le callback
        //  en lui signalant l'annulation
        try
        {
          if(pCallBackInstance)
            pCallBackFunction.call(this.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;          
      }
      
    pStopButton.style.visibility = 'visible';
  }
  else
      pStopButton.style.visibility = 'hidden';
  
  // libération de la mémoire prise par ces variables locales non
  //  utilisées dans les closures
  aArgs = null;
  aParams = null;
  aDecodedData = null;
  sSimpleURL = null;
  pStopButton = null;
  
}

function getDecodedDatas( sURL )
{
  var aEncodedParams = getDatas( sURL );
  var aDecodedData = {};
  for(var p in aEncodedParams)
  {
    if( aEncodedParams.hasOwnProperty(p) )
      aDecodedData[p] = decodeURIComponent(aEncodedParams[p]);
  }
  return aDecodedData;
}

function getDatas( sURL )
{
  var aTmp = sURL.split("?");
  var sParams = aTmp[1];
  var aEncodedParams = sParams.split("&");
  var aData = {};
  for(var i=0; i<aEncodedParams.length; i++)
  {
    if (aEncodedParams[i].match(getRegExp(/^.+=.*$/)))
    {
      var aKeyValue = aEncodedParams[i].split("=");
      aData[aKeyValue[0]] = aKeyValue[1];
    }
  }
  return aData;
}


function getSimpleURL( sURL )
{
  var aTmp = sURL.split("?");
  return aTmp[0];
}

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 createRemoteCallOptions(sClassName, aParams)
{
  var aNewParams = {
      'mime_type' : 'text/plain',
      'class' : sClassName
  };
  
  if ( !window.sessionParams )
  {
    var sessionParams = getDatas( serverURL );
    window.sessionParams = {};
    for ( var p in sessionParams )
    {
      if( sessionParams.hasOwnProperty(p) )
        window.sessionParams[p] = sessionParams[p];
    }
  }
  for ( var p in window.sessionParams )
  {
    if( window.sessionParams.hasOwnProperty(p) )
      aNewParams[p] = window.sessionParams[p];
  }
  for( var i=0 ; i < aParams.length ; i++ )
  {
    if(aParams[i] === false)
      aParams[i] = 0;
    if(aParams[i] === true)
      aParams[i] = 1;
    aNewParams['arg'+(i+1)] = ( aParams[i] != null ? aParams[i] : '' );
  }
  aNewParams['num_args'] = aParams.length;
  return aNewParams;
}

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

  if( pRet === undefined )
  {
    var sErrorMessage;
    if ( context && context.url )
    {
      sErrorMessage = 'Invalid remote call response for "'+context.url+'": '+sResponse;
    }
    else
    {
      sErrorMessage = 'Invalid remote call response: ' + sResponse;
    }
    throw new RemoteCallException(null, sErrorMessage );
  }

  if( pRet instanceof RemoteCallException ||
      pRet instanceof CheckerException ||
      pRet instanceof Error )
    throw pRet;

  return pRet;
}

function remoteCallURL( sFullUrl, pCallBackFunction, nTimeOut, bCheckStatus, bUseXML )
{
  return getAjaxCallWindow().jQuery.ajax( {
      url: sFullUrl,
      async: false
    }
  ).responseText;
}

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

/**
 * Pour éviter des problèmes d'accès au serveur depuis les appels ajax, tous les appels sont effectués depuis la frame applicative.
 * Cette méthode retourne cette frame ou die si jamais on ne la trouve pas.
 */
var g_pAjaxCallWindow = null;
function getAjaxCallWindow()
{
  if(!g_pAjaxCallWindow)
  {
    var pAppWindow = findParentWindow("app", window);
    if( !pAppWindow )
    {
      // c'est pour la réservation en ligne
      //  qui n'a pas de frame applicative
      if( window.jQuery )
        g_pAjaxCallWindow = window;
      else
        throw new Error("No application frame 'app' and window did not init jQuery to make ajax calls");
    }
    else
    {
      if( pAppWindow.jQuery )
        g_pAjaxCallWindow = pAppWindow;
      else
        throw new Error("Application frame 'app' did not init jQuery to make ajax calls");
    }
  }
  return g_pAjaxCallWindow;
}

