/* date = August 19th 2023 1:28 pm */

#ifndef BASE_BIG_FUNCTIONS_H
#define BASE_BIG_FUNCTIONS_H

////////////////////////////////
// NOTE(allen): Symbolic Constant Functions

link_function OperatingSystem operating_system_from_context(void);
link_function Architecture architecture_from_context(void);

link_function char* string_from_operating_system(OperatingSystem os);
link_function char* string_from_architecture(Architecture arch);
link_function char* string_from_month(Month month);
link_function char* string_from_day_of_week(DayOfWeek day_of_week);

////////////////////////////////
// NOTE(allen): Time Functions

link_function DenseTime dense_time_from_date_time(DateTime *date_time);
link_function DateTime  date_time_from_dense_time(DenseTime dense_time);

////////////////////////////////
// NOTE(allen): Memory Functions

link_function Arena* arena_alloc_reserve(U64 reserve_size, B32 growing);
link_function Arena* arena_alloc(void);
link_function void   arena_release(Arena *arena);
link_function void*  arena_push_no_zero(Arena *arena, U64 size);
link_function void   arena_pop_to(Arena *arena, U64 pos);
link_function U64    arena_current_pos(Arena *arena);

link_function void*  arena_push(Arena *arena, U64 size);
link_function void   arena_align(Arena *arena, U64 pow2_align);
link_function void   arena_pop_amount(Arena *arena, U64 amount);

#define push_array(a,T,c) (T*)arena_push((a), sizeof(T)*(c))
#define push_array_no_zero(a,T,c) (T*)arena_push_no_zero((a), sizeof(T)*(c))

link_function ArenaTemp arena_begin_temp(Arena *arena);
link_function void      arena_end_temp(ArenaTemp *temp);

link_function ArenaTemp arena_get_scratch(Arena **conflict_array, U32 count);
#define arena_release_scratch(temp) arena_end_temp(temp)

////////////////////////////////
// NOTE(allen): String Compound Constructor Functions

link_function void str8_list_push_explicit(String8List *list, String8 string,
                                           String8Node *node_memory);
link_function void str8_list_push(Arena *arena, String8List *list, String8 string);

link_function String8 str8_join(Arena *arena, String8List *list,
                                StringJoin *optional_join);

link_function String8List str8_split(Arena *arena, String8 string,
                                     U8 *split_characters, U32 count);

link_function String8 str8_pushfv(Arena *arena, char *fmt, va_list args);
link_function String8 str8_pushf(Arena *arena, char *fmt, ...);
link_function void    str8_list_pushf(Arena *arena, String8List *list, char *fmt, ...);

link_function String8 str8_push_copy(Arena *arena, String8 string);

////////////////////////////////
// NOTE(allen): String Comparison Functions

link_function B32 str8_match(String8 a, String8 b, StringMatchFlags flags);

////////////////////////////////
// NOTE(allen): Unicode Functions

link_function StringDecode str_decode_utf8(U8 *str, U32 cap);
link_function U32          str_encode_utf8(U8 *dst, U32 codepoint);
link_function StringDecode str_decode_utf16(U16 *str, U32 cap);
link_function U32          str_encode_utf16(U16 *dst, U32 codepoint);

link_function String32     str32_from_str8(Arena *arena, String8 string);
link_function String8      str8_from_str32(Arena *arena, String32 string);
link_function String16     str16_from_str8(Arena *arena, String8 string);
link_function String8      str8_from_str16(Arena *arena, String16 string);

////////////////////////////////
// NOTE(allen): Log

link_function void log_accum_begin(void);
link_function void log_emit(String8 message);
link_function void log_emitf(char *fmt, ...);
link_function String8 log_accum_end(Arena *arena);

typedef struct LOG_Node{
  struct LOG_Node *next;
  U64 pos;
  String8List log;
} LOG_Node;

typedef struct LOG_ThreadVars{
  Arena    *arena;
  LOG_Node *stack;
  // TODO(allen): eliminate over stack & replace with
  // chaining arena for log
  U64       over_stack;
} LOG_ThreadVars;

////////////////////////////////
// NOTE(allen): Errors

link_function void er_accum_begin(void);
link_function void er_emit(String8 error);
link_function void er_emitf(char *fmt, ...);
link_function String8 er_accum_end(Arena *arena);

typedef struct ER_Node{
  struct ER_Node *next;
  U64 pos;
  String8 error;
} ER_Node;

typedef struct ER_ThreadVars{
  Arena   *arena;
  ER_Node *stack;
  U64      over_stack;
} ER_ThreadVars;

////////////////////////////////
// NOTE(allen): Interleaving Functions

link_function String8  bop_interleave(Arena *arena, void **in,
                                      U64 lane_count, U64 el_size, U64 el_count);

link_function String8* bop_uninterleave(Arena *arena, void *in,
                                        U64 lane_count, U64 el_size, U64 el_count);

////////////////////////////////
// NOTE(allen): Conversions

link_function String8 bop_f32_from_s24(Arena *arena, String8 in);
link_function String8 bop_s24_from_f32(Arena *arena, String8 in);
link_function String8 bop_s16_from_f32(Arena *arena, String8 in);

////////////////////////////////
// NOTE(allen): PRNG Functions

// TODO(allen): Build out more high level features for a good prng layer.

link_function PRNG prng_make_from_seed(PRNG_Seed *seed);

link_function U32  prng_next_u32(PRNG *prng);
link_function U64  prng_next_u64(PRNG *prng);

link_function U32  prng_next_bounded(PRNG *prng, U32 bound);

// [0,1]
link_function F32  prng_next_unital_f32(PRNG *prng);
// [-1,1]
link_function F32  prng_next_biunital_f32(PRNG *prng);

link_function B32  prng_next_pcoin(PRNG *prng, F32 p);

////////////////////////////////
// NOTE(allen): Big Math Functions

link_function F32       math_gaussian(F32 sigma, F32 x);
link_function Array_F32 math_gaussian_kernel(Arena *arena, F32 sigma,
                                             U32 extra_reach);


#endif //BASE_BIG_FUNCTIONS_H
