/**
 * DreamStack Delta Codec — C port for ESP32-P4
 *
 * Ported from engine/ds-stream/src/codec.rs (lines 109-179)
 * Exact same encoding: 0x00 + 2-byte LE count = zero run.
 */

#include "ds_codec.h"
#include <string.h>

size_t ds_rle_decode(const uint8_t *compressed, size_t comp_len,
                     uint8_t *output, size_t out_cap) {
    size_t i = 0;   // input position
    size_t o = 0;   // output position

    while (i < comp_len) {
        if (compressed[i] == 0x00) {
            // Zero run: 0x00 + count_lo + count_hi
            if (i + 2 >= comp_len) break;
            uint16_t count = (uint16_t)compressed[i + 1]
                           | ((uint16_t)compressed[i + 2] << 8);
            if (o + count > out_cap) return 0;  // overflow
            memset(output + o, 0, count);
            o += count;
            i += 3;
        } else {
            // Literal byte
            if (o >= out_cap) return 0;
            output[o++] = compressed[i++];
        }
    }
    return o;
}

void ds_xor_apply(uint8_t *framebuffer, const uint8_t *delta, size_t len) {
    // Process 4 bytes at a time for speed on 32-bit RISC-V
    size_t i = 0;
    size_t aligned = len & ~3u;
    for (; i < aligned; i += 4) {
        *(uint32_t *)(framebuffer + i) ^= *(const uint32_t *)(delta + i);
    }
    for (; i < len; i++) {
        framebuffer[i] ^= delta[i];
    }
}

int ds_apply_delta_rle(uint8_t *framebuffer, size_t fb_len,
                       const uint8_t *compressed, size_t comp_len,
                       uint8_t *scratch) {
    size_t decoded_len = ds_rle_decode(compressed, comp_len, scratch, fb_len);
    if (decoded_len == 0 || decoded_len != fb_len) {
        return -1;
    }
    ds_xor_apply(framebuffer, scratch, fb_len);
    return 0;
}
