#include "core/compressors/Stc0.h"

namespace bmp2tile
{

uint8_t EncodeStc0Group(const uint8_t* group, uint8_t values[4], int& valuesCount)
{
    uint8_t mask = 0;
    bool lastValid = false;
    uint8_t lastValue = 0;
    valuesCount = 0;

    for (int j = 0; j < 4; ++j)
    {
        const uint8_t b = group[j];
        const int shift = 6 - j * 2;  // byte0->bits7-6, byte1->bits5-4, byte2->bits3-2, byte3->bits1-0
        if (b == 0x00)
        {
            mask = static_cast<uint8_t>(mask | (0x2 << shift));  // %10
        }
        else if (b == 0xFF)
        {
            mask = static_cast<uint8_t>(mask | (0x3 << shift));  // %11
        }
        else if (!lastValid || b != lastValue)
        {
            mask = static_cast<uint8_t>(mask | (0x1 << shift));  // %01, new raw value
            lastValid = true;
            lastValue = b;
            values[valuesCount++] = b;
        }
        // else: leave this byte's 2 bits as %00 -- repeats lastValue, no data emitted
    }

    return mask;
}

std::vector<uint8_t> CompressStc0(const std::vector<uint8_t>& input)
{
    std::vector<uint8_t> output;
    output.reserve(input.size() / 4 * 5 + 1);  // worst case 5 bytes/group (mask + 4 raw), +1 terminator

    for (size_t pos = 0; pos + 4 <= input.size(); pos += 4)
    {
        uint8_t values[4];
        int valuesCount = 0;
        const uint8_t mask = EncodeStc0Group(&input[pos], values, valuesCount);

        output.push_back(mask);
        for (int k = 0; k < valuesCount; ++k)
        {
            output.push_back(values[k]);
        }
    }

    output.push_back(0x00);  // end-of-data marker
    return output;
}

}  // namespace bmp2tile
