#include "tile/base/encoding/detail/hex_chars.h"

namespace tile {
namespace detail {

namespace {
static constexpr auto kCharMin = std::numeric_limits<char>::min();
static constexpr auto kCharMax = std::numeric_limits<char>::max();
static constexpr auto kSize    = kCharMax - kCharMin + 1;

int
AsciiCodeFromCharPairSlow(char a, char b)
{
    a          = ToLower(a);
    b          = ToLower(b);
    auto ToNum = [](char x) {
        if (x >= '0' && x <= '9') {
            return x - '0';
        } else if (x >= 'a' && x <= 'f') {
            return x - 'a' + 10;
        } else {
            return -1;
        }
    };

    int x = ToNum(a);
    int y = ToNum(b);
    if (x == -1 || y == -1) { return -1; }

    return (x << 4) | y;
}

std::pair<char, char>
AsciiCodeToCharPairSlow(std::uint8_t value, bool uppercase)
{
    if (uppercase) {
        return std::make_pair(kHexCharsUpper[value >> 4], kHexCharsUpper[value & 0x0f]);
    } else {
        return std::make_pair(kHexCharsLower[value >> 4], kHexCharsLower[value & 0x0f]);
    }
}

std::array<std::array<int, 256>, 256>
GenAsciiCodeFromCharPairTable()
{
    std::array<std::array<int, 256>, 256> table;
    for (char i = kCharMin; i != kCharMax; ++i) {
        for (char j = kCharMin; j != kCharMax; ++j) {
            table[i - kCharMin][j - kCharMin] = AsciiCodeFromCharPairSlow(i, j);
        }
    }
    return table;
}

std::array<std::pair<char, char>, 256>
GenAsciiCodeToCharPairTable(bool uppercase)
{
    std::array<std::pair<char, char>, 256> table;
    for (int i = 0; i != 256; ++i) { table[i] = AsciiCodeToCharPairSlow(i, uppercase); }
    return table;
}

}// namespace

int
AsciiCodeFromCharPair(char a, char b)
{
    static auto table = GenAsciiCodeFromCharPairTable();
    return table[a - kCharMin][b - kCharMin];
}

inline std::pair<char, char>
AsciiCodeToUpperCharPair(std::uint8_t value)
{
    static auto table = GenAsciiCodeToCharPairTable(true);
    return table[value];
}

inline std::pair<char, char>
AsciiCodeToLowerCharPair(std::uint8_t value)
{
    static auto table = GenAsciiCodeToCharPairTable(false);
    return table[value];
}

std::pair<char, char>
AsciiCodeToCharPair(std::uint8_t value, bool uppercase)
{
    return uppercase ? AsciiCodeToUpperCharPair(value) : AsciiCodeToLowerCharPair(value);
}

}// namespace detail
}// namespace tile
