/*Copyright (C) 2010-2023 Duncan Deveaux

This file is part of Hikou no mizu.

Hikou no mizu is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

Hikou no mizu is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Hikou no mizu.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "Log.hpp"

#include <iostream>
#include <sstream>

namespace Log
{
    namespace
    {
        Decoration errorDecoration(Color(255, 0, 0));
    }

    ////////////////
    ///Decoration///
    ////////////////
    Decoration::Decoration(Emphasis emph) :
    m_mode(Decoration::ColorMode::None), m_emphasis(emph)
    {
        generateANSI();
    }

    Decoration::Decoration(const Color &fg, Emphasis emph) :
    m_color1(fg), m_mode(Decoration::ColorMode::Foreground), m_emphasis(emph)
    {
        generateANSI();
    }

    Decoration::Decoration(const Color &fg, const Color &bg, Emphasis emph) :
    m_color1(fg), m_color2(bg), m_mode(Decoration::ColorMode::FgAndBg), m_emphasis(emph)
    {
        generateANSI();
    }

    void Decoration::generateANSI()
    {
        if (m_mode == Decoration::ColorMode::None)
        {
            m_ansiCodes.clear();
            return;
        }

        std::ostringstream ansiText;

        if (m_emphasis == Decoration::Emphasis::Bold) ansiText << "\x1b[1m";
        else if (m_emphasis == Decoration::Emphasis::Faint) ansiText << "\x1b[2m";
        else if (m_emphasis == Decoration::Emphasis::Italic) ansiText << "\x1b[3m";

        ansiText << "\x1b[38;2;" << +m_color1.red << ";"
                                 << +m_color1.green << ";"
                                 << +m_color1.blue << "m";

        if (m_mode == Decoration::ColorMode::FgAndBg)
        {
            ansiText << "\x1b[48;2;" << +m_color2.red << ";"
                                     << +m_color2.green << ";"
                                     << +m_color2.blue << "m";
        }

        m_ansiCodes = ansiText.str();
    }

    std::string Decoration::apply(const std::string &str) const
    {
        return m_ansiCodes + str + "\x1b[0m";
    }

    void info(const std::string &info)
    {
        std::cout << info << std::endl;
    }

    #ifdef _WIN32
        void info(const std::string &info, const Decoration &/*style*/)
        {
            std::cout << info << std::endl;
        }
    #else
        void info(const std::string &info, const Decoration &style)
        {
            std::cout << style.apply(info) << std::endl;
        }
    #endif

    void err(const std::string &error)
    {
        #ifdef _WIN32
            std::cerr << "Error: " << error << std::endl;
        #else
            std::cerr << errorDecoration.apply("Error: " + error) << std::endl;
        #endif
    }
}
