#ifndef __TAP_LOADER____H__
#define __TAP_LOADER____H__

#include <SDL.h>

#include "Cpu.h"

enum tapHeaderType { Program=0, NumberArray=1, CharacterArray=2, Code=3 };
enum tapBlockType { Header=0x00, Data=0xFF };

// properties exposed from the data area of a block, when that block is of Header type
struct tapHeaderBlock {
    enum tapHeaderType type;
    char* filename;
    Uint16 dataBlockLength;
    Uint16 parameter1;
    Uint16 parameter2;
};

// a single TAP block
struct tapBlock {
    enum tapBlockType type;
    struct tapHeaderBlock* headerInfo;  // non-NULL when type is Header
    Uint16 blockDataSize;   // whatever the first two bytes of the TAP header said
    Uint16 blockRawDataSize; // excluding ZX Spectrum block's type and checksum bytes
    Uint8 flagByte;         // helps differentiate between 0xFF data and
                            //     headerless (seemingly any value except
                            //     0x00 and 0xFF)
    const char* flagByteHumanReadable;

    Uint8* tapBlockBytes;       // points to first size byte
    Uint32 tapBlockOffset;      // within TAP file
    Uint32 tapBlockEndOffset;   // within TAP file
    Uint16 tapBlockSize;        // including size bytes

    Uint16 blockIndex;
};

// what the "tape player" is doing in a run state
enum tapRunStateType { Stopped, Silence, LeadTone, SyncPulse1, SyncPulse2, DataBytes };

struct tapRunState {
    enum tapRunStateType type;
    Sint64 pulsesRemaining;         // until next run state or next bit
    Sint64 tstatesRemaining;        // until next pulse
    Uint32 tstatesPerPulse;

    struct tapBlock* block;
    Uint8* dataBytePointer;
    Sint8 bitNumber;
};

void taploader_start();
void taploader_destroy();

struct tapRunState taploader_get_state();
Uint16 taploader_get_block_count();

void taploader_seek_next();
void taploader_seek_previous();
void taploader_press_play(Uint8 isContinuous);
void taploader_press_stop();
void taploader_set_desired_turbo(Uint8 isEnabled);

void taploader_set_on_stop_handler(void (*handler)());
void taploader_set_on_play_handler(void (*handler)());

Uint8 taploader_load(char* filename);
Uint8 taploader_is_file_loaded();

void taploader_on_instruction_tstates_elapsed(struct instruction* instruction);
void taploader_on_instruction_tstates_elapsed__tap_independent_border_effect(struct instruction* instruction);

#endif  // !__TAP_LOADER____H__
