/*
 * palette.c — Sprinter palette (BIOS $A4 PIC_SET_PAL / PIC_GET_PAL,
 *                                BIOS $A6 SET_PAL_INIT).
 *
 * Direction in $A4 is selected by bit 7 of A:
 *   A = pal_num         → write entries from RAM to VRAM
 *   A = 0x80 | pal_num  → read entries from VRAM into RAM
 *
 * Lives under libc/video/ because palette control is shared between
 * graphics (mode 0x81/0x82) and text (mode 0x03) — pal_num 0..3 for
 * graphics, 4..7 for the four text-mode planes. The conio and gfx
 * subsystems each ship thin domain-specific wrappers on top.
 */

#include <stdint.h>
#include <palette.h>

/* Statics used to pass parameters to the inline asm — SDCC __sdcccall(1)
 * gives us only HL natively, so the rest go through memory. */
static uint8_t  pal_num_;
static uint8_t  pal_start_;
static uint8_t  pal_count_;
static uint16_t pal_data_;

/* ---- $A4 PIC_SET_PAL — write entries to VRAM --------------------- */

void pal_load(uint8_t pal_num, uint8_t start, uint8_t count,
              const uint8_t *bgr0)
{
    pal_num_   = pal_num;
    pal_start_ = start;
    pal_count_ = count;
    pal_data_  = (uint16_t)(uintptr_t)bgr0;

    __asm
        push  ix
        ld    a, (_pal_start_)
        ld    e, a                  ; E = start
        ld    a, (_pal_count_)
        ld    d, a                  ; D = count (0 → 256)
        ld    hl, (_pal_data_)      ; HL = data
        ld    b, #0xFF              ; B = mask (no AND)
        ld    a, (_pal_num_)        ; A = palette number (bit7 = 0 → write)
        ld    c, #0xA4              ; BIOS PIC_SET_PAL
        rst   #0x08
        pop   ix
    __endasm;
}

/* ---- $A4 PIC_GET_PAL — read entries from VRAM -------------------- *
 * Same function id; bit 7 of A flips it to read mode. */

void pal_get(uint8_t pal_num, uint8_t start, uint8_t count, uint8_t *bgr0)
{
    pal_num_   = (uint8_t)(pal_num | 0x80);   /* bit 7 = read */
    pal_start_ = start;
    pal_count_ = count;
    pal_data_  = (uint16_t)(uintptr_t)bgr0;

    __asm
        push  ix
        ld    a, (_pal_start_)
        ld    e, a                  ; E = start
        ld    a, (_pal_count_)
        ld    d, a                  ; D = count (0 → 256)
        ld    hl, (_pal_data_)      ; HL = buffer
        ld    b, #0xFF              ; B = mask
        ld    a, (_pal_num_)        ; A = 0x80 | pal_num → read
        ld    c, #0xA4              ; BIOS PIC_GET_PAL (= $A4)
        rst   #0x08
        pop   ix
    __endasm;
}

/* ---- one-colour helpers ------------------------------------------ */

void pal_set_color(uint8_t pal_num, uint8_t slot,
                   uint8_t r, uint8_t g, uint8_t b)
{
    uint8_t entry[4];
    entry[0] = b;
    entry[1] = g;
    entry[2] = r;
    entry[3] = 0;
    pal_load(pal_num, slot, 1, entry);
}

void pal_get_color(uint8_t pal_num, uint8_t slot,
                   uint8_t *r, uint8_t *g, uint8_t *b)
{
    uint8_t entry[4];
    pal_get(pal_num, slot, 1, entry);
    if (b) *b = entry[0];
    if (g) *g = entry[1];
    if (r) *r = entry[2];
}

/* ---- $A6 SET_PAL_INIT — restore a built-in default palette ------- *
 * Signature: A = pal_page, E = graphics palette index (0..3), B = type.
 * Type is one of PAL_GRAPH (1) / PAL_SINCLAIR (2) / PAL_CGA (3). */

static uint8_t  reset_page_;
static uint8_t  reset_graph_;
static uint8_t  reset_type_;

void pal_reset_at(uint8_t type, uint8_t pal_page, uint8_t graph_pal)
{
    reset_type_  = type;
    reset_page_  = pal_page;
    reset_graph_ = graph_pal;

    __asm
        push  ix
        ld    a, (_reset_graph_)
        ld    e, a                  ; E = graphics palette index (0..3)
        ld    a, (_reset_type_)
        ld    b, a                  ; B = type (1=GRAPH, 2=SINCLAIR, 3=CGA)
        ld    a, (_reset_page_)     ; A = palette page (last — A is needed)
        ld    c, #0xA6              ; BIOS SET_PAL_INIT
        rst   #0x08
        pop   ix
    __endasm;
}

void pal_reset(uint8_t type)
{
    pal_reset_at(type, 4, 0);
    pal_reset_at(type, 5, 0);
    pal_reset_at(type, 6, 0);
    pal_reset_at(type, 7, 0);
}
