/*
 * SPDX-FileCopyrightText: 2000-2002 Copyright LifeLine Networks BV (www.lifeline.nl)
 * SPDX-FileCopyrightText: 2000-2002 Copyright Bastiaan Bakker
 * SPDX-FileCopyrightText: 2004 Copyright contributors to the cppTango project
 *
 * SPDX-License-Identifier: LGPL-3.0-or-later
 */

#include <tango/common/log4tango/Portability.h>

#ifdef TANGO_HAVE_UNISTD_H
  #include <unistd.h>
#endif

#include <tango/internal/log4tango/StringUtil.h>

#include <tango/common/log4tango/Logger.h>

#include <mutex>

namespace log4tango
{

Logger::Logger(const std::string &name, Level::Value level) :
    _name(name),
    _level(level)
{
    // no-op
}

Logger::~Logger() { }

void Logger::set_level(Level::Value level)
{
    if((level >= Level::OFF) && (level <= Level::DEBUG))
    {
        _level = level;
        { //-- Begin critical section -----------------------------
            std::scoped_lock guard{_appendersMutex};
            if(!_appenders.empty())
            {
                auto i = _appenders.begin();
                auto e = _appenders.end();
                for(; i != e; ++i)
                {
                    i->second->level_changed(_level);
                }
            }
        } //-- End critical section ------------------------------
    }
}

void Logger::call_appenders(const LoggingEvent &event)
{
    std::vector<std::string> *bad_appenders = nullptr;
    { //-- Begin critical section -----------------------------
        std::scoped_lock guard{_appendersMutex};
        if(!_appenders.empty())
        {
            auto i = _appenders.begin();
            auto e = _appenders.end();
            for(; i != e; ++i)
            {
                if(i->second->append(event) == -1)
                {
                    if(bad_appenders == nullptr)
                    {
                        bad_appenders = new std::vector<std::string>;
                    }
                    if(bad_appenders != nullptr)
                    {
                        bad_appenders->push_back(i->second->get_name());
                    }
                }
            }
        }
    } //-- End critical section ------------------------------
    if(bad_appenders != nullptr)
    {
        for(unsigned int a = 0; a < bad_appenders->size(); a++)
        {
            remove_appender((*bad_appenders)[a]);
        }
        delete bad_appenders;
    }
}

void Logger::log_unconditionally(const std::string &file, int line, Level::Value level, const char *format, ...)
{
    va_list va;
    va_start(va, format);
    log_unconditionally(file, line, level, StringUtil::vform(format, va));
    va_end(va);
}

void Logger::log_unconditionally(const std::string &file, int line, Level::Value level, const std::string &message)
{
    LoggingEvent event{get_name(), message, level, file, line};
    call_appenders(event);
}

void Logger::log(const std::string &file, int line, Level::Value level, const char *format, ...)
{
    if(is_level_enabled(level))
    {
        va_list va;
        va_start(va, format);
        log_unconditionally(file, line, level, StringUtil::vform(format, va));
        va_end(va);
    }
}

void Logger::debug(const std::string &file, int line, const char *format, ...)
{
    if(is_level_enabled(Level::DEBUG))
    {
        va_list va;
        va_start(va, format);
        log_unconditionally(file, line, Level::DEBUG, StringUtil::vform(format, va));
        va_end(va);
    }
}

void Logger::info(const std::string &file, int line, const char *format, ...)
{
    if(is_level_enabled(Level::INFO))
    {
        va_list va;
        va_start(va, format);
        log_unconditionally(file, line, Level::INFO, StringUtil::vform(format, va));
        va_end(va);
    }
}

void Logger::warn(const std::string &file, int line, const char *format, ...)
{
    if(is_level_enabled(Level::WARN))
    {
        va_list va;
        va_start(va, format);
        log_unconditionally(file, line, Level::WARN, StringUtil::vform(format, va));
        va_end(va);
    }
}

void Logger::error(const std::string &file, int line, const char *format, ...)
{
    if(is_level_enabled(Level::ERROR))
    {
        va_list va;
        va_start(va, format);
        log_unconditionally(file, line, Level::ERROR, StringUtil::vform(format, va));
        va_end(va);
    }
}

void Logger::fatal(const std::string &file, int line, const char *format, ...)
{
    if(is_level_enabled(Level::FATAL))
    {
        va_list va;
        va_start(va, format);
        log_unconditionally(file, line, Level::FATAL, StringUtil::vform(format, va));
        va_end(va);
    }
}

} // namespace log4tango
