/* date = April 23rd 2023 10:47 am */

#ifndef BASE_STRINGS_H
#define BASE_STRINGS_H

// We decide that the basic string handling will be immutable.
// This means that whatever memory we got when initialising the string is what we have to live with.
// This will give us easy interfaces and work for most cases.
// The downside is that it might not have the best performance, always.
// In such cases we will develop special code for handling the special cases.

/////////////////////////
//~ Basic string types, lists and arrays

typedef struct String8 String8;
struct String8 {
  U8* str;
  U64 size;
};

typedef struct String16 String16;
struct String16 {
    U16 *str;
    U64 size;
};

typedef struct String32 String32;
struct String32 {
    U32 *str;
    U64 size;
};

typedef struct String8Node String8Node;
struct String8Node {
    String8Node *next;
    String8 string;
};

typedef struct String8List String8List;
struct String8List {
    String8Node *first;
    String8Node *last;
    U64 node_count;
    U64 total_size;
};

typedef struct String8Array String8Array;
struct String8Array {
    U64 count;
    String8 *v;
};

/////////////////////////
//~ String operations
typedef struct StringJoin StringJoin;
struct StringJoin {
    String8 pre;
    String8 sep;
    String8 post;
};

typedef struct DecodeCodepoint DecodeCodepoint;
struct DecodeCodepoint {
    U32 codepoint;
    U32 advance;
};


/////////////////////////
//~ String operations
//~ String functions

//- Helpers 
root_function U64 calculate_string_C_string_length(char *cstr);

//- Constructors 
root_function String8 str8(U8 *str, U64 size);
// Get a String8 from a C-string.
#define str8_C(cstring) str8((U8 *)cstring,calculate_string_C_string_length(cstring))
// Get a String8 from a literal
#define str8_lit(s) str8((U8*)(s), sizeof(s) - 1) // -1 since we don't want null terminated,
                                                  // but this still stores the null char for interop with APIs 
                                                  // that expect Cstrings.
// Specify a Str8 as just its struct members
#define str8_lit_comp(s) {(U8*)(s), sizeof(s)-1}
root_function String8 str8_range(U8 *first, U8 *one_past_last);

#define str8_struct(ptr) str8((U8 *)(ptr), sizeof(*(ptr)))

//- Substrings 
root_function String8 str8_substr(String8 string, U64 first, U64 one_past_last);
root_function String8 str8_prefix(String8 string, U64 size);
root_function String8 str8_chop(String8 string, U64 amount);
root_function String8 str8_suffix(String8 string, U64 size);
root_function String8 str8_skip(String8 string, U64 amount);

// Used in format strings!
#define str8_expand(s) (int)((s).size), ((s).str)

//- Lists 
root_function void str8_list_push_node(String8List *list, String8Node *n);
root_function void str8_list_push_node_front(String8List *list, String8Node *n);
root_function void str8_list_push(Arena *arena, String8List *list, String8 string);
root_function void str8_list_push_front(Arena *arena, String8List *list, String8 string);
root_function void str8_list_concat(String8List *list, String8List *to_push);
root_function String8List str8_split(Arena *arena, String8 string, int split_count, String8 *splits);
root_function String8 str8_list_join(Arena *arena, String8List list, StringJoin *optional_params);

//- Allocation and format strings 
root_function String8 str8_copy(Arena *arena, String8 string);
root_function String8 str8_pushfv(Arena *arena, char *fmt, va_list args);
root_function String8 str8_pushf(Arena *arena, char* fmt, ...);
root_function void str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...);

//~ Unicode conversions
root_function DecodeCodepoint decode_from_utf8(U8 *str, U64 max);
root_function U32             utf8_from_codepoint(U8* out, U32 codepoint);
root_function DecodeCodepoint decode_from_utf16(U16 *str, U64 max);
root_function U32             utf16_from_codepoint(U16* out, U32 codepoint);
root_function String8         str8_from16(Arena *arena, String16 string);
root_function String8         str8_from32(Arena *arena, String32 string);
root_function String16        str16_from8(Arena* arena, String8 string);
root_function String32        str32_from8(Arena *arena, String8 string);
#endif //BASE_STRINGS_H
