/////////////////////////////////////////////////////////////////////////////
// Name:        wx/log.h
// Purpose:     Assorted wxLogXXX functions, and wxLog (sink for logs)
// Author:      Vadim Zeitlin
// Created:     29/01/98
// Copyright:   (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

#ifndef _WX_LOG_H_
#define _WX_LOG_H_

#include "wx/defs.h"
#include "wx/cpp.h"

// ----------------------------------------------------------------------------
// types
// ----------------------------------------------------------------------------

// NB: this is needed even if wxUSE_LOG == 0
typedef unsigned long wxLogLevel;

// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------

#include "wx/string.h"

// This is a hack, but this header used to include wx/hashmap.h which, in turn,
// included wx/wxcrt.h and it turns out quite some existing code relied on it
// by using the CRT wrapper functions declared there without explicitly
// including that header, so keep including it from here to let it continue to
// compile.
#include "wx/wxcrt.h"

// ----------------------------------------------------------------------------
// forward declarations
// ----------------------------------------------------------------------------

class WXDLLIMPEXP_FWD_BASE wxObject;

#if wxUSE_GUI
    class WXDLLIMPEXP_FWD_CORE wxFrame;
#endif // wxUSE_GUI

#if wxUSE_LOG

#include "wx/arrstr.h"

#include <time.h>   // for time_t

#include "wx/dynarray.h"
#include "wx/msgout.h"
#include "wx/time.h"

#if wxUSE_THREADS
    #include "wx/thread.h"
#endif // wxUSE_THREADS

#include <unordered_map>

// wxUSE_LOG_DEBUG enables the debug log messages
#ifndef wxUSE_LOG_DEBUG
    #if wxDEBUG_LEVEL
        #define wxUSE_LOG_DEBUG 1
    #else // !wxDEBUG_LEVEL
        #define wxUSE_LOG_DEBUG 0
    #endif
#endif

// wxUSE_LOG_TRACE enables the trace messages, they are disabled by default
#ifndef wxUSE_LOG_TRACE
    #if wxDEBUG_LEVEL
        #define wxUSE_LOG_TRACE 1
    #else // !wxDEBUG_LEVEL
        #define wxUSE_LOG_TRACE 0
    #endif
#endif // wxUSE_LOG_TRACE

// wxLOG_COMPONENT identifies the component which generated the log record and
// can be #define'd to a user-defined value (ASCII only) when compiling the
// user code to use component-based filtering (see wxLog::SetComponentLevel())
#ifndef wxLOG_COMPONENT
    // this is a variable and not a macro in order to allow the user code to
    // just #define wxLOG_COMPONENT without #undef'ining it first
    extern WXDLLIMPEXP_DATA_BASE(const char *) wxLOG_COMPONENT;

    #ifdef WXBUILDING
        #define wxLOG_COMPONENT "wx"
    #endif
#endif

// ----------------------------------------------------------------------------
// constants
// ----------------------------------------------------------------------------

// different standard log levels (you may also define your own)
enum wxLogLevelValues
{
    wxLOG_FatalError, // program can't continue, abort immediately
    wxLOG_Error,      // a serious error, user must be informed about it
    wxLOG_Warning,    // user is normally informed about it but may be ignored
    wxLOG_Message,    // normal message (i.e. normal output of a non GUI app)
    wxLOG_Status,     // informational: might go to the status line of GUI app
    wxLOG_Info,       // informational message (a.k.a. 'Verbose')
    wxLOG_Debug,      // never shown to the user, disabled in release mode
    wxLOG_Trace,      // trace messages are also only enabled in debug mode
    wxLOG_Progress,   // used for progress indicator (not yet)
    wxLOG_User = 100, // user defined levels start here
    wxLOG_Max = 10000
};

// symbolic trace masks - wxLogTrace("foo", "some trace message...") will be
// discarded unless the string "foo" has been added to the list of allowed
// ones with AddTraceMask()

#define wxTRACE_MemAlloc wxT("memalloc") // trace memory allocation (new/delete)
#define wxTRACE_Messages wxT("messages") // trace window messages/X callbacks
#define wxTRACE_ResAlloc wxT("resalloc") // trace GDI resource allocation
#define wxTRACE_RefCount wxT("refcount") // trace various ref counting operations

#ifdef  __WINDOWS__
    #define wxTRACE_OleCalls wxT("ole")  // OLE interface calls
#endif

#include "wx/iosfwrap.h"

// ----------------------------------------------------------------------------
// information about a log record, i.e. unit of log output
// ----------------------------------------------------------------------------

class wxLogRecordInfo
{
public:
    // default ctor creates an uninitialized object
    wxLogRecordInfo()
    {
        memset(static_cast<void*>(this), 0, sizeof(*this));
    }

    // normal ctor, used by wxLogger specifies the location of the log
    // statement; its time stamp and thread id are set up here
    wxLogRecordInfo(const char *filename_,
                    int line_,
                    const char *func_,
                    const char *component_)
    {
        filename = filename_;
        func = func_;
        line = line_;
        component = component_;

        // don't initialize the timestamp yet, we might not need it at all if
        // the message doesn't end up being logged and otherwise we'll fill it
        // just before logging it, which won't change it by much
        timestampMS = 0;
#if WXWIN_COMPATIBILITY_3_0
        timestamp = 0;
#endif // WXWIN_COMPATIBILITY_3_0

#if wxUSE_THREADS
        threadId = wxThread::GetCurrentId();
#endif // wxUSE_THREADS

        m_data = nullptr;
    }

    // we need to define copy ctor and assignment operator because of m_data
    wxLogRecordInfo(const wxLogRecordInfo& other)
    {
        Copy(other);
    }

    wxLogRecordInfo& operator=(const wxLogRecordInfo& other)
    {
        if ( &other != this )
        {
            delete m_data;
            Copy(other);
        }

        return *this;
    }

