#pragma once

#include "pxl8_types.h"

#define PXL8_PALETTE_SIZE 256
#define PXL8_MAX_CYCLES 8
#define PXL8_MAX_CYCLE_LEN 16
#define PXL8_CUBE_SIZE 32
#define PXL8_CUBE_ENTRIES (PXL8_CUBE_SIZE * PXL8_CUBE_SIZE * PXL8_CUBE_SIZE)

typedef struct pxl8_palette pxl8_palette;
typedef struct pxl8_palette_cube pxl8_palette_cube;

typedef enum pxl8_cycle_mode {
    PXL8_CYCLE_LOOP,
    PXL8_CYCLE_ONCE,
    PXL8_CYCLE_PINGPONG,
} pxl8_cycle_mode;

typedef enum pxl8_easing {
    PXL8_EASE_LINEAR,
    PXL8_EASE_IN,
    PXL8_EASE_IN_OUT,
    PXL8_EASE_OUT,
} pxl8_easing;

typedef struct pxl8_cycle_range {
    pxl8_easing easing;
    bool interpolate;
    u8 len;
    pxl8_cycle_mode mode;
    u16 period;
    u8 start;
} pxl8_cycle_range;

#ifdef __cplusplus
extern "C" {
#endif

pxl8_palette* pxl8_palette_create(void);
void pxl8_palette_destroy(pxl8_palette* pal);

pxl8_result pxl8_palette_load_ase(pxl8_palette* pal, const char* path);

u16 pxl8_palette_color_count(const pxl8_palette* pal);
u8* pxl8_palette_color_ramp(pxl8_palette* pal);
u32* pxl8_palette_colors(pxl8_palette* pal);
u8 pxl8_palette_ramp_index(const pxl8_palette* pal, u8 position);
u8 pxl8_palette_ramp_position(const pxl8_palette* pal, u8 index);
u8 pxl8_palette_find_closest(const pxl8_palette* pal, u8 r, u8 g, u8 b);
u32 pxl8_palette_color(const pxl8_palette* pal, u8 idx);
i32 pxl8_palette_index(const pxl8_palette* pal, u32 color);
void pxl8_palette_get_rgb(const pxl8_palette* pal, u8 idx, u8* r, u8* g, u8* b);
void pxl8_palette_get_rgba(const pxl8_palette* pal, u8 idx, u8* r, u8* g, u8* b, u8* a);
void pxl8_palette_set_rgb(pxl8_palette* pal, u8 idx, u8 r, u8 g, u8 b);
void pxl8_palette_set_rgba(pxl8_palette* pal, u8 idx, u8 r, u8 g, u8 b, u8 a);
void pxl8_set_palette(pxl8_palette* pal, const u32* colors, u16 count);

void pxl8_palette_fill_gradient(pxl8_palette* pal, u8 start, u8 count, u32 from, u32 to);
void pxl8_palette_fill_gradient_rgb(pxl8_palette* pal, u8 start, u8 count, u8 r0, u8 g0, u8 b0, u8 r1, u8 g1, u8 b1);

void pxl8_palette_reset_cycle(pxl8_palette* pal, u8 slot);
void pxl8_palette_set_cycle(pxl8_palette* pal, u8 slot, pxl8_cycle_range range);
void pxl8_palette_set_cycle_colors(pxl8_palette* pal, u8 slot, const u32* colors, u8 count);
void pxl8_palette_set_cycle_phase(pxl8_palette* pal, u8 slot, f32 phase);
void pxl8_palette_tick(pxl8_palette* pal, u16 delta_ticks);

pxl8_cycle_range pxl8_cycle_range_create(u8 start, u8 len, u16 period);
pxl8_cycle_range pxl8_cycle_range_disabled(void);

pxl8_palette_cube* pxl8_palette_cube_create(const pxl8_palette* pal);
void pxl8_palette_cube_destroy(pxl8_palette_cube* cube);
void pxl8_palette_cube_rebuild(pxl8_palette_cube* cube, const pxl8_palette* pal);
u8 pxl8_palette_cube_lookup(const pxl8_palette_cube* cube, u8 r, u8 g, u8 b);
u8 pxl8_palette_cube_lookup_stable(const pxl8_palette_cube* cube, u8 r, u8 g, u8 b);
void pxl8_palette_cube_get_rgb(const pxl8_palette_cube* cube, u8 idx, u8* r, u8* g, u8* b);

#ifdef __cplusplus
}
#endif
