// This is a color lib made by cosf.
// Please include this text while using this lib.
// (2024-2-23 by cosf)

// Defined colors:
// black, red, green, yellow, blue, magenta,
// cyan, white, light_black, light_red,
// light_green, light_yellow, light_blue,
// light_magenta, light_cyan, light_white,
// reset.
//
// Defined function:
// endc(used by stream operators) (endl + reset)
// color(fore, back, light): to create a color with specified color values (ANSI).
// DEFINE_COLOR(name, fore, back, light): same as "Color name = color(fore, back, light);" but with static and const features.
//
// Settings:
// USE_COLOR                  : to determine whether to use color (1) or to set all color to "reset" (0).
// SET_ANSI_COLOR_IF_AVAILABLE: to determine whether to use ANSI meaning-transferring char codes to perform color (1) or not (0).
// REVERSE_COLOR              : to determine whether to set the background to black (0) or white (1).
// USE_NAMESOACE              : to determine whether to declare a namespace called "color" to store the variables (1) or not (0).
//
// Types & Classes:
// Color { int fore, back, light; }: a structure to store a color.
//
// Notice:
// ANSI codes and windows' text attributes are slightly different:
// color(31, 47, 0) may perform a white-based red color in ANSI codes,
// but it may perform a white-based blue color in windows' text attributes.
//
// (2024-2-23 by cosf)

#ifndef COLOR_LIB
#define COLOR_LIB

// These are settings

#define USE_COLOR 1

#if (defined(__WINDOWS_) || defined(_WIN32))
#define SET_ANSI_COLOR_IF_AVAILABLE 0
#else                                 // (defined(__WINDOWS) || defined(_WIN32))
#define SET_ANSI_COLOR_IF_AVAILABLE 1 // do NOT set
#endif                                // (defined(__WINDOWS) || defined(_WIN32))

// settings end

#define REVERSE_COLOR 1
#define USE_NAMESPACE 1

#include <iostream>
#include <string>

#if (defined(__WINDOWS) || defined(_WIN32))
#include <windows.h>
#endif // (defined(__WINDOWS) || defined(_WIN32))

#if USE_NAMESPACE

namespace color
{

#endif // USE_NAMESPACE

    struct Color
    {
        int fore, back, light;
    };

    static Color color(int fore, int back, int light)
    {
        return {fore, back, light};
    }

#define DEFINE_COLOR(name, fore, back, light) static const Color name = {fore, back, light};

#if USE_COLOR

#if SET_ANSI_COLOR_IF_AVAILABLE

#if REVERSE_COLOR

    DEFINE_COLOR(black, 30, 47, 0);
    DEFINE_COLOR(red, 31, 47, 0);
    DEFINE_COLOR(green, 32, 47, 0);
    DEFINE_COLOR(yellow, 33, 47, 0);
    DEFINE_COLOR(blue, 34, 47, 0);
    DEFINE_COLOR(magenta, 35, 47, 0);
    DEFINE_COLOR(cyan, 36, 47, 0);
    DEFINE_COLOR(white, 37, 47, 0);
    DEFINE_COLOR(light_black, 30, 47, 1);
    DEFINE_COLOR(light_red, 31, 47, 1);
    DEFINE_COLOR(light_green, 32, 47, 1);
    DEFINE_COLOR(light_yellow, 33, 47, 1);
    DEFINE_COLOR(light_blue, 34, 47, 1);
    DEFINE_COLOR(light_magenta, 35, 47, 1);
    DEFINE_COLOR(light_cyan, 36, 47, 1);
    DEFINE_COLOR(light_white, 37, 47, 1);

#else // REVERSE_COLOR

    DEFINE_COLOR(black, 30, 40, 0);
    DEFINE_COLOR(red, 31, 40, 0);
    DEFINE_COLOR(green, 32, 40, 0);
    DEFINE_COLOR(yellow, 33, 40, 0);
    DEFINE_COLOR(blue, 34, 40, 0);
    DEFINE_COLOR(magenta, 35, 40, 0);
    DEFINE_COLOR(cyan, 36, 40, 0);
    DEFINE_COLOR(white, 37, 40, 0);
    DEFINE_COLOR(light_black, 30, 40, 1);
    DEFINE_COLOR(light_red, 31, 40, 1);
    DEFINE_COLOR(light_green, 32, 40, 1);
    DEFINE_COLOR(light_yellow, 33, 40, 1);
    DEFINE_COLOR(light_blue, 34, 40, 1);
    DEFINE_COLOR(light_magenta, 35, 40, 1);
    DEFINE_COLOR(light_cyan, 36, 40, 1);
    DEFINE_COLOR(light_white, 37, 40, 1);

#endif // REVERSE_COLOR

#else // SET_ANSI_COLOR_IF_AVAILABLE

#if REVERSE_COLOR

