// These decompression routines are rather complicated to allow customization.
// If you only want to decompress some data into graphics memory, you can use
// the functions at the end of this file instead.

#ifndef CVU_COMPRESSION_H
#define CVU_COMPRESSION_H 1

#include <stdint.h>
#include "cvu_graphics.h"

// Huffman decompression
#undef CVU_HUFFMAN_ITERATIVE
#undef CVU_HUFFMAN_RECURSIVE

struct cvu_huffman_node	// Changing this struct will affect asm implementation of cvu_get_huffman
{
        uint8_t left;   // Position of left node in tree or character.
        uint8_t right;  // Position of right node in tree or character.
};

struct cvu_huffman_state	// Changing this struct will affect asm implementation of cvu_get_huffman, _read_from_array
{
	uint8_t (*input)(void);
	const struct cvu_huffman_node *nodes;	// Array of nodes
	uint8_t root;	// Position of root node among nodes
	uint8_t ls, bs, rs;
	unsigned char bit;	// Position of currently processed bit
	uint8_t buffer;	// Currently processed input byte
#ifdef CVU_HUFFMAN_RECURSIVE
	uint8_t current;	// Currently processed node
#endif
};

void cvu_init_huffman(struct cvu_huffman_state *restrict state, uint8_t (* input)(void), const struct cvu_huffman_node *restrict tree, uint8_t root, uint8_t ls, uint8_t bs, uint8_t rs);
uint8_t cvu_get_huffman(struct cvu_huffman_state *state);

// RLE decompression
struct cvu_rle_state	// Changing this struct will affect asm implementation of cvu_get_rle, _read_from_array
{
	uint8_t (*input)(void);
	uint8_t escape;
	uint8_t left;
	uint8_t buffer;
};

void cvu_init_rle(struct cvu_rle_state *restrict state, uint8_t (* input)(void), uint8_t escape);
uint8_t cvu_get_rle(struct cvu_rle_state *state);

// LZK decompression
struct cvu_lzk_state
{
	uint8_t (*input)(void);
	uint8_t escape;
	uint8_t left;
	uint8_t offset;
	uint8_t start;
	uint8_t buffer[64];
};

void cvu_init_lzk(struct cvu_lzk_state *restrict state, uint8_t (* input)(void), uint8_t escape);
uint8_t cvu_get_lzk(struct cvu_lzk_state *state);

// Decompression routines which will handle all the details for you.
// Just create a cvu_compression_state struct, initialize it and decompress.
struct cvu_compression_state	// Changing this struct will affect asm implementation of _read_from_array
{
	struct cvu_huffman_state huffman;
	struct cvu_rle_state rle;
	const uint8_t *data;
};

// Initilization:
// data: compressed data
// state: compression struct to initialize
// tree: huffman tree generated by huffman_analyzer
// root, ls, bs, rs: constants generated by huffman_analyzer
// escape: constant generated by rle_analyzer
void cvu_init_compression(const uint8_t *restrict data, struct cvu_compression_state *restrict state, const struct cvu_huffman_node *restrict tree, uint8_t root, uint8_t ls, uint8_t bs, uint8_t rs, uint8_t escape);

// The functions below can be mixed: 

// This function will return a decompressed octet on each invocation.
uint8_t cvu_get_compression(struct cvu_compression_state *state);

// This function will decompress and write n octets to graphics memory at dest.
// It is not reentrant and may not be called why any function from cvu_graphics.h marked as such is called.
void cvu_memtovmemcpy_compression(cv_vmemp dest, struct cvu_compression_state *state, size_t n);

// This function will decompress and write n octets to memory at dest.
void *cvu_memcpy_compression(void *restrict dest, struct cvu_compression_state *state, size_t n);

#endif

