#include "generated/vn_character.meta.c"

global character_registry *Global_CharacterRegistry = 0;

////////////////////////////////
//~ sixten: Character String Chunk Functions
static character_string_list CR_CharacterStringListAlloc(character_registry *Registry, string String)
{
    character_string_list Result = {};
    s64 ChunksNeeded = (String.Count + CHARACTER_STRING_CHUNK_DATA_SIZE - 1) / CHARACTER_STRING_CHUNK_DATA_SIZE;
    s64 BytesLeft = String.Count;
    u64 StringIndex = 0;
    for(s64 ChunkIndex = 0; ChunkIndex < ChunksNeeded; ChunkIndex += 1)
    {
        character_string_chunk *Chunk = Registry->FirstFreeChunk;
        if(Chunk)
        {
            Registry->FirstFreeChunk = Chunk->Next;
        }
        else
        {
            Chunk = PushStructNoClear(Registry->StringArena, character_string_chunk);
        }
        u64 ToCopy = Min(BytesLeft, CHARACTER_STRING_CHUNK_DATA_SIZE);
        Copy(Chunk->Data, String.Data+StringIndex, ToCopy);
        QueuePush(Result.First, Result.Last, Chunk);
        Result.ChunkCount += 1;
        Result.StringCount += ToCopy;
        BytesLeft -= ToCopy;
        StringIndex += ToCopy;
    }
    return(Result);
}

static character_string_list CR_CharacterStringListRelease(character_registry *Registry, character_string_list *List)
{
    for(character_string_chunk *Chunk = List->First, *Next = 0; Chunk != 0; Chunk = Next)
    {
        Next = Chunk->Next;
        Chunk->Next = Registry->FirstFreeChunk;
        Registry->FirstFreeChunk = Chunk;
    }
    ZeroStruct(List);
}

static string CR_StringFromList(memory_arena *Arena, character_string_list *List)
{
    string Result;
    Result.Count = List->StringCount;
    Result.Data = PushArrayNoClear(Arena, u8, Result.Count);
    s64 StringIndex = 0;
    s64 BytesLeft = List->StringCount;
    for(character_string_chunk *Chunk = List->First; Chunk != 0; Chunk = Chunk->Next)
    {
        s64 ToCopy = Min(BytesLeft, CHARACTER_STRING_CHUNK_DATA_SIZE);
        Copy(Result.Data+StringIndex, Chunk->Data, ToCopy);
        StringIndex += ToCopy;
        BytesLeft -= ToCopy;
    }
    return(Result);
}

////////////////////////////////
//~ sixten: Character Registry Functions
static void CR_SetState(character_registry *State)
{
    Global_CharacterRegistry = State;
}

static character_registry *CR_GetState(void)
{
    return(Global_CharacterRegistry);
}

static character_list CR_GetCharacters(void)
{
    return(CR_GetState()->Characters);
}

static void CR_Init(character_registry *State)
{
    CR_SetState(State);
    
    State->Arena = ArenaAllocate(Megabytes(32));
}

static character_entry *CR_EntryFromName(string Name)
{
    character_entry *Entry = 0;
    
    character_registry *Registry = CR_GetState();
    for(character_entry *Iter = Registry->Characters.First; Iter != 0; Iter = Iter->Next)
    {
        if(AreEqual(Name, Iter->Name))
        {
            Entry = Iter;
            break;
        }
    }
    
    if(!Entry)
    {
        Entry = PushStruct(Registry->Arena, character_entry);
        Entry->Name = PushString(Registry->Arena, Name);
        DLLInsertLast(Registry->Characters.First, Registry->Characters.Last, Entry);
    }
    
    return(Entry);
}