/*
 * Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
 */

#include <nostalgia/core/config.hpp>
#include <nostalgia/core/core.hpp>
#include <nostalgia/core/input.hpp>

#include "addresses.hpp"
#include "bios.hpp"
#include "irq.hpp"
#include "core.hpp"

extern "C" void isr();

namespace nostalgia::core {

// Timer Consts
constexpr int NanoSecond = 1000000000;
constexpr int MilliSecond = 1000;
constexpr int TicksMs59ns = 65535 - (NanoSecond / MilliSecond) / 59.59;

extern UpdateHandler g_updateHandler;

extern volatile gba_timer_t g_timerMs;

static void initIrq() noexcept {
	REG_ISR = isr;
	REG_IME = 1; // enable interrupts
}

static void initTimer() noexcept {
	// make timer0 a ~1 millisecond timer
	REG_TIMER0 = TicksMs59ns;
	REG_TIMER0CTL = 0b11000000;
	// enable interrupt for timer0
	REG_IE = REG_IE | Int_timer0;
}

ox::Result<ox::UniquePtr<Context>> init(ox::UniquePtr<ox::FileSystem> fs, const char *appName) noexcept {
	auto ctx = ox::make_unique<Context>();
	ctx->rom = std::move(fs);
	ctx->appName = std::move(appName);
	oxReturnError(initGfx(ctx.get()));
	initTimer();
	initIrq();
	return ctx;
}

void setUpdateHandler(Context*, UpdateHandler h) noexcept {
	g_updateHandler = h;
}

uint64_t ticksMs(Context*) noexcept {
	return g_timerMs;
}

bool buttonDown(Context*, Key k) noexcept {
	return !(REG_GAMEPAD & (1 << static_cast<int>(k)));
}

void shutdown(Context *ctx) noexcept {
	ctx->running = false;
}

}