    // dtor is non-virtual, this class is not meant to be derived from
    ~wxLogRecordInfo()
    {
        delete m_data;
    }


    // the file name and line number of the file where the log record was
    // generated, if available or nullptr and 0 otherwise
    const char *filename;
    int line;

    // the name of the function where the log record was generated
    const char *func;

    // the name of the component which generated this message, may be null if
    // not set (i.e. wxLOG_COMPONENT not defined). It must be in ASCII.
    const char *component;

    // time of record generation in milliseconds since Epoch
    wxLongLong_t timestampMS;

#if WXWIN_COMPATIBILITY_3_0
    // preserved for compatibility only, use timestampMS instead now
    time_t timestamp;
#endif // WXWIN_COMPATIBILITY_3_0

#if wxUSE_THREADS
    // id of the thread which logged this record
    wxThreadIdType threadId;
#endif // wxUSE_THREADS


    // store an arbitrary value in this record context
    //
    // wxWidgets always uses keys starting with "wx.", e.g. "wx.sys_error"
    void StoreValue(const wxString& key, wxUIntPtr val)
    {
        if ( !m_data )
            m_data = new ExtraData;

        m_data->numValues[key] = val;
    }

    void StoreValue(const wxString& key, const wxString& val)
    {
        if ( !m_data )
            m_data = new ExtraData;

        m_data->strValues[key] = val;
    }


    // these functions retrieve the value of either numeric or string key,
    // return false if not found
    bool GetNumValue(const wxString& key, wxUIntPtr *val) const
    {
        if ( !m_data )
            return false;

        const auto it = m_data->numValues.find(key);
        if ( it == m_data->numValues.end() )
            return false;

        *val = it->second;

        return true;
    }

    bool GetStrValue(const wxString& key, wxString *val) const
    {
        if ( !m_data )
            return false;

        const auto it = m_data->strValues.find(key);
        if ( it == m_data->strValues.end() )
            return false;

        *val = it->second;

        return true;
    }

private:
    void Copy(const wxLogRecordInfo& other)
    {
        memcpy(static_cast<void*>(this), &other, sizeof(*this));
        if ( other.m_data )
           m_data = new ExtraData(*other.m_data);
    }

    // extra data associated with the log record: this is completely optional
    // and can be used to pass information from the log function to the log
    // sink (e.g. wxLogSysError() uses this to pass the error code)
    struct ExtraData
    {
        std::unordered_map<wxString, wxUIntPtr> numValues;
        std::unordered_map<wxString, wxString> strValues;
    };

    // nullptr if not used
    ExtraData *m_data;
};

#define wxLOG_KEY_TRACE_MASK wxASCII_STR("wx.trace_mask")

// ----------------------------------------------------------------------------
// log record: a unit of log output
// ----------------------------------------------------------------------------

struct wxLogRecord
{
    wxLogRecord(wxLogLevel level_,
                const wxString& msg_,
                const wxLogRecordInfo& info_)
        : level(level_),
          msg(msg_),
          info(info_)
    {
    }

    wxLogLevel level;
    wxString msg;
    wxLogRecordInfo info;
};

// ----------------------------------------------------------------------------
// Derive from this class to customize format of log messages.
// ----------------------------------------------------------------------------

class WXDLLIMPEXP_BASE wxLogFormatter
{
public:
    // Default constructor.
    wxLogFormatter() = default;

    // Trivial but virtual destructor for the base class.
    virtual ~wxLogFormatter() = default;


    // Override this method to implement custom formatting of the given log
    // record. The default implementation simply prepends a level-dependent
    // prefix to the message and optionally adds a time stamp.
    virtual wxString Format(wxLogLevel level,
                            const wxString& msg,
                            const wxLogRecordInfo& info) const;

protected:
    // Override this method to change just the time stamp formatting. It is
    // called by default Format() implementation.
    virtual wxString FormatTimeMS(wxLongLong_t msec) const;

#if WXWIN_COMPATIBILITY_3_0
    // Old function which only worked at second resolution.
    virtual wxString FormatTime(time_t t) const;
#endif // WXWIN_COMPATIBILITY_3_0
};

// Special kind of trivial formatter which simply uses the message unchanged.
class wxLogFormatterNone : public wxLogFormatter
{
public:
    wxLogFormatterNone() = default;

    virtual wxString Format(wxLogLevel WXUNUSED(level),
                            const wxString& msg,
                            const wxLogRecordInfo& WXUNUSED(info)) const override
    {
        return msg;
    }
};

// ----------------------------------------------------------------------------
// derive from this class to redirect (or suppress, or ...) log messages
// normally, only a single instance of this class exists but it's not enforced
// ----------------------------------------------------------------------------

class WXDLLIMPEXP_BASE wxLog
{
public:
    // ctor
    wxLog() : m_formatter(new wxLogFormatter) { }

    // make dtor virtual for all derived classes
    virtual ~wxLog();


    // log messages selection
    // ----------------------

    // these functions allow to completely disable all log messages or disable
    // log messages at level less important than specified for the current
    // thread

    // is logging enabled at all now?
    static bool IsEnabled()
    {
#if wxUSE_THREADS
        if ( !wxThread::IsMain() )
            return IsThreadLoggingEnabled();
#endif // wxUSE_THREADS

        return ms_doLog;
    }

    // change the flag state, return the previous one
    static bool EnableLogging(bool enable = true)
    {
#if wxUSE_THREADS
        if ( !wxThread::IsMain() )
            return EnableThreadLogging(enable);
#endif // wxUSE_THREADS

        const bool doLogOld = ms_doLog;
        ms_doLog = enable;
        return doLogOld;
    }

    // return the current global log level
    static wxLogLevel GetLogLevel() { return ms_logLevel; }

    // set global log level: messages with level > logLevel will not be logged
    static void SetLogLevel(wxLogLevel logLevel) { ms_logLevel = logLevel; }

    // set the log level for the given component
    static void SetComponentLevel(const wxString& component, wxLogLevel level);

    // return the effective log level for this component, falling back to
    // parent component and to the default global log level if necessary
    static wxLogLevel GetComponentLevel(const wxString& component);


    // is logging of messages from this component enabled at this level?
    //
    // usually always called with wxLOG_COMPONENT as second argument
    static bool IsLevelEnabled(wxLogLevel level, const wxString& component)
    {
        return IsEnabled() && level <= GetComponentLevel(component);
    }


    // enable/disable messages at wxLOG_Verbose level (only relevant if the
    // current log level is greater or equal to it)
    //
    // notice that verbose mode can be activated by the standard command-line
    // '--verbose' option
    static void SetVerbose(bool bVerbose = true) { ms_bVerbose = bVerbose; }

    // check if verbose messages are enabled
    static bool GetVerbose() { return ms_bVerbose; }


    // message buffering
    // -----------------

    // flush shows all messages if they're not logged immediately (FILE
    // and iostream logs don't need it, but wxLogGui does to avoid showing
    // 17 modal dialogs one after another)
    virtual void Flush();

    // flush the active target if any and also output any pending messages from
    // background threads
    static void FlushActive();

    // only one sink is active at each moment get current log target, will call
    // wxAppTraits::CreateLogTarget() to create one if none exists
    static wxLog *GetActiveTarget();

    // change log target, logger may be null
    static wxLog *SetActiveTarget(wxLog *logger);

#if wxUSE_THREADS
    // change log target for the current thread only, shouldn't be called from
    // the main thread as it doesn't use thread-specific log target
    static wxLog *SetThreadActiveTarget(wxLog *logger);
#endif // wxUSE_THREADS

    // suspend the message flushing of the main target until the next call
    // to Resume() - this is mainly for internal use (to prevent wxYield()
    // from flashing the messages)
    static void Suspend() { ms_suspendCount++; }

    // must be called for each Suspend()!
    static void Resume() { ms_suspendCount--; }

    // should GetActiveTarget() try to create a new log object if the
    // current is null?
    static void DontCreateOnDemand();

    // Make GetActiveTarget() create a new log object again.
    static void DoCreateOnDemand();

    // log the count of repeating messages instead of logging the messages
    // multiple times
    static void SetRepetitionCounting(bool bRepetCounting = true)
        { ms_bRepetCounting = bRepetCounting; }

    // gets duplicate counting status
    static bool GetRepetitionCounting() { return ms_bRepetCounting; }

    // add string trace mask
    static void AddTraceMask(const wxString& str);

    // add string trace mask
    static void RemoveTraceMask(const wxString& str);

    // remove all string trace masks
    static void ClearTraceMasks();

    // get string trace masks: note that this is MT-unsafe if other threads can
    // call AddTraceMask() concurrently
    static const wxArrayString& GetTraceMasks();

    // is this trace mask in the list?
    static bool IsAllowedTraceMask(const wxString& mask);


    // log formatting
    // -----------------

    // Change wxLogFormatter object used by wxLog to format the log messages.
    //
    // wxLog takes ownership of the pointer passed in but the caller is
    // responsible for deleting the returned pointer.
    wxLogFormatter* SetFormatter(wxLogFormatter* formatter);


    // All the time stamp related functions below only work when the default
    // wxLogFormatter is being used. Defining a custom formatter overrides them
    // as it could use its own time stamp format or format messages without
    // using time stamp at all.


    // sets the time stamp string format: this is used as strftime() format
    // string for the log targets which add time stamps to the messages; set
    // it to empty string to disable time stamping completely.
    static void SetTimestamp(const wxString& ts) { ms_timestamp = ts; }

    // disable time stamping of log messages
    static void DisableTimestamp() { SetTimestamp(wxEmptyString); }


    // get the current timestamp format string (maybe empty)
    static const wxString& GetTimestamp() { return ms_timestamp; }



    // helpers: all functions in this section are mostly for internal use only,
    // don't call them from your code even if they are not formally deprecated

    // put the time stamp into the string if ms_timestamp is not empty (don't
    // change it otherwise); the first overload uses the current time.
    static void TimeStamp(wxString *str);
    static void TimeStamp(wxString *str, time_t t);
    static void TimeStampMS(wxString *str, wxLongLong_t msec);

    // these methods should only be called from derived classes DoLogRecord(),
    // DoLogTextAtLevel() and DoLogText() implementations respectively and
    // shouldn't be called directly, use logging functions instead
    void LogRecord(wxLogLevel level,
                   const wxString& msg,
                   const wxLogRecordInfo& info)
    {
        DoLogRecord(level, msg, info);
    }

    void LogTextAtLevel(wxLogLevel level, const wxString& msg)
    {
        DoLogTextAtLevel(level, msg);
    }

    void LogText(const wxString& msg)
    {
        DoLogText(msg);
    }

    // this is a helper used by wxLogXXX() functions, don't call it directly
    // and see DoLog() for function to overload in the derived classes
    static void OnLog(wxLogLevel level,
                      const wxString& msg,
                      const wxLogRecordInfo& info);

    // version called when no information about the location of the log record
    // generation is available (but the time stamp is), it mainly exists for
    // backwards compatibility, don't use it in new code
    static void OnLog(wxLogLevel level, const wxString& msg, time_t t);

    // a helper calling the above overload with current time
    static void OnLog(wxLogLevel level, const wxString& msg)
    {
        OnLog(level, msg, time(nullptr));
    }


    // this method exists for backwards compatibility only, don't use
    bool HasPendingMessages() const { return true; }

protected:
    // the logging functions that can be overridden: DoLogRecord() is called
    // for every "record", i.e. a unit of log output, to be logged and by
    // default formats the message and passes it to DoLogTextAtLevel() which in
    // turn passes it to DoLogText() by default

    // override this method if you want to change message formatting or do
    // dynamic filtering
    virtual void DoLogRecord(wxLogLevel level,
                             const wxString& msg,
                             const wxLogRecordInfo& info);

