#include "Types.h"

#include <array>
#include <memory_resource>

namespace renderive {
namespace {

constexpr std::size_t domain_count = static_cast<std::size_t>(Memory_Domain::Count);

auto& domain_resources() {
    static std::array<std::pmr::synchronized_pool_resource, domain_count> resources;
    return resources;
}

std::vector<Pixel> default_gradient() {
    std::vector<Pixel> colors;
    colors.reserve(256);
    for (int index = 0; index < 256; ++index) {
        const double x = static_cast<double>(index) / 255.0;
        const auto channel = [x](double center) {
            const double value = 1.5 - std::abs(4.0 * x - center);
            return static_cast<std::uint8_t>(std::clamp(value, 0.0, 1.0) * 255.0 + 0.5);
        };
        colors.push_back(pack_rgba(channel(3.0), channel(2.0), channel(1.0)));
    }
    return colors;
}

} // namespace

std::pmr::memory_resource* memory_resource() noexcept {
    return memory_resource(Memory_Domain::Other);
}

std::pmr::memory_resource* memory_resource(Memory_Domain domain) noexcept {
    auto index = static_cast<std::size_t>(domain);
    if (index >= domain_count)
        index = static_cast<std::size_t>(Memory_Domain::Other);
    return &domain_resources()[index];
}

Color_Map::Color_Map() : colors_(default_gradient()) {}

Color_Map::Color_Map(std::vector<Pixel> colors) {
    set_colors(std::move(colors));
}

void Color_Map::set_colors(std::vector<Pixel> colors) {
    colors_ = std::move(colors);
    if (colors_.empty())
        colors_ = default_gradient();
}

Pixel Color_Map::at_normalized(double value) const noexcept {
    if (colors_.empty())
        return 0;
    value = std::clamp(value, 0.0, 1.0);
    const auto index = static_cast<std::size_t>(value * static_cast<double>(colors_.size() - 1));
    return colors_[index];
}

} // namespace renderive

