/*-----------------------------------------------------------------*/
/*! 
  \file scscpstatus.c
  \brief SCSCP status functions
  \author  M. Gastineau 
           Astronomie et Systemes Dynamiques, IMCCE, CNRS, Observatoire de Paris. 

   Copyright, 2008, 2012,  M. Gastineau, IMCCE-CNRS
   email of the author : gastineau@imcce.fr
  
  \bug M. GASTINEAU 12/09/08 : update for SCSCP 1.2
  \bug M. GASTINEAU 20/04/09 : update for SCSCP 1.3
*/
/*-----------------------------------------------------------------*/

/*-----------------------------------------------------------------*/
/* License  of this file :
 This file is "dual-licensed", you have to choose one  of the two licenses 
 below to apply on this file.
 
    CeCILL-C
    	The CeCILL-C license is close to the GNU LGPL.
    	( http://www.cecill.info/licences/Licence_CeCILL-C_V1-en.html )
 
 or CeCILL v2.0
      The CeCILL license is compatible with the GNU GPL.
      ( http://www.cecill.info/licences/Licence_CeCILL_V2-en.html )
 

This library is governed by the CeCILL-C or the CeCILL license under 
French law and abiding by the rules of distribution of free software.  
You can  use, modify and/ or redistribute the software under the terms 
of the CeCILL-C or CeCILL license as circulated by CEA, CNRS and INRIA  
at the following URL "http://www.cecill.info". 

As a counterpart to the access to the source code and  rights to copy,
modify and redistribute granted by the license, users are provided only
with a limited warranty  and the software's author,  the holder of the
economic rights,  and the successive licensors  have only  limited
liability. 

In this respect, the user's attention is drawn to the risks associated
with loading,  using,  modifying and/or developing or reproducing the
software by the user in light of its specific status of free software,
that may mean  that it is complicated to manipulate,  and  that  also
therefore means  that it is reserved for developers  and  experienced
professionals having in-depth computer knowledge. Users are therefore
encouraged to load and test the software's suitability as regards their
requirements in conditions enabling the security of their systems and/or 
data to be ensured and,  more generally, to use and operate it in the 
same conditions as regards security. 

The fact that you are presently reading this means that you have had
knowledge of the CeCILL-C or CeCILL license and that you accept its terms.
*/
/*-----------------------------------------------------------------*/

#include <stdio.h>
#if HAVE_CONFIG_H
#include "scscpconfig.h"
#endif /*HAVE_CONFIG_H*/
#if HAVE_WINDOWS_H
#include <windows.h>
#include <Winsock2.h>
#else
#if HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#endif /*HAVE_WINDOWS_H*/
#if HAVE_STRING_H
#include <string.h>
#endif
#include <ctype.h>
#include <errno.h>
#define __SCSCP_WITHIN_SCSCP
#include "scscp.h"
#include "scscpdebug.h"
#include "scscpinternal.h"
#include "scscpfileclient.h"
#include "scscpfileserver.h"



/*-----------------------------------------------------------------*/
/*! clear the status object
  @param status (inout) status to be updated
*/
/*-----------------------------------------------------------------*/
__SCSCP_DECLSPEC void SCSCP_status_clear(SCSCP_status* status)
{
 if (status)
 {
  SCSCP_debugprint("SCSCP_status_clear(%p) - enter\n", status);
  if (SCSCP_status_is(status)==SCSCP_STATUS_EXECFAILED)
  {
   if (status->m_cdname) free(status->m_cdname);  
   if (status->m_symbolname) free(status->m_symbolname);  
   if (status->m_message) free(status->m_message);  
   if (status->m_fullformattedmessage) free(status->m_fullformattedmessage);  
  }
  *status = SCSCP_STATUS_INITIALIZER;
  SCSCP_debugprint("SCSCP_status_clear() - return\n");
 }
}

/*-----------------------------------------------------------------*/
/*!  set the error to value
  @param status (in) status to be updated
  @param value (in) error value (must be SCSCP_STATUS_xxxx)
*/
/*-----------------------------------------------------------------*/
void SCSCP_status_seterror(SCSCP_status* status, int value)
{
 SCSCP_status_clear(status);
 if (status) 
 {
  status->m_code = value;
 }
}

/*-----------------------------------------------------------------*/
/*!  set the error to value  : EXECFAILED
  @param status (in) status to be updated
  @param cdname (in) name of the cd
  @param symbolname (in) name of the symbol
  @param msg (in) message
*/
/*-----------------------------------------------------------------*/
void SCSCP_status_setexecfailed(SCSCP_status* status, const char *cdname, const char *symbolname, const char *msg)
{
 SCSCP_status_seterror(status, SCSCP_STATUS_EXECFAILED);
 if (status)
 {
   const char *format = "Remote execution failed. Reason : cd='%s' name='%s' message='%s'\n";
   status->m_cdname = SCSCP_strdup(cdname, SCSCP_STATUS_IGNORE);  
   status->m_symbolname = SCSCP_strdup(symbolname, SCSCP_STATUS_IGNORE);  
   status->m_message = SCSCP_strdup(msg, SCSCP_STATUS_IGNORE);  
   status->m_fullformattedmessage=(char*)SCSCP_malloc((strlen(cdname)+strlen(symbolname)+strlen(msg)+strlen(format)+2)*sizeof(char), SCSCP_STATUS_IGNORE); 
   if (status->m_fullformattedmessage)
   {
    sprintf(status->m_fullformattedmessage,format, cdname, symbolname, msg);
   }
   if (status->m_cdname==NULL || status->m_symbolname==NULL || status->m_message==NULL || status->m_fullformattedmessage==NULL)
   {
    SCSCP_status_seterror(status, SCSCP_STATUS_ERRNO);
   }
 }
}


