/**
 *
 * @file src/trace/values/Color.cpp
 *
 * @copyright 2008-2024 Bordeaux INP, CNRS (LaBRI UMR 5800), Inria,
 *                      Univ. Bordeaux. All rights reserved.
 *
 * @author Camille Ordronneau
 * @author Johnny Jazeix
 * @author Mathieu Faverge
 * @author Olivier Lagrasse
 * @author Clement Vuchener
 *
 * @date 2024-07-17
 */

#include <string>
#include <iostream>
#include <sstream>
#include <iomanip> // For std::setprecision
#include <cstdlib>
/* -- */
#include "common/Tools.hpp"
/* -- */
#include "trace/values/Value.hpp"
#include "trace/values/Color.hpp"

using namespace std;

double
Color::check_value(double v, const string &spectrum) {
    if (v < 0.) {
        cerr << "Invalid value for " << spectrum << " color " << v << " (must be between 0. and 1.)" << endl;
        v = 0.;
    }
    /* Extra Test for StarPU bug in state color values */
    if (v > 1.) {
        v = v / 255.;
    }
    if (v > 1.) {
        cerr << "Invalid value for " << spectrum << " color " << v << " (must be between 0. and 1.)" << endl;
        v = 1.;
    }
    return v;
}

Color::Color() :
    _r((rand() % 256) / 255.),
    _g((rand() % 256) / 255.),
    _b((rand() % 256) / 255.) {
    _is_correct = true;
}

Color::Color(double r, double g, double b) {
    _r = Color::check_value(r, "red");
    _g = Color::check_value(g, "green");
    _b = Color::check_value(b, "blue");
    _is_correct = true;
}

Color::Color(const Color &c) :
    Value(c), _r(c._r), _g(c._g), _b(c._b) {
    _is_correct = c._is_correct;
}

Color::Color(const Color *c) :
    Value(*c), _r(c->_r), _g(c->_g), _b(c->_b) {
    _is_correct = c->_is_correct;
}

Color::Color(const std::string &in) {
    double r = 0, g = 0, b = 0;
    string separated_color[3];
    string temp = in;

    for (auto &i: separated_color) {
        size_t position_of_space = temp.find(' ');
        i = temp.substr(0, position_of_space);
        temp = temp.substr(position_of_space + 1);
    }

    _is_correct = convert_to_double(separated_color[0], &r) && convert_to_double(separated_color[1], &g) && convert_to_double(separated_color[2], &b);

    _r = Color::check_value(r, "red");
    _g = Color::check_value(g, "green");
    _b = Color::check_value(b, "blue");
}

std::string Color::to_string() const {
    std::ostringstream oss;
    oss << "<font color=\"#";
    oss << std::hex << std::setfill('0');
    ;
    oss << std::setw(2) << (int)(_r * 255 + 0.5) % 256
        << std::setw(2) << (int)(_g * 255 + 0.5) % 256
        << std::setw(2) << (int)(_b * 255 + 0.5) % 256;
    oss << "\">";
    oss << std::dec << std::setprecision(Value::_PRECISION) << _r << " " << _g << " " << _b;
    oss << "</font>";
    return oss.str();
}

double Color::get_red() const {
    return _r;
}

double Color::get_green() const {
    return _g;
}

double Color::get_blue() const {
    return _b;
}