    // override this method to redirect output to different channels depending
    // on its level only; if even the level doesn't matter, override
    // DoLogText() instead
    virtual void DoLogTextAtLevel(wxLogLevel level, const wxString& msg);

    // this function is not pure virtual as it might not be needed if you do
    // the logging in overridden DoLogRecord() or DoLogTextAtLevel() directly
    // but if you do not override them in your derived class you must override
    // this one as the default implementation of it simply asserts
    virtual void DoLogText(const wxString& msg);

    // log a message indicating the number of times the previous message was
    // repeated if previous repetition counter is strictly positive, does
    // nothing otherwise; return the old value of repetition counter
    unsigned LogLastRepeatIfNeeded();

private:
#if wxUSE_THREADS
    // called from FlushActive() to really log any buffered messages logged
    // from the other threads
    void FlushThreadMessages();

    // these functions are called for non-main thread only by IsEnabled() and
    // EnableLogging() respectively
    static bool IsThreadLoggingEnabled();
    static bool EnableThreadLogging(bool enable = true);
#endif // wxUSE_THREADS

    // get the active log target for the main thread, auto-creating it if
    // necessary
    //
    // this is called from GetActiveTarget() and OnLog() when they're called
    // from the main thread
    static wxLog *GetMainThreadActiveTarget();

    // called from OnLog() if it's called from the main thread or if we have a
    // (presumably MT-safe) thread-specific logger and by FlushThreadMessages()
    // when it plays back the buffered messages logged from the other threads
    void CallDoLogNow(wxLogLevel level,
                      const wxString& msg,
                      const wxLogRecordInfo& info);


    // variables
    // ----------------

    wxLogFormatter    *m_formatter; // We own this pointer.


    // static variables
    // ----------------

    // if true, don't log the same message multiple times, only log it once
    // with the number of times it was repeated
    static bool        ms_bRepetCounting;

    static wxLog      *ms_pLogger;      // currently active log sink
    static bool        ms_doLog;        // false => all logging disabled
    static bool        ms_bAutoCreate;  // create new log targets on demand?
    static bool        ms_bVerbose;     // false => ignore LogInfo messages

    static wxLogLevel  ms_logLevel;     // limit logging to levels <= ms_logLevel

    static size_t      ms_suspendCount; // if positive, logs are not flushed

    // format string for strftime(), if empty, time stamping log messages is
    // disabled
    static wxString    ms_timestamp;

    wxDECLARE_NO_COPY_CLASS(wxLog);
};

// ----------------------------------------------------------------------------
// "trivial" derivations of wxLog
// ----------------------------------------------------------------------------

// log everything except for the debug/trace messages (which are passed to
// wxMessageOutputDebug) to a buffer
class WXDLLIMPEXP_BASE wxLogBuffer : public wxLog
{
public:
    wxLogBuffer() = default;

    // get the string contents with all messages logged
    const wxString& GetBuffer() const { return m_str; }

    // clear all the messages, this, in particular, prevents them from being
    // flushed
    void Clear() { m_str.clear(); }

    // show the buffer contents to the user in the best possible way (this uses
    // wxMessageOutputMessageBox) and clear it
    virtual void Flush() override;

protected:
    virtual void DoLogTextAtLevel(wxLogLevel level, const wxString& msg) override;

private:
    wxString m_str;

    wxDECLARE_NO_COPY_CLASS(wxLogBuffer);
};


// log everything to a "FILE *", stderr by default
class WXDLLIMPEXP_BASE wxLogStderr : public wxLog,
                                     protected wxMessageOutputStderr
{
public:
    // redirect log output to a FILE
    wxLogStderr(FILE *fp = nullptr,
                const wxMBConv &conv = wxConvWhateverWorks);

protected:
    // implement sink function
    virtual void DoLogText(const wxString& msg) override;

    wxDECLARE_NO_COPY_CLASS(wxLogStderr);
};

#if wxUSE_STD_IOSTREAM

// log everything to an "ostream", cerr by default
class WXDLLIMPEXP_BASE wxLogStream : public wxLog,
                                     private wxMessageOutputWithConv
{
public:
    // redirect log output to an ostream
    wxLogStream(std::ostream *ostr = (std::ostream *) nullptr,
                const wxMBConv& conv = wxConvWhateverWorks);

protected:
    // implement sink function
    virtual void DoLogText(const wxString& msg) override;

    // using ptr here to avoid including <iostream.h> from this file
    std::ostream *m_ostr;

    wxDECLARE_NO_COPY_CLASS(wxLogStream);
};

#endif // wxUSE_STD_IOSTREAM

// ----------------------------------------------------------------------------
// /dev/null log target: suppress logging until this object goes out of scope
// ----------------------------------------------------------------------------

// example of usage:
/*
    void Foo()
    {
        wxFile file;

        // wxFile.Open() normally complains if file can't be opened, we don't
        // want it
        wxLogNull logNo;

        if ( !file.Open("bar") )
            ... process error ourselves ...

        // ~wxLogNull called, old log sink restored
    }
 */
class WXDLLIMPEXP_BASE wxLogNull
{
public:
    wxLogNull() : m_flagOld(wxLog::EnableLogging(false)) { }
    ~wxLogNull() { (void)wxLog::EnableLogging(m_flagOld); }

private:
    bool m_flagOld; // the previous value of the wxLog::ms_doLog
};

// ----------------------------------------------------------------------------
// Collect all logged messages into a (multiline) string.
// ----------------------------------------------------------------------------

// This class is supposed to be used as a local variable and collects, without
// showing them, all the messages logged during its lifetime.
class wxLogCollector
{
public:
    wxLogCollector()
        : m_logOrig{wxLog::SetActiveTarget(&m_logBuf)}
    {
        delete m_logBuf.SetFormatter(new wxLogFormatterNone{});
    }

