#pragma once

#include "log.h"
#include <library/cpp/logger/global/global.h>

namespace NLoggingImpl {
    ///
    /// @brief A routine to write a specific kind of TLogElement to the global log
    /// @param log Log object obtained from TLoggerOperator
    /// @param componentLogEl Log record resulted from TComponentLogFormatter.
    ///     Must be a string like "file.cpp:12: Message" or "Message", without EOL and without Priority prefix
    /// @param subsystemName An extra log prefix to be put, like the name of the component, or id of an operation (must be pre-formatted)
    ///
    inline void WriteToGlobalLog(TLog& log, const TLogRecord& componentLogEl, TStringBuf subsystemName) {
        TStringBuf stdGlobalMessage;
        ELogPriority prio = componentLogEl.Priority;
        switch (prio) {
            case TLOG_EMERG:
            case TLOG_ALERT:
                prio = TLOG_CRIT;
                //goto next
            case TLOG_CRIT:
                stdGlobalMessage = TStringBuf("CRITICAL_INFO");
                break;
            case TLOG_ERR:
                stdGlobalMessage = TStringBuf("ERROR");
                break;
            case TLOG_WARNING:
                stdGlobalMessage = TStringBuf("WARNING");
                break;
            case TLOG_NOTICE:
                stdGlobalMessage = TStringBuf("NOTICE");
                break;
            case TLOG_INFO:
                stdGlobalMessage = TStringBuf("INFO");
                break;
            case TLOG_DEBUG:
                stdGlobalMessage = TStringBuf("DEBUG");
                break;
            case TLOG_RESOURCES:
                stdGlobalMessage = TStringBuf("RESOURCES");
                break;
                // no default, to trigger compile warning if the enum changes
        }
        TLogElement el(&log, prio);
        el << stdGlobalMessage << ": " << NLoggingImpl::GetLocalTimeS() << " " << subsystemName << TStringBuf(componentLogEl.Data, componentLogEl.Len) << Endl;
    }

    template <typename TLog>
    class TComponentBackendBase: public TLogBackend {
    private:
        TAutoPtr<TLogBackend> Callback;
        TStringBuf ComponentPrefix;
        ELogPriority LogLevel;

    public:
        TComponentBackendBase(TStringBuf prefix, ELogPriority filtrationLevel = LOG_MAX_PRIORITY)
            : ComponentPrefix(prefix)
            , LogLevel(filtrationLevel)
        {
        }

        TLogBackend* GetCallback() const {
            return Callback.Get();
        }

        void ResetCallback(TAutoPtr<TLogBackend> callback) {
            Callback = callback;
        }

    public:
        virtual void WriteData(const TLogRecord& rec) override {
            WriteToGlobalLog(TLoggerOperator<TLog>::Log(), rec, ComponentPrefix);
            if (Callback) {
                Callback->WriteData(rec);
            }
        }

        virtual void ReopenLog() override {
        }

        virtual ELogPriority FiltrationLevel() const override {
            return LogLevel;
        }
    };

    using TComponentLogBackend = TComponentBackendBase<TGlobalLog>;
}