/*-----------------------------------------------------------------*/
/*!  copy the error code from src to dst 
  @param dst (out) status to be updated
  @param src (in) status to be copied
*/
/*-----------------------------------------------------------------*/
void SCSCP_status_copy(SCSCP_status* dst, const SCSCP_status *src)
{
 SCSCP_debugprint("SCSCP_status_copy(%p, %p) - enter\n", dst, src);
 if (dst && src) 
 {
  *dst = *src;
   if (dst->m_fullformattedmessage)
   {
    dst->m_fullformattedmessage=SCSCP_strdup(dst->m_fullformattedmessage, SCSCP_STATUS_IGNORE);
   }
   if (dst->m_cdname) dst->m_cdname = SCSCP_strdup(dst->m_cdname, SCSCP_STATUS_IGNORE);  
   if (dst->m_symbolname) dst->m_symbolname = SCSCP_strdup(dst->m_symbolname, SCSCP_STATUS_IGNORE);  
   if (dst->m_message) dst->m_message = SCSCP_strdup(dst->m_message, SCSCP_STATUS_IGNORE);  
 }
 SCSCP_debugprint("SCSCP_status_copy() - return\n");
}

/*-----------------------------------------------------------------*/
/*!  copythe error code from src to dst 
  @param dst (out) status to be updated
  @param src (in) status to be copied
*/
/*-----------------------------------------------------------------*/
SCSCP_status SCSCP_status_getinitializer()
{
 SCSCP_status status = {SCSCP_STATUS_OK, NULL, NULL, NULL, NULL};
 return status;
}


/*-----------------------------------------------------------------*/
/*!  return a pointer to the corresponding message string 
  @param status (out) error code 
*/
/*-----------------------------------------------------------------*/
__SCSCP_DECLSPEC const char* SCSCP_status_strerror(const SCSCP_status* status)
{
 int j;
#define SCSCP_STATUS_MAXERR 21
 struct st_msg 
 {
  int value;       /*!< value of the error code */
  const char *msg; /*!< message string */
 }
 armsg[SCSCP_STATUS_MAXERR]={
    { SCSCP_STATUS_OK ,"Success" },
    { SCSCP_STATUS_NOMEM ,"Not enough memory"},
    { SCSCP_STATUS_CLIENTOBJECTNULL,"The object client passed to the function is NULL"},
    { SCSCP_STATUS_CALLOPTIONSOBJECTNULL,"The call options passed to the function is NULL"},
    { SCSCP_STATUS_RECVCANCEL ,"The interrupt message '<?scscp cancel ?> was received"},
    { SCSCP_STATUS_RECVQUIT ,"The interrupt message '<?scscp quit ?> was received"},
    { SCSCP_STATUS_RETURNOPTIONSOBJECTNULL ,"The return options passed to the function is NULL"},
    { SCSCP_STATUS_SERVEROBJECTNULL ,"The object server passed to the function is NULL"},
    { SCSCP_STATUS_STREAMOBJECTNULL ,"The object stream passed to the function is NULL"},
    { SCSCP_STATUS_CALLIDISNOTSET ,"The call identifier isn't defined in the options"},
    { SCSCP_STATUS_RETURNTYPEISNOTSET ,"The return type isn't defined in the options"},
    { SCSCP_STATUS_USAGEUNKNOWNRUNTIME ," The runtime usage isn't available in the procedure return message"},
    { SCSCP_STATUS_USAGEUNKNOWNMEM ,"The memory usage isn't available in the procedure return message"},
    { SCSCP_STATUS_USAGEUNKNOWNMESSAGE ,"The information message isn't available in the procedure return message"},
    { SCSCP_STATUS_USAGEUNKNOWNRUNTIMELIMIT,"The runtime limit usage isn't available in the procedure call message"},
    { SCSCP_STATUS_USAGEUNKNOWNMINMEMORY ,"The min memory isn't available in the procedure call message"},
    { SCSCP_STATUS_USAGEUNKNOWNMAXMEMORY ,"The max memory isn't available in the procedure call message"},
    { SCSCP_STATUS_USAGEUNKNOWNDEBUGLEVEL ,"The debug level isn't available in the procedure call message"},
    { SCSCP_STATUS_USAGEUNKNOWNRETURNTYPE ,"The return type isn't available in the procedure call message"},
    { SCSCP_STATUS_VERSIONNEGOTIATIONFAILED ,"The version negotiation fails"},
    { SCSCP_STATUS_OPENMATHNOTVALID, "The OpenMath expression isn't valid"}
   };
 const char *msg;
 
 if (status==NULL) msg = "";
 else if (SCSCP_status_is(status)==SCSCP_STATUS_EXECFAILED) msg = status->m_fullformattedmessage;
 else if (SCSCP_status_is(status)==SCSCP_STATUS_ERRNO) msg=strerror(errno);
 else
 {
  msg=NULL;
  for (j=0; j<SCSCP_STATUS_MAXERR && msg==NULL; j++)
  {
   if (armsg[j].value==SCSCP_status_is(status)) msg = armsg[j].msg;
  }
  if (msg==NULL) msg = "";
 }
 return msg;
}




