/* This file is part of Lcrzo.
*/

int lcrzo_err_fprint(LCRZOFILE *pf, int err)
{ lcrzo_string errmsg;
  int err_errno, err_h_errno;
  lcrzo_int16 language;
#if defined LCRZODEF_SYSTEM_Unix
#elif defined LCRZODEF_SYSTEM_Windows
  int err_getlasterror;
#else
 #error "Unknown value for LCRZODEF_SYSTEM"
#endif

  /* do it now because lcrzo_global_get_language change it */
  err_errno=errno;
  err_h_errno=h_errno;
#if defined LCRZODEF_SYSTEM_Unix
#elif defined LCRZODEF_SYSTEM_Windows
  err_getlasterror=GetLastError();
  /* we do not use WSAGetLastError, because it is equivalent to h_errno */
#else
 #error "Unknown value for LCRZODEF_SYSTEM"
#endif

  /*parameters verification*/
  if (pf==NULL) return(LCRZO_ERR_PANULLPTR);

#if 0
  /*get pid*/
  fprintf(pf, "[pid%d] ", getpid());
#endif

  /*affichage des erreurs particulieres*/
  lcrzo_er(lcrzo_global_get_language(&language));
  if (err!=LCRZO_ERR_OK)
  { if (language==LCRZO_GLOBAL_LANG_FR)
      fprintf(pf, "Erreur %d : ", err);
    else
      fprintf(pf, "Error %d : ", err);
  }

  lcrzo_priv_err_fprint(pf, err, language);

  lcrzo_priv_global_get_errmsglcrzo(&errmsg);
  if (strlen(errmsg))
  { fprintf(pf, " `--> %s\n", errmsg);
  }
  lcrzo_string_free(errmsg);

  lcrzo_priv_global_get_errmsgsys(&errmsg);
  if (strlen(errmsg))
  { fprintf(pf, " `--> %s\n", errmsg);
  }
  lcrzo_string_free(errmsg);

  if(err_errno)
  { fprintf(pf, " `--> errno %d : %s\n", err_errno, strerror(err_errno));
  }

#if defined LCRZODEF_SYSTEM_Unix
#elif defined LCRZODEF_SYSTEM_Windows
  if (err_getlasterror)
  { LPVOID lpMsgBuf;
    DWORD languageid;
    int bytenum;
    /* display error number */
    fprintf(pf, " `--> GetLastError %d", err_getlasterror);
    /* try to get error string in the chosen language */
    if (language==LCRZO_GLOBAL_LANG_FR)
      languageid=MAKELANGID(LANG_FRENCH, SUBLANG_DEFAULT);
    else
      languageid=MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT);
    bytenum=FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
                          NULL, err_getlasterror, languageid,
                          (LPTSTR) &lpMsgBuf, 0, NULL);
    if (!bytenum)
    { /* try the system language */
      languageid=MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT);
      bytenum=FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
                            NULL, err_getlasterror, languageid,
                            (LPTSTR) &lpMsgBuf, 0, NULL);
    }
    if (bytenum)
    { fprintf(pf, " : %s", lpMsgBuf);
      LocalFree(lpMsgBuf);
    }
    else 
    { fprintf(pf, "\n");
    }
  }
#else
 #error "Unknown value for LCRZODEF_SYSTEM"