    DEFINE_COLOR(black, 30, 47, 0);
    DEFINE_COLOR(blue, 31, 47, 0);
    DEFINE_COLOR(green, 32, 47, 0);
    DEFINE_COLOR(cyan, 33, 47, 0);
    DEFINE_COLOR(red, 34, 47, 0);
    DEFINE_COLOR(magenta, 35, 47, 0);
    DEFINE_COLOR(yellow, 36, 47, 0);
    DEFINE_COLOR(white, 37, 47, 0);
    DEFINE_COLOR(light_black, 30, 47, 1);
    DEFINE_COLOR(light_blue, 31, 47, 1);
    DEFINE_COLOR(light_green, 32, 47, 1);
    DEFINE_COLOR(light_cyan, 33, 47, 1);
    DEFINE_COLOR(light_red, 34, 47, 1);
    DEFINE_COLOR(light_magenta, 35, 47, 1);
    DEFINE_COLOR(light_yellow, 36, 47, 1);
    DEFINE_COLOR(light_white, 37, 47, 1);

#else // REVERSE_COLOR

    DEFINE_COLOR(black, 30, 40, 0);
    DEFINE_COLOR(blue, 31, 40, 0);
    DEFINE_COLOR(green, 32, 40, 0);
    DEFINE_COLOR(cyan, 33, 40, 0);
    DEFINE_COLOR(red, 34, 40, 0);
    DEFINE_COLOR(magenta, 35, 40, 0);
    DEFINE_COLOR(yellow, 36, 40, 0);
    DEFINE_COLOR(white, 37, 40, 0);
    DEFINE_COLOR(light_black, 30, 40, 1);
    DEFINE_COLOR(light_blue, 31, 40, 1);
    DEFINE_COLOR(light_green, 32, 40, 1);
    DEFINE_COLOR(light_cyan, 33, 40, 1);
    DEFINE_COLOR(light_red, 34, 40, 1);
    DEFINE_COLOR(light_magenta, 35, 40, 1);
    DEFINE_COLOR(light_yellow, 36, 40, 1);
    DEFINE_COLOR(light_white, 37, 40, 1);

#endif // REVERSE_COLOR

#endif // SET_ANSI_COLOR_IF_AVAILABLE

#else // USE_COLOR

DEFINE_COLOR(black, 0, 0, 0);
DEFINE_COLOR(red, 0, 0, 0);
DEFINE_COLOR(green, 0, 0, 0);
DEFINE_COLOR(yellow, 0, 0, 0);
DEFINE_COLOR(blue, 0, 0, 0);
DEFINE_COLOR(magenta, 0, 0, 0);
DEFINE_COLOR(cyan, 0, 0, 0);
DEFINE_COLOR(white, 0, 0, 0);
DEFINE_COLOR(light_black, 0, 0, 0);
DEFINE_COLOR(light_red, 0, 0, 0);
DEFINE_COLOR(light_green, 0, 0, 0);
DEFINE_COLOR(light_yellow, 0, 0, 0);
DEFINE_COLOR(light_blue, 0, 0, 0);
DEFINE_COLOR(light_magenta, 0, 0, 0);
DEFINE_COLOR(light_cyan, 0, 0, 0);
DEFINE_COLOR(light_white, 0, 0, 0);

#endif // USE_COLOR

    DEFINE_COLOR(reset, 0, 0, 0);

#if USE_NAMESPACE
}

#endif // USE_NAMESPACE

template <typename _CT, typename _T>
inline std::basic_ostream<_CT, _T> &operator<<(std::basic_ostream<_CT, _T> &os, color::Color cw)
{
#if SET_ANSI_COLOR_IF_AVAILABLE // UNABLE? TODO
    os << std::string("\e[") + (cw.light ? "1;" : "") + std::to_string(cw.fore) + (cw.back != 47 ? ";" + std::to_string(cw.back) : "") + "m";
#elif (defined(__WINDOWS_) || defined(_WIN32))
    SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), (cw.fore - 30) | (cw.light << 3) | ((cw.back - 40) << 4));
#else // SET_ANSI_COLOR_IF_AVAILABLE || (defined(__WINDOWS_) || defined(_WIN32))
#error "Unable to use ansi color renderer or windows color renderer!"
#endif // SET_ANSI_COLOR_IF_AVAILABLE || (defined(__WINDOWS_) || defined(_WIN32))
    return os;
}

#if USE_NAMESPACE
namespace color
{
#endif // USE_NAMESPACE
    template <typename _CT, typename _T>
    inline std::basic_ostream<_CT, _T> &endc(std::basic_ostream<_CT, _T> &os)
    {
        return os << reset << std::endl;
    }

#if USE_NAMESPACE
}
#endif // USE_NAMESPACE

#endif // COLOR_LIB