// #TODO: #Arena_Table #garbage_collection in `release_arena`
// [ ] Garbage collection if we have >> 64 in a particular table for a while.
//     There should be some parameters regarding what the upper limit for idle 
//     committed pages should be and a heuristic for maximum number of arenas waiting

global Arena_Table* arena_table;

// Only call once from main thread!
void initialize_arena_table (Allocator allocator) {
  Assert(arena_table != nullptr);
  if (arena_table->initialized)
      return;
  
  for (s32 i = 0; i < 6; i += 1) {
    arena_table->in_flight_count[i] = 0;
    arena_table->free_table[i].allocator = allocator;
    array_reserve(arena_table->free_table[i], 64);
#if ARENA_DEBUG
    arena_table->in_flight[i].allocator = allocator;
    array_reserve(arena_table->in_flight[i], 64);
#endif
  }
  
  arena_table->initialized = true;
}

Arena* next_arena (Arena_Reserve reserve_size) {
  Assert(arena_table != nullptr);
  Arena* arena;
  std::lock_guard<std::mutex> lock(arena_table->mutex);
  s64 reserve_index = (s64)reserve_size;
  
  if (!arena_table->free_table[reserve_index].count) {
    arena = bootstrap_arena(reserve_size, ARENA_DEFAULT_COMMIT_PAGE_COUNT);
  } else {
    arena = pop(arena_table->free_table[reserve_index]);
  }
#if ARENA_DEBUG 
  array_add(arena_table->in_flight[reserve_index], arena);
#endif  

  arena_table->in_flight_count[reserve_index] += 1;

  Assert(arena != nullptr);
  return arena;
}

void release_arena (Arena* arena, bool delete_extra_pages) {
  Assert(arena_table != nullptr);
  Assert(arena != nullptr);
  Assert(arena_is_bootstrapped(arena));
  // Only put into free table if arena is bootstrapped?
  std::lock_guard<std::mutex> lock(arena_table->mutex);
  s64 reserve_index = (s64)arena->reserve_size;
  
#if ARENA_DEBUG 
  array_unordered_remove_by_value(arena_table->in_flight[reserve_index], arena, 1); // BUILD_DEBUG!
#endif
  arena_reset_keeping_memory(arena);
  if (delete_extra_pages) {
    free_pages_down_to(arena, arena->initial_commit_page_count);
  }
  array_add(arena_table->free_table[reserve_index], arena);
  
  arena_table->in_flight_count[reserve_index] -= 1;
  // #TODO #garbage_collection
  // if (arena_free_table[reserve_index].count > 64) {
  //   s64 arenas_to_delete_count = arena_free_table[reserve_index].count - 64;
  //   while (arenas_to_delete_count > 0) {
  //     arena_delete(arena_free_table[arena_free_table.count-1]);
  //     array_unordered_remove_by_index(..);
  //     arenas_to_delete_count -= 1;
  //   }
  // }
}
