#include "../engine/Shared.h"
#include "Global.h"
#include "Instance.h"

#include <cassert>
#include <cstdint>

using namespace Gen;

namespace
{
    SharedData* SharedInstance = nullptr;
    Game::GameInstance* GameInst = nullptr;
} // namespace

namespace Game
{
    SharedData& GetShared()
    {
        assert(SharedInstance != nullptr);
        return *SharedInstance;
    }

    void SetShared(SharedData& instance)
    {
        SharedInstance = &instance;
    }

    GameInstance& GetInstance()
    {
        assert(GameInst != nullptr);
        return *GameInst;
    }

    void SetInstance(Game::GameInstance& instance)
    {
        GameInst = &instance;
    }

    uint8_t* AllocateScratch(uint64_t byteCount, uint32_t align)
    {
        assert(align <= 64); // The alignment of the arena limits the alignment that can be specified here!
        auto& arena = GetShared().Game.TransientArena;
        uint64_t offsetAligned = ((arena.Used + align - 1) / align) * align;
        uint8_t* ptrAligned = arena.Base + offsetAligned;
        uint64_t newOffset = offsetAligned + byteCount;
        if (newOffset > arena.MaxSize) return nullptr;
        arena.Used = newOffset;
        arena.LastAllocSize = byteCount;
        return ptrAligned;
    }

    bool ResizeLastScratchAlloc(uint64_t newByteCount)
    {
        auto& arena = GetShared().Game.TransientArena;
        if (newByteCount > arena.LastAllocSize)
        {
            LOG_ERROR("Can't resize to more than previous size!");
            return false;
        }
        LOG("Resizing last allocation from %llu to %llu", arena.LastAllocSize, newByteCount);
        arena.Used -= arena.LastAllocSize;
        arena.Used += newByteCount;
        LOG("New total: %llu", arena.Used);
        return true;
    }

    void ResetScratch()
    {
        auto& arena = GetShared().Game.TransientArena;
        arena.Used = 0;
        arena.LastAllocSize = 0;
    }
} // namespace Game
