#ifndef SCRIPT_MEMORY_PRIVATE_H
#define SCRIPT_MEMORY_PRIVATE_H

#include <stddef.h>
#include <stdint.h>

#include "coduo_engine_structs.h"

enum {
    SCRIPT_MEMORY_BLOCK_COUNT = 0x10000,
    SCRIPT_MEMORY_BLOCK_SIZE = 8,
    SCRIPT_MEMORY_MAX_BUCKET = 0x10,
    SCRIPT_MEMORY_BUCKET_COUNT = SCRIPT_MEMORY_MAX_BUCKET + 1,
    SCRIPT_MEMORY_LOOKUP_COUNT = 0x100,
    SCRIPT_MEMORY_MAX_ALLOCATION_SIZE = 0x10000,
    SCRIPT_MEMORY_INDEX_MASK = 0xffff,
    SCRIPT_STRING_HASH_SLOT_COUNT = 16384
};

typedef union script_memory_block_u {
    struct {
        uint16_t left;
        uint16_t right;
        uint32_t payload;
    } freeNode;
    uint8_t bytes[SCRIPT_MEMORY_BLOCK_SIZE];
} script_memory_block_t;

typedef struct script_memory_allocator_header_s {
    script_memory_block_t *arenaBase;
    struct script_memory_allocator_header_s *prev;
    struct script_memory_allocator_header_s *next;
    uint32_t reserved;
} script_memory_allocator_header_t;

typedef struct script_string_hash_slot_s {
    uint16_t linkAndFlags;
    uint16_t stringHandle;
} script_string_hash_slot_t;

extern script_memory_block_t script_memoryBlocks[SCRIPT_MEMORY_BLOCK_COUNT];
extern script_memory_allocator_header_t script_memoryAllocatorHeader;
extern int32_t script_memoryAllocatedBucketCount;
extern int32_t script_memoryAllocatedInstanceCount;
extern uint8_t script_memoryBitWidthTable[SCRIPT_MEMORY_LOOKUP_COUNT];
extern uint16_t script_memoryFreeRoots[SCRIPT_MEMORY_BUCKET_COUNT];
extern uint8_t script_memoryPopcountTable[SCRIPT_MEMORY_LOOKUP_COUNT];
extern uint8_t script_memoryTrailingZeroBits[SCRIPT_MEMORY_LOOKUP_COUNT];
extern uint16_t script_stringCanonicalCount;
extern uint16_t *script_stringCanonicalMap;
extern script_string_hash_slot_t *script_stringFreedHashSlot;
extern script_string_hash_slot_t
    script_stringHashSlots[SCRIPT_STRING_HASH_SLOT_COUNT];

void MT_Init(void);
uint16_t MT_AllocIndex(size_t size, int32_t type);
void MT_FreeIndex(uint16_t blockIndex, size_t size);
qboolean MT_Realloc(size_t lhsSize, size_t rhsSize);
void MT_DumpTree(void);
void *MT_Alloc(size_t size, int32_t type);
void MT_Free(void *ptr, size_t size);
const char *SL_ConvertToString(uint16_t handle);
void SL_Init(void);
uint16_t SL_GetString(const char *text, uint8_t user);
uint16_t SL_GetString_(const char *text,
                       uint8_t user,
                       int32_t type);
uint16_t SL_GetStringOfLen(const char *text,
                            uint8_t user,
                            uint32_t size,
                            int32_t type);
uint16_t
SL_GetLowercaseString_(const char *text, uint8_t user, int32_t type);
uint16_t
SL_GetLowercaseStringOfLen(const char *text, uint8_t user, uint32_t size,
                           int32_t type);
uint16_t
Scr_CreateCanonicalFilename(const char *filename);
uint16_t
SL_TransferToCanonicalString(uint16_t handle);
uint16_t SL_GetStringForFloat(float value);
uint16_t SL_GetStringForInt(int32_t value);
uint16_t SL_GetStringForVector(const float *vector);
uint16_t SL_FindCanonicalString(const char *text);
void SL_AddRefToString(uint16_t handle);
void SL_RemoveRefToString(uint16_t handle);
void SL_RemoveRefToStringOfLen(uint16_t handle,
                               uint32_t size);
void SL_TransferRefToString(uint16_t handle,
                            uint8_t usage);
void SL_BeginLoadScripts(void);
void SL_EndLoadScripts(void);
void SL_ShutdownSystem(uint8_t usage);
uint16_t SL_FindLowercaseString(const char *text);

#endif