    ~wxLogCollector()
    {
        // Don't flush the messages in the buffer.
        m_logBuf.Clear();

        wxLog::SetActiveTarget(m_logOrig);
    }

    const wxString& GetMessages() const
    {
        return m_logBuf.GetBuffer();
    }

private:
    wxLogBuffer m_logBuf;
    wxLog* const m_logOrig;

    wxDECLARE_NO_COPY_CLASS(wxLogCollector);
};

// ----------------------------------------------------------------------------
// chaining log target: installs itself as a log target and passes all
// messages to the real log target given to it in the ctor but also forwards
// them to the previously active one
//
// note that you don't have to call SetActiveTarget() with this class, it
// does it itself in its ctor
// ----------------------------------------------------------------------------

class WXDLLIMPEXP_BASE wxLogChain : public wxLog
{
public:
    wxLogChain(wxLog *logger);
    virtual ~wxLogChain();

    // change the new log target
    void SetLog(wxLog *logger);

    // this can be used to temporarily disable (and then re-enable) passing
    // messages to the old logger (by default we do pass them)
    void PassMessages(bool bDoPass) { m_bPassMessages = bDoPass; }

    // are we passing the messages to the previous log target?
    bool IsPassingMessages() const { return m_bPassMessages; }

    // return the previous log target (may be null)
    wxLog *GetOldLog() const { return m_logOld; }

    // override base class version to flush the old logger as well
    virtual void Flush() override;

    // call to avoid destroying the old log target
    void DetachOldLog() { m_logOld = nullptr; }

protected:
    // pass the record to the old logger if needed
    virtual void DoLogRecord(wxLogLevel level,
                             const wxString& msg,
                             const wxLogRecordInfo& info) override;

private:
    // the current log target
    wxLog *m_logNew;

    // the previous log target
    wxLog *m_logOld;

    // do we pass the messages to the old logger?
    bool m_bPassMessages;

    wxDECLARE_NO_COPY_CLASS(wxLogChain);
};

// a chain log target which uses itself as the new logger

#define wxLogPassThrough wxLogInterposer

class WXDLLIMPEXP_BASE wxLogInterposer : public wxLogChain
{
public:
    wxLogInterposer();

private:
    wxDECLARE_NO_COPY_CLASS(wxLogInterposer);
};

// a temporary interposer which doesn't destroy the old log target
// (calls DetachOldLog)

class WXDLLIMPEXP_BASE wxLogInterposerTemp : public wxLogChain
{
public:
    wxLogInterposerTemp();

private:
    wxDECLARE_NO_COPY_CLASS(wxLogInterposerTemp);
};

#if wxUSE_GUI
    // include GUI log targets:
    #include "wx/generic/logg.h"
#endif // wxUSE_GUI

// ----------------------------------------------------------------------------
// wxLogger
// ----------------------------------------------------------------------------

// wxLogger is a helper class used by wxLogXXX() functions implementation,
// don't use it directly as it's experimental and subject to change (OTOH it
// might become public in the future if it's deemed to be useful enough)

// contains information about the context from which a log message originates
// and provides Log() vararg method which forwards to wxLog::OnLog() and passes
// this context to it
class wxLogger
{
public:
    // ctor takes the basic information about the log record
    wxLogger(wxLogLevel level,
             const char *filename,
             int line,
             const char *func,
             const char *component)
        : m_level(level),
          m_info(filename, line, func, component)
    {
    }

    // store extra data in our log record and return this object itself (so
    // that further calls to its functions could be chained)
    template <typename T>
    wxLogger& Store(const wxString& key, T val)
    {
        m_info.StoreValue(key, val);
        return *this;
    }

    // hack for "overloaded" wxLogXXX() functions: calling this method
    // indicates that we may have an extra first argument preceding the format
    // string and that if we do have it, we should store it in m_info using the
    // given key (while by default 0 value will be used)
    wxLogger& MaybeStore(const char* key, wxUIntPtr value = 0)
    {
        wxASSERT_MSG( m_optKey.empty(), "can only have one optional value" );

        // We only use keys defined in this file and we can be sure they
        // contain ASCII characters only.
        m_optKey = wxString::FromAscii(key);

        m_info.StoreValue(m_optKey, value);
        return *this;
    }


    // non-vararg function used by wxVLogXXX():

    // log the message at the level specified in the ctor if this log message
    // is enabled
    void LogV(const wxString& format, va_list argptr)
    {
        // remember that fatal errors can't be disabled
        if ( m_level == wxLOG_FatalError ||
                wxLog::IsLevelEnabled(m_level, wxASCII_STR(m_info.component)) )
            DoCallOnLog(wxString::FormatV(format, argptr));
    }

    // overloads used by functions with optional leading arguments (whose
    // values are stored in the key passed to MaybeStore())
    void LogV(long num, const wxString& format, va_list argptr)
    {
        Store(m_optKey, num);

        LogV(format, argptr);
    }

    void LogV(void *ptr, const wxString& format, va_list argptr)
    {
        Store(m_optKey, wxPtrToUInt(ptr));

        LogV(format, argptr);
    }

    void LogVTrace(const wxString& mask, const wxString& format, va_list argptr)
    {
        if ( !wxLog::IsAllowedTraceMask(mask) )
            return;

        Store(wxLOG_KEY_TRACE_MASK, mask);

        LogV(format, argptr);
    }


    // variadic functions used by wxLogXXX():

    // we need to use an extra class with a more restricted set of ctors than
    // wxString itself, as otherwise we'd get ambiguities between constructing
    // wxString from long
    struct FormatString : wxString
    {
        FormatString(const wxString& str) : wxString(str) {}
        FormatString(const wxCStrData& str) : wxString(str) {}
        FormatString(const wchar_t *str) : wxString(str) {}
        FormatString(const wxScopedWCharBuffer& str) : wxString(str) {}
#ifndef wxNO_IMPLICIT_WXSTRING_ENCODING
        FormatString(const char *str) : wxString(str) {}
        FormatString(const wxScopedCharBuffer& str) : wxString(str) {}
#endif // !wxNO_IMPLICIT_WXSTRING_ENCODING
    };