#endif

  if(err_h_errno) 
  {
   #if defined LCRZODEF_SYSTEM_Unix
    #ifdef LCRZODEF_HAVEFONC_ETHER_HSTRERROR
     fprintf(pf, " `--> h_errno %d : %s\n", err_h_errno, hstrerror(err_h_errno));
    #else
     fprintf(pf, " `--> h_errno %d\n", err_h_errno);
    #endif
   #elif defined LCRZODEF_SYSTEM_Windows
    fprintf(pf, " `--> h_errno %d", err_h_errno);
    /* there is no portable way to get Winsock error messages, so we do it here */
    switch(err_h_errno)
    {
      case WSAEINTR :           fprintf(pf, " : Interrupted system call"); break;
      case WSAEBADF :           fprintf(pf, " : Bad file number"); break;
      case WSAEACCES :          fprintf(pf, " : Permission denied"); break;
      case WSAEFAULT :          fprintf(pf, " : Bad address"); break;
      case WSAEINVAL :          fprintf(pf, " : Invalid argument"); break;
      case WSAEMFILE :          fprintf(pf, " : Too many open sockets"); break;
      case WSAEWOULDBLOCK :     fprintf(pf, " : Operation would block"); break;
      case WSAEINPROGRESS :     fprintf(pf, " : Operation now in progress"); break;
      case WSAEALREADY :        fprintf(pf, " : Operation already in progress"); break;
      case WSAENOTSOCK :        fprintf(pf, " : Socket operation on non-socket"); break;
      case WSAEDESTADDRREQ :    fprintf(pf, " : Destination address required"); break;
      case WSAEMSGSIZE :        fprintf(pf, " : Message too long"); break;
      case WSAEPROTOTYPE :      fprintf(pf, " : Protocol wrong type for socket"); break;
      case WSAENOPROTOOPT :     fprintf(pf, " : Bad protocol option"); break;
      case WSAEPROTONOSUPPORT : fprintf(pf, " : Protocol not supported"); break;
      case WSAESOCKTNOSUPPORT : fprintf(pf, " : Socket type not supported"); break;
      case WSAEOPNOTSUPP :      fprintf(pf, " : Operation not supported on socket"); break;
      case WSAEPFNOSUPPORT :    fprintf(pf, " : Protocol family not supported"); break;
      case WSAEAFNOSUPPORT :    fprintf(pf, " : Address family not supported"); break;
      case WSAEADDRINUSE :      fprintf(pf, " : Address already in use"); break;
      case WSAEADDRNOTAVAIL :   fprintf(pf, " : Can't assign requested address"); break;
      case WSAENETDOWN :        fprintf(pf, " : Network is down"); break;
      case WSAENETUNREACH :     fprintf(pf, " : Network is unreachable"); break;
      case WSAENETRESET :       fprintf(pf, " : Net connection reset"); break;
      case WSAECONNABORTED :    fprintf(pf, " : Software caused connection abort"); break;
      case WSAECONNRESET :      fprintf(pf, " : Connection reset by peer"); break;
      case WSAENOBUFS :         fprintf(pf, " : No buffer space available"); break;
      case WSAEISCONN :         fprintf(pf, " : Socket is already connected"); break;
      case WSAENOTCONN :        fprintf(pf, " : Socket is not connected"); break;
      case WSAESHUTDOWN :       fprintf(pf, " : Can't send after socket shutdown"); break;
      case WSAETOOMANYREFS :    fprintf(pf, " : Too many references, can't splice"); break;
      case WSAETIMEDOUT :       fprintf(pf, " : Connection timed out"); break;
      case WSAECONNREFUSED :    fprintf(pf, " : Connection refused"); break;
      case WSAELOOP :           fprintf(pf, " : Too many levels of symbolic links"); break;
      case WSAENAMETOOLONG :    fprintf(pf, " : File name too long"); break;
      case WSAEHOSTDOWN :       fprintf(pf, " : Host is down"); break;
      case WSAEHOSTUNREACH :    fprintf(pf, " : No route to host"); break;
      case WSAENOTEMPTY :       fprintf(pf, " : Directory not empty"); break;
      case WSAEPROCLIM :        fprintf(pf, " : Too many processes"); break;
      case WSAEUSERS :          fprintf(pf, " : Too many users"); break;
      case WSAEDQUOT :          fprintf(pf, " : Disc quota exceeded"); break;
      case WSAESTALE :          fprintf(pf, " : Stale NFS file handle"); break;
      case WSAEREMOTE :         fprintf(pf, " : Too many levels of remote in path"); break;
      case WSASYSNOTREADY :     fprintf(pf, " : Network system is unavailable"); break;
      case WSAVERNOTSUPPORTED : fprintf(pf, " : Winsock DLL version out of range"); break;
      case WSANOTINITIALISED :  fprintf(pf, " : WSAStartup not yet called"); break;
      case WSAEDISCON :         fprintf(pf, " : Graceful shutdown in progress"); break;
      case WSAHOST_NOT_FOUND :  fprintf(pf, " : Host not found"); break;
      case WSATRY_AGAIN :       fprintf(pf, " : Non-Authoritative Host not found"); break;
      case WSANO_RECOVERY :     fprintf(pf, " : Non-Recoverable errors: FORMERR, REFUSED, NOTIMP"); break;
      case WSANO_DATA :         fprintf(pf, " : No host data of that type was found"); break;
    }
    fprintf(pf, "\n");
   #else
    #error "Unknown value for LCRZODEF_SYSTEM"
   #endif
  }

#define  LCRZO_PRIV_ERROROK_DEBUG 0
#if LCRZO_PRIV_ERROROK_DEBUG==1
  if ( err==LCRZO_ERR_OK )
  { if ( err_errno || err_h_errno
#if defined LCRZODEF_SYSTEM_Unix
#elif defined LCRZODEF_SYSTEM_Windows
         || err_getlasterror
#else
 #error "Unknown value for LCRZODEF_SYSTEM"
#endif
       )
  { fprintf(pf, "err=OK, but subval are not OK\n");
    lcrzo_process_current_exit(LCRZO_ERR_IEINTERNALERROR);
  }
  }
#endif

  lcrzo_er(lcrzo_err_purge());
  lcrzo_er(lcrzo_stream_flush(stdout));
  return(LCRZO_ERR_OK);
}

