#include "emulation.h"
#include <stdlib.h>

static int onFrame(VB *sim) {
    SimContext *ctx = vbGetUserData(sim);
    ctx->hasFrame = true;
    return 1;
}

int emuInit(EmulationContext *emu) {
    emu->sim = malloc(vbSizeOf());
    vbInit(emu->sim);

    emu->ctx = malloc(sizeof(SimContext));
    emu->ctx->hasFrame = false;
    emu->ctx->currentSample = 0;
    vbSetSamples(emu->sim, emu->ctx->samples[emu->ctx->currentSample], VB_S16, 834);
    vbSetUserData(emu->sim, emu->ctx);
    vbSetFrameCallback(emu->sim, &onFrame);

    return 0;
}

void emuDestroy(EmulationContext *emu) {
    uint8_t *rom = vbGetCartROM(emu->sim, NULL);
    SimContext *ctx = vbGetUserData(emu->sim);

    if (rom) free(rom);
    if (ctx) free(ctx);
    free(emu->sim);
}

void emuLoadGame(EmulationContext *emu, uint8_t *rom, uint32_t romSize) {
    uint8_t *oldRom = vbGetCartROM(emu->sim, NULL);
    if (oldRom) free(oldRom);
    vbSetCartROM(emu->sim, rom, romSize);
    vbReset(emu->sim);
}

void emuReset(EmulationContext *emu) {
    vbReset(emu->sim);
}

bool emuIsGameLoaded(EmulationContext *emu) {
    return vbGetCartROM(emu->sim, NULL) != NULL;
}

#define MAX_STEP_CLOCKS 20000000
void emuTick(EmulationContext *emu) {
    uint32_t clocks = MAX_STEP_CLOCKS;
    vbEmulate(emu->sim, &clocks);
}

bool emuReadPixels(EmulationContext *emu, uint8_t *left, uint8_t *right) {
    if (!emu->ctx->hasFrame) {
        return false;
    }
    emu->ctx->hasFrame = false;
    vbGetPixels(emu->sim, left, 1, 384, right, 1, 384);
    return true;
}

void emuReadSamples(EmulationContext *emu, void **data, uint32_t *bytes) {
    uint32_t samplePairs;

    *data = vbGetSamples(emu->sim, NULL, NULL, &samplePairs);
    *bytes = samplePairs * 4;
    emu->ctx->currentSample += 1;
    emu->ctx->currentSample %= 2;
    vbSetSamples(emu->sim, emu->ctx->samples[emu->ctx->currentSample], VB_S16, 834);
}

void emuSetKeys(EmulationContext *emu, uint16_t keys) {
    vbSetKeys(emu->sim, keys);
}