/* date = June 19th 2023 9:15 pm */

#ifndef CORE_STRING_H
#define CORE_STRING_H

/////////////////////////////////////
//~ sixten: String types

struct string
{
    s64 Count;
    u8 *Data;
};

struct string16
{
    s64 Count;
    u16 *Data;
};

typedef string buffer;

struct string_node
{
    string String;
    string_node *Next;
    string_node *Prev;
};

struct string_list
{
    string_node *First;
    string_node *Last;
    
    s64 TotalCount;
};

/////////////////////////////////////
//~ sixten: String Chunk Types
struct string_chunk_list
{
    s64 ChunkSize;
    s64 ChunkCount;
    s64 TotalCount;
    
    string_node *First;
    string_node *Last;
    string_node *FirstFree;
    string_node *LastFree;
};


/////////////////////////////////////
//~ sixten: Char funcitons

inline b32 IsWhitespace(char C);
inline b32 IsDigit(char C);
inline b32 IsLetter(char C);


/////////////////////////////////////
//~ sixten: String functions

//- sixten: Basic constructors

inline string MakeString(u8 *Data, s64 Count);
inline string MakeString(u8 *Start, u8 *End);
inline string MakeString(char *CString);
#define StrLit(String) MakeString((u8 *)String, (s64)(ArrayCount(String) - 1))

inline string16 MakeString16(u16 *Data, s64 Count);

//- sixten: Equality

static b32 AreEqual(string A, string B);

//- sixten: Substring

static string Substring(string String, range1_s64 Range);
static string Prefix(string String, s64 Count);
static string Suffix(string String, s64 Count);

//- sixten: Hashing

static u64 HashString(string String);

//- sixten: Searching

static s64 FirstIndexOf(string String, char Char);
static s64 LastIndexOf(string String, char Char);
static s64 FirstIndexOf(string String, string Sub);
static s64 LastIndexOf(string String, string Sub);

//- sixten: Allocation

static string PushString(memory_arena *Arena, string String);
static string PushFormatVariadic(memory_arena *Arena, char *Format, va_list Arguments);
static string PushFormat(memory_arena *Arena, char *Format, ...);
static string PushCString(memory_arena *Arena, char *String);

//- sixten: Conversion

static s64 ConvertStringToS64(string String);
static string ConvertS64ToString(memory_arena *Arena, s64 Value);
static string StringFromCodepoint(memory_arena *Arena, u32 Codepoint);
static r64 DoubleFromString(string String);

//- sixten: Replacing

static string RemoveAll(memory_arena *Arena, string Text, char ToRemove);

//- sixten: "C Style" strings

static s64 StringLength(char *String);
static s64 StringLength16(u16 *String);


#if 0
/////////////////////////////////////
//~ sixten: String Chunk Functions
static string_chunk_list MakeStringChunkList(s64 ChunkSize);
static string JoinStringChunkList(memory_arena *Arena, string_chunk_list *List);
static void ReplaceRange(memory_arena *Arena, string_chunk_list *List, string Text, range1_s64 Range);
#endif

//~ sixten: String list

static void AppendString(string_list *List, string String, memory_arena *Arena);
static string JoinStringList(string_list *List, memory_arena *Arena);


//~ sixten: Unicode

struct string_decode
{
    u32 Codepoint;
    s32 Size;
};

static string_decode DecodeUTF8Codepoint(u8 *Data, s64 Count);
static u32 EncodeUTF8Codepoint(u8 *Dest, u32 Codepoint);

static string_decode DecodeUTF16Codepoint(u16 *Data, s64 Count);
static u32 EncodeUTF16Codepoint(u16 *Dest, u32 Codepoint);

static s64 UTF8FromCodepoint(u8 *Out, u32 Codepoint);

static string String8FromString16(memory_arena *Arena, string16 String);
static string16 String16FromString8(memory_arena *Arena, string String);

//~ sixten: Text point

struct text_point
{
    s64 Line;
    s64 Column;
};

struct text_range
{
    text_point Min;
    text_point Max;
};

static text_point TextPointFromOffset(string String, s64 Offset);
static s64 OffsetFromTextPoint(string String, text_point Point);

static text_range TextRange(text_point A, text_point B);

////////////////////////////////
//~ sixten: 1D Interval List & Array Types
struct range1_s64_node
{
    range1_s64 Range;
    range1_s64_node *Next;
};

struct range1_s64_list
{
    s64 Count;
    range1_s64_node *First;
    range1_s64_node *Last;
};

struct range1_s64_array
{ 
    s64 Count;
    range1_s64 *Ranges;
};

////////////////////////////////
//~ sixten: 1D Interval List & Array Functions
static void Range1S64ListPush(memory_arena *Arena, range1_s64_list *List, range1_s64 Range);
static range1_s64_array Range1S64ArrayFromList(memory_arena *Arena, range1_s64_list *List);
static s64 OffsetFromTextPoint(string Text, range1_s64_array Lines, text_point Point);

#endif //CORE_STRING_H