    // will log the message at the level specified in the ctor
    //
    // notice that this function supposes that the caller already checked that
    // the level was enabled and does no checks itself
    template <typename... Targs>
    void Log(const FormatString& format, Targs... args)
    {
        DoCallOnLog(wxString::Format(format, args...));
    }

    // overload used when there are no format specifiers: we want to avoid
    // using wxString::Format() in this case both because this would be
    // needlessly inefficient and because it would misinterpret any "%"
    // characters in the string as introducing format specifiers
    void Log(const wxString& s)
    {
        DoCallOnLog(s);
    }

    // same as Log() but with an extra numeric or pointer parameters: this is
    // used to pass an optional value by storing it in m_info under the name
    // passed to MaybeStore() and is required to support "overloaded" versions
    // of wxLogStatus() and wxLogSysError()
    template <typename... Targs>
    void Log(long num, const FormatString& format, Targs... args)
    {
        Store(m_optKey, num);

        DoCallOnLog(wxString::Format(format, args...));
    }

    void Log(long num, const wxString& s)
    {
        Store(m_optKey, num);

        DoCallOnLog(s);
    }

    // unfortunately we can't use "void *" here as we get overload ambiguities
    // with Log(FormatString, ...) when the first argument is a "char *" or
    // "wchar_t *" then -- so we only allow passing wxObject here, which is
    // ugly but fine in practice as this overload is only used by wxLogStatus()
    // whose first argument is a wxFrame
    template <typename... Targs>
    void Log(wxObject* ptr, const FormatString& format, Targs... args)
    {
        Store(m_optKey, wxPtrToUInt(ptr));

        DoCallOnLog(wxString::Format(format, args...));
    }

    void Log(wxObject* ptr, const wxString& s)
    {
        Store(m_optKey, wxPtrToUInt(ptr));

        DoCallOnLog(s);
    }

    // log the message at the level specified as its first argument
    //
    // as the macros don't have access to the level argument in this case, this
    // function does check that the level is enabled itself
    template <typename... Targs>
    void LogAtLevel(wxLogLevel level, const wxString& format, Targs... args)
    {
        if ( !wxLog::IsLevelEnabled(level, wxASCII_STR(m_info.component)) )
            return;

        DoCallOnLog(level, wxString::Format(format, args...));
    }

    void LogAtLevel(wxLogLevel level, const wxString& s)
    {
        if ( !wxLog::IsLevelEnabled(level, wxASCII_STR(m_info.component)) )
            return;

        DoCallOnLog(level, s);
    }

    // special versions for wxLogTrace() which is passed either string or
    // integer mask as first argument determining whether the message should be
    // logged or not
    template <typename... Targs>
    void LogTrace(const wxString& mask, const wxString& format, Targs... args)
    {
        if ( !wxLog::IsAllowedTraceMask(mask) )
            return;

        Store(wxLOG_KEY_TRACE_MASK, mask);

        DoCallOnLog(wxString::Format(format, args...));
    }

    void LogTrace(const wxString& mask, const wxString& s)
    {
        if ( !wxLog::IsAllowedTraceMask(mask) )
            return;

        Store(wxLOG_KEY_TRACE_MASK, mask);

        DoCallOnLog(s);
    }

private:
    void DoCallOnLog(wxLogLevel level, const wxString& msg)
    {
        // As explained in wxLogRecordInfo ctor, we don't initialize its
        // timestamp to avoid calling time() unnecessary, but now that we are
        // about to log the message, we do need to do it.
        m_info.timestampMS = wxGetUTCTimeMillis().GetValue();

#if WXWIN_COMPATIBILITY_3_0
        m_info.timestamp = m_info.timestampMS / 1000;
#endif // WXWIN_COMPATIBILITY_3_0

        wxLog::OnLog(level, msg, m_info);
    }

    void DoCallOnLog(const wxString& msg)
    {
        DoCallOnLog(m_level, msg);
    }


    const wxLogLevel m_level;
    wxLogRecordInfo m_info;

    wxString m_optKey;

    wxDECLARE_NO_COPY_CLASS(wxLogger);
};

// ============================================================================
// global functions
// ============================================================================

// ----------------------------------------------------------------------------
// get error code/error message from system in a portable way
// ----------------------------------------------------------------------------

// return the last system error code
WXDLLIMPEXP_BASE unsigned long wxSysErrorCode();

// return the error message for given (or last if 0) error code
WXDLLIMPEXP_BASE const wxChar* wxSysErrorMsg(unsigned long nErrCode = 0);

// return the error message for given (or last if 0) error code
WXDLLIMPEXP_BASE wxString wxSysErrorMsgStr(unsigned long nErrCode = 0);

// ----------------------------------------------------------------------------
// define wxLog<level>() functions which can be used by application instead of
// stdio, iostream &c for log messages for easy redirection
// ----------------------------------------------------------------------------

/*
    The code below is unreadable because it (unfortunately unavoidably)
    contains a lot of macro magic but all it does is to define wxLogXXX() such
    that you can call them as vararg functions to log a message at the
    corresponding level.

    More precisely, it defines:

        - wxLog{FatalError,Error,Warning,Message,Verbose,Debug}() functions
        taking the format string and additional vararg arguments if needed.
        - wxLogGeneric(wxLogLevel level, const wxString& format, ...) which
        takes the log level explicitly.
        - wxLogSysError(const wxString& format, ...) and wxLogSysError(long
        err, const wxString& format, ...) which log a wxLOG_Error severity
        message with the error message corresponding to the system error code
        err or the last error.
        - wxLogStatus(const wxString& format, ...) which logs the message into
        the status bar of the main application window and its overload
        wxLogStatus(wxFrame *frame, const wxString& format, ...) which logs it
        into the status bar of the specified frame.
        - wxLogTrace(Mask mask, const wxString& format, ...) which only logs
        the message is the specified mask is enabled. This comes in two kinds:
        Mask can be a wxString or a long. Both are deprecated.

    In addition, wxVLogXXX() versions of all the functions above are also
    defined. They take a va_list argument instead of "...".
 */

// creates wxLogger object for the current location
#define wxMAKE_LOGGER(level) \
    wxLogger(wxLOG_##level, __FILE__, __LINE__, __func__, wxLOG_COMPONENT)

// this macro generates the expression which logs whatever follows it in
// parentheses at the level specified as argument
#define wxDO_LOG(level) wxDO_LOG_WITH_FUNC(level, Log)

// generalization of the macro above that uses the given function of wxLogger
// object rather than the default "Log"
#define wxDO_LOG_WITH_FUNC(level, func) wxMAKE_LOGGER(level).func

// this is the non-vararg equivalent
#define wxDO_LOGV(level, format, argptr) \
    wxMAKE_LOGGER(level).LogV(format, argptr)

// Macro evaluating to true if logging at the given level is enabled.
#define wxLOG_IS_ENABLED(level) \
    wxLog::IsLevelEnabled(wxLOG_##level, wxASCII_STR(wxLOG_COMPONENT))

// Macro used to define most of the actual wxLogXXX() macros: just calls
// wxLogger::Log(), if logging at the specified level is enabled.
#define wxDO_LOG_IF_ENABLED(level)                                            \
    wxDO_IF(wxLOG_IS_ENABLED(level))                                          \
    wxDO_LOG(level)

// Similar to above, but calls the given function instead of Log().
#define wxDO_LOG_IF_ENABLED_WITH_FUNC(level, func)                            \
    wxDO_IF(wxLOG_IS_ENABLED(level))                                          \
    wxDO_LOG_WITH_FUNC(level, func)

// wxLogFatalError() is special as it can't be disabled
#define wxLogFatalError wxDO_LOG(FatalError)
#define wxVLogFatalError(format, argptr) wxDO_LOGV(FatalError, format, argptr)

#define wxLogError wxDO_LOG_IF_ENABLED(Error)
#define wxVLogError(format, argptr) wxDO_LOGV(Error, format, argptr)

#define wxLogWarning wxDO_LOG_IF_ENABLED(Warning)
#define wxVLogWarning(format, argptr) wxDO_LOGV(Warning, format, argptr)

#define wxLogMessage wxDO_LOG_IF_ENABLED(Message)
#define wxVLogMessage(format, argptr) wxDO_LOGV(Message, format, argptr)

#define wxLogInfo wxDO_LOG_IF_ENABLED(Info)
#define wxVLogInfo(format, argptr) wxDO_LOGV(Info, format, argptr)


// this one is special as it only logs if we're in verbose mode
#define wxLogVerbose                                                          \
    wxDO_IF(wxLOG_IS_ENABLED(Info) && wxLog::GetVerbose())                    \
    wxDO_LOG(Info)

#define wxVLogVerbose(format, argptr)                                         \
    wxDO_IF(wxLOG_IS_ENABLED(Info) && wxLog::GetVerbose())                    \
    wxDO_LOGV(Info, format, argptr)

// another special case: the level is passed as first argument of the function
// and so is not available to the macro
//
// notice that because of this, arguments of wxLogGeneric() are currently
// always evaluated, unlike for the other log functions
#define wxLogGeneric wxMAKE_LOGGER(Max).LogAtLevel
#define wxVLogGeneric(level, format, argptr) \
    wxDO_IF(wxLOG_IS_ENABLED(level))                                          \
    wxDO_LOGV(level, format, argptr)


// wxLogSysError() needs to stash the error code value in the log record info
// so it needs special handling too; additional complications arise because the
// error code may or not be present as the first argument
//
// notice that we unfortunately can't avoid the call to wxSysErrorCode() even
// though it may be unneeded if an explicit error code is passed to us because
// the message might not be logged immediately (e.g. it could be queued for
// logging from the main thread later) and so we can't to wait until it is
// logged to determine whether we have last error or not as it will be too late
// and it will have changed already by then (in fact it even changes when
// wxString::Format() is called because of vsnprintf() inside it so it can
// change even much sooner)
#define wxLOG_KEY_SYS_ERROR_CODE "wx.sys_error"

#define wxLogSysError \
    wxDO_LOG_IF_ENABLED_WITH_FUNC(Error, MaybeStore(wxLOG_KEY_SYS_ERROR_CODE, \
                                                    wxSysErrorCode()).Log)

// unfortunately we can't have overloaded macros so we can't define versions
// both with and without error code argument and have to rely on LogV()
// overloads in wxLogger to select between them
#define wxVLogSysError \
    wxMAKE_LOGGER(Error).MaybeStore(wxLOG_KEY_SYS_ERROR_CODE, \
                                    wxSysErrorCode()).LogV

#if wxUSE_GUI
    // wxLogStatus() is similar to wxLogSysError() as it allows to optionally
    // specify the frame to which the message should go
    #define wxLOG_KEY_FRAME "wx.frame"

    #define wxLogStatus \
        wxDO_LOG_IF_ENABLED_WITH_FUNC(Status, MaybeStore(wxLOG_KEY_FRAME).Log)

    #define wxVLogStatus \
        wxMAKE_LOGGER(Status).MaybeStore(wxLOG_KEY_FRAME).LogV
#endif // wxUSE_GUI


#else // !wxUSE_LOG

#undef wxUSE_LOG_DEBUG
#define wxUSE_LOG_DEBUG 0

#undef wxUSE_LOG_TRACE
#define wxUSE_LOG_TRACE 0

// define macros for defining log functions which do nothing at all
#define wxDEFINE_EMPTY_LOG_FUNCTION(level)                                  \
    template <typename... Targs>                                            \
    void wxLog##level(const wxString& WXUNUSED(format), Targs...) { }       \
    inline void wxVLog##level(const wxString& WXUNUSED(format),             \
                              va_list WXUNUSED(argptr)) { }                 \

#define wxDEFINE_EMPTY_LOG_FUNCTION2(level, argclass)                       \
    template <typename... Targs>                                            \
    void wxLog##level(argclass WXUNUSED(arg),                               \
                      const wxString& WXUNUSED(format), Targs...) { }       \
    inline void wxVLog##level(argclass WXUNUSED(arg),                       \
                              const wxString& WXUNUSED(format),             \
                              va_list WXUNUSED(argptr)) {}

wxDEFINE_EMPTY_LOG_FUNCTION(FatalError);
wxDEFINE_EMPTY_LOG_FUNCTION(Error);
wxDEFINE_EMPTY_LOG_FUNCTION(SysError);
wxDEFINE_EMPTY_LOG_FUNCTION2(SysError, long);
wxDEFINE_EMPTY_LOG_FUNCTION(Warning);
wxDEFINE_EMPTY_LOG_FUNCTION(Message);
wxDEFINE_EMPTY_LOG_FUNCTION(Info);
wxDEFINE_EMPTY_LOG_FUNCTION(Verbose);

wxDEFINE_EMPTY_LOG_FUNCTION2(Generic, wxLogLevel);

#if wxUSE_GUI
    wxDEFINE_EMPTY_LOG_FUNCTION(Status);
    wxDEFINE_EMPTY_LOG_FUNCTION2(Status, wxFrame *);
#endif // wxUSE_GUI

// Empty Class to fake wxLogNull
class WXDLLIMPEXP_BASE wxLogNull
{
public:
    wxLogNull() = default;
};

// Dummy macros to replace some functions.
#define wxSysErrorCode() (unsigned long)0
#define wxSysErrorMsg( X ) (const wxChar*)nullptr
#define wxSysErrorMsgStr( X ) wxEmptyString

// Fake symbolic trace masks... for those that are used frequently
#define wxTRACE_OleCalls wxEmptyString // OLE interface calls

#endif // wxUSE_LOG/!wxUSE_LOG


// debug functions can be completely disabled in optimized builds

// if these log functions are disabled, we prefer to define them as (empty)
// variadic macros as this completely removes them and their argument
// evaluation from the object code but if this is not supported by compiler we
// use empty inline functions instead (defining them as nothing would result in
// compiler warnings)
//
// note that making wxVLogDebug/Trace() themselves (empty inline) functions is
// a bad idea as some compilers are stupid enough to not inline even empty
// functions if their parameters are complicated enough, but by defining them
// as an empty inline function we ensure that even dumbest compilers optimise
// them away
inline void wxLogNop() { }

#if wxUSE_LOG_DEBUG
    #define wxLogDebug wxDO_LOG_IF_ENABLED(Debug)
    #define wxVLogDebug(format, argptr) wxDO_LOGV(Debug, format, argptr)
#else // !wxUSE_LOG_DEBUG
    #define wxVLogDebug(fmt, valist) wxLogNop()
    #define wxLogDebug(fmt, ...) wxLogNop()
#endif // wxUSE_LOG_DEBUG/!wxUSE_LOG_DEBUG

#if wxUSE_LOG_TRACE
    #define wxLogTrace wxDO_LOG_IF_ENABLED_WITH_FUNC(Trace, LogTrace)
    #define wxVLogTrace wxDO_LOG_IF_ENABLED_WITH_FUNC(Trace, LogVTrace)
#else  // !wxUSE_LOG_TRACE
    #define wxVLogTrace(mask, fmt, valist) wxLogNop()
    #define wxLogTrace(mask, fmt, ...) wxLogNop()
#endif // wxUSE_LOG_TRACE/!wxUSE_LOG_TRACE

// wxLogFatalError helper: show the (fatal) error to the user in a safe way,
// i.e. without using wxMessageBox() for example because it could crash
bool WXDLLIMPEXP_BASE
wxSafeShowMessage(const wxString& title, const wxString& text);

// ----------------------------------------------------------------------------
// debug only logging functions: use them with API name and error code
// ----------------------------------------------------------------------------

#if wxUSE_LOG_DEBUG
    // make life easier for people using VC++ IDE: clicking on the message
    // will take us immediately to the place of the failed API
#ifdef __VISUALC__
    #define wxLogApiError(api, rc)                                            \
        wxLogDebug(wxT("%s(%d): '%s' failed with error 0x%08lx (%s)."),       \
                   __TFILE__, __LINE__, api,                                  \
                   (long)rc, wxSysErrorMsgStr(rc))
#else // !VC++
    #define wxLogApiError(api, rc)                                            \
        wxLogDebug(wxT("In file %s at line %d: '%s' failed with ")            \
                   wxT("error 0x%08lx (%s)."),                                \
                   __TFILE__, __LINE__, api,                                  \
                   (long)rc, wxSysErrorMsgStr(rc))
#endif // VC++/!VC++

    #define wxLogLastError(api) wxLogApiError(api, wxSysErrorCode())

#else // !wxUSE_LOG_DEBUG
    #define wxLogApiError(api, err) wxLogNop()
    #define wxLogLastError(api) wxLogNop()
#endif // wxUSE_LOG_DEBUG/!wxUSE_LOG_DEBUG

// macro which disables debug logging in release builds: this is done by
// default by wxIMPLEMENT_APP() so usually it doesn't need to be used explicitly
#if defined(NDEBUG) && wxUSE_LOG_DEBUG
    #define wxDISABLE_DEBUG_LOGGING_IN_RELEASE_BUILD() \
        wxLog::SetLogLevel(wxLOG_Info)
#else // !NDEBUG
    #define wxDISABLE_DEBUG_LOGGING_IN_RELEASE_BUILD()
#endif // NDEBUG/!NDEBUG

#endif  // _WX_LOG_H_

