#pragma once

#include <stdint.h>

typedef struct Drive Drive;
typedef void (*DriveReadFn)(Drive* drive, uint8_t* block, uint16_t i);
typedef void (*DriveWriteFn)(Drive* drive, const uint8_t* block, uint16_t i);

struct Drive {
    void* self;
    uint16_t block_size;
    uint16_t block_amount;
    DriveReadFn read;
    DriveWriteFn write;
};

typedef enum {
    InterruptType_None,
    InterruptType_Shutdown,
    InterruptType_KeyEvent,
} InterruptType;

typedef struct {
    InterruptType type;
    union {
        uint16_t keycode;
    };
} Interrupt;

#define VCD_BUFFER_OFFSET 0x0c00
#define VCD_BUFFER_SIZE 480
#define VCD_SCREEN_WIDTH 40
#define VCD_SCREEN_HEIGHT 12

typedef struct IODevice IODevice;
typedef void (*IODeviceSetCharFn)(
    IODevice* device, uint16_t offset, uint8_t value);
typedef void (*IODeviceWaitForInterruptFn)(IODevice* device);
typedef Interrupt (*IODeviceMaybeNextInterruptFn)(IODevice* device);

struct IODevice {
    void* self;
    IODeviceSetCharFn set_char;
    IODeviceWaitForInterruptFn wait_for_interrupt;
    IODeviceMaybeNextInterruptFn maybe_next_interrupt;
};

void vm_start(Drive* boot_drive, IODevice* io_device);