/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * Copyright 2012-2016 Danny Robson <danny@nerdcruft.net>
 */


#include "log.hpp"

#include "../cast.hpp"
#include "../string.hpp"

#include "sink/console.hpp"

#include <mutex>
#include <map>
#include <string>


///////////////////////////////////////////////////////////////////////////////
bool
cruft::log::needs_break (level_t level)
{
    static level_t break_level;

    static bool has_level = [&] (void) {
        const char *env = getenv ("BREAK_LEVEL");
        if (!env)
            return false;

        try {
            break_level = cruft::log::to_level (env);
            return true;
        } catch (...) {
            return false;
        }
    } ();

    return has_level && level <= break_level;
}


///////////////////////////////////////////////////////////////////////////////
// mingw#xxx: MinGW doesn't have once_flag so we just use an atomic bool.
// Pray that multiple threads don't run into an issue here.
static std::atomic<bool> s_sink_init;
static std::unique_ptr<cruft::log::sink::base> s_default_sink;


//-----------------------------------------------------------------------------
cruft::log::sink::base&
cruft::log::default_sink (std::unique_ptr<sink::base> value)
{
    s_default_sink = std::move (value);
    return *s_default_sink;
}


//-----------------------------------------------------------------------------
cruft::log::sink::base&
cruft::log::default_sink ()
{
    if (unlikely (!s_sink_init)) {
        default_sink (
            std::make_unique<sink::console> (PACKAGE_NAME)
        );
        s_sink_init = true;
    }

    return *s_default_sink;
}


///////////////////////////////////////////////////////////////////////////////
void
cruft::log::write (level_t level, const std::string &msg)
{
    return write (level, std::string_view (msg));
}


//-----------------------------------------------------------------------------
void
cruft::log::write (level_t level, char const *msg)
{
    return write (level, std::string_view (msg));
}


//-----------------------------------------------------------------------------
void
cruft::log::write (level_t level, std::string_view msg)
{
    return default_sink ().write (
        packet (level, msg)
    );
}