// @(#)root/base:$Id$
// Author: Fons Rademakers   29/07/95

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT_TError
#define ROOT_TError


//////////////////////////////////////////////////////////////////////////
//                                                                      //
// Error handling routines.                                             //
//                                                                      //
// This file defines a number of global error handling routines:        //
// Warning(), Error(), SysError() and Fatal(). They all take a          //
// location string (where the error happened) and a printf style format //
// string plus vararg's. In the end these functions call an             //
// errorhanlder function. Initially, a minimal, non thread-safe handler //
// is installed that is supposed to be replaced by the                  //
// DefaultErrorHandler(), which needs to be implemented and installed   //
// by the user of TError.  Normally, the default error handler is set   //
// during gROOT initialization.                                         //
//                                                                      //
//////////////////////////////////////////////////////////////////////////


#include <DllImport.h> // for R__EXTERN
#include "RtypesCore.h"
#include <ROOT/RConfig.hxx>

#include <cstdarg>
#include <functional>


class TVirtualMutex;

constexpr Int_t kUnset    =  -1;
constexpr Int_t kPrint    =   0;
constexpr Int_t kInfo     =   1000;
constexpr Int_t kWarning  =   2000;
constexpr Int_t kError    =   3000;
constexpr Int_t kBreak    =   4000;
constexpr Int_t kSysError =   5000;
constexpr Int_t kFatal    =   6000;


// TROOT sets the error ignore level handler, the system error message handler, and the error abort handler on
// construction such that the "Root.ErrorIgnoreLevel" environment variable is used for the ignore level
// and gSystem is used to generate a stack trace on abort.
namespace ROOT {
namespace Internal {

/// Retrieves the error string associated with the last system error.
using ErrorSystemMsgHandlerFunc_t = std::function<const char *()>;

ErrorSystemMsgHandlerFunc_t GetErrorSystemMsgHandler();
/// Returns the previous system error message handler
ErrorSystemMsgHandlerFunc_t SetErrorSystemMsgHandler(ErrorSystemMsgHandlerFunc_t h);

void MinimalErrorHandler(int level, Bool_t abort, const char *location, const char *msg);

} // namespace Internal
} // namespace ROOT

typedef void (*ErrorHandlerFunc_t)(int level, Bool_t abort, const char *location,
              const char *msg);

extern "C" void ErrorHandler(int level, const char *location, const char *fmt, std::va_list va);

extern void DefaultErrorHandler(int level, Bool_t abort, const char *location, const char *msg);

extern ErrorHandlerFunc_t SetErrorHandler(ErrorHandlerFunc_t newhandler);
extern ErrorHandlerFunc_t GetErrorHandler();

extern void Info(const char *location, const char *msgfmt, ...)
#if defined(__GNUC__)
__attribute__((format(printf, 2, 3)))
#endif
;
extern void Warning(const char *location, const char *msgfmt, ...)
#if defined(__GNUC__)
__attribute__((format(printf, 2, 3)))
#endif
;
extern void Error(const char *location, const char *msgfmt, ...)
#if defined(__GNUC__)
__attribute__((format(printf, 2, 3)))
#endif
;
extern void Break(const char *location, const char *msgfmt, ...)
#if defined(__GNUC__)
__attribute__((format(printf, 2, 3)))
#endif
;
extern void SysError(const char *location, const char *msgfmt, ...)
#if defined(__GNUC__)
__attribute__((format(printf, 2, 3)))
#endif
;
extern void Fatal(const char *location, const char *msgfmt, ...)
#if defined(__GNUC__)
__attribute__((format(printf, 2, 3)))
#endif
;

extern void AbstractMethod(const char *method);
extern void MayNotUse(const char *method);
extern void Obsolete(const char *function, const char *asOfVers, const char *removedFromVers);

R__EXTERN const char *kAssertMsg;
R__EXTERN const char *kCheckMsg;

/*! Checks condition `e` and reports a fatal error if it's false.
 * \warning
 *   - this check is NOT stripped in release mode, so it should not be used for hot paths.
 *     For those cases, prefer a regular `assert()`;
 *   - depending on `gErrorIgnoreLevel`, this might not terminate the program, \see ::Fatal.
 */
#define R__ASSERT(e)                                              \
   do {                                                           \
      if (R__unlikely(!(e)))                                      \
         ::Fatal("", kAssertMsg, _QUOTE_(e), __LINE__, __FILE__); \
   } while (false)

/*! Checks condition `e` and reports a warning message if it's false.
 * \warning this check is NOT stripped in release mode, so it should not be used for hot paths.
 */
#define R__CHECK(e)                                                \
   do {                                                            \
      if (R__unlikely(!(e)))                                       \
         ::Warning("", kCheckMsg, _QUOTE_(e), __LINE__, __FILE__); \
   } while (false)

R__EXTERN Int_t  gErrorIgnoreLevel;    ///< errors with level below this value will be ignored. Default is `kUnset`.
R__EXTERN Int_t  gErrorAbortLevel;     ///< non-ignored errors with level equal or above this value will call abort(). Default is `kSysError+1`.
R__EXTERN Bool_t gPrintViaErrorHandler;///< If true, ROOT's `Printf` will print via the currently active ROOT error handler; if false (default), it will use the standard `printf`.

#endif
