#pragma once


// =======================================================================
// =                   C64EmulatorExtension Interface                    =
// =               Copyright (C) 2013-2014 Thomas Hochgoetz              =
// =                       All rights reserved.                          =
// =======================================================================
// =       Read the "C64 Extension Interface Documentation"              =
// =======================================================================



#ifdef  __cplusplus
extern "C" {
#endif


// ============================================================>
// ======================== DEFINES ===========================>
// ============================================================>


#if defined( CEP_STATIC )
#define			CEP_EXPORT
#elif defined( CEP_IMPORT )
#define			CEP_EXPORT        __declspec(dllimport)
#else
#define			CEP_EXPORT        __declspec(dllexport)
#endif
#define     CEP_API           __cdecl


#define __STL_MEMBER_TEMPLATES

#ifndef NULL
#ifdef  __cplusplus
#define NULL    0
#else
#define NULL    ((void *)0)
#endif
#endif

#ifndef _WCHAR_T_DEFINED
typedef unsigned short wchar_t;
#define _WCHAR_T_DEFINED
#endif
typedef long long DLONG;
typedef wchar_t TSCHAR;
typedef unsigned short MEMADDRESS;
typedef unsigned char MEMBYTE;
typedef unsigned char SERBYTE;
typedef unsigned int USERPORT;
typedef void* CONTEXT_COOKIE;


#define CEP_INTERFACE_VERSION  6



// ============================================================>
// ========================= ENUMS ============================>
// ============================================================>


typedef enum CEP_RESULT__
{
    ECEP_RESULT_OK,
    ECEP_RESULT_ERROR,
    ECEP_RESULT_ERROR_ARGUMENTS,
    ECEP_RESULT_ERROR_DEVICE_NOTFOUND,
    ECEP_RESULT_ERROR_PLUGIN_CONTEXT,
} CEP_RESULT;


typedef enum CEP_BOOL__
{
    ECEP_FALSE,
    ECEP_TRUE,
} CEP_BOOL;


typedef enum CEP_DEVICE__
{
    ECEP_DEVICE_C64,
    ECEP_DEVICE_DRIVE_8,
    ECEP_DEVICE_DRIVE_9,
    ECEP_DEVICE_DRIVE_10,
    ECEP_DEVICE_DRIVE_11,
} CEP_DEVICE;


typedef enum CEP_DISABLE_MASK__
{
    CEP_DISABLE_BOARD_CPU         = 1,
    CEP_DISABLE_SERIAL_PORT       = 2,
    CEP_DISABLE_SERIAL_CHANNEL    = 4,
    CEP_DISABLE_AUDIO_VIDEO       = 8,
    CEP_DISABLE_USER_PORT         = 16,
} CEP_DISABLE_MASK;


typedef enum CEP_EVENT__
{
    CEP_EVENT_KEY_CHAR,
    CEP_EVENT_VKEY_DOWN,
    CEP_EVENT_VKEY_UP,
    CEP_EVENT_MOUSE_CLICK,
    CEP_EVENT_CARTRIDGE_BUTTON,

    CEP_EVENT_LOAD_SNAPSHOT = 64,
    CEP_EVENT_SAVE_SNAPSHOT,
    CEP_EVENT_SPEED_CHANGED,
    CEP_EVENT_LEAVE_EMULATION,
    CEP_EVENT_ENTER_EMULATION,
} CEP_EVENT;


typedef enum CEP_MEMORY_OPTION__
{
    CEP_MEMORY_DEFAULT,
    CEP_MEMORY_DEBUG,
} CEP_MEMORY_OPTION;


typedef enum CEP_MEMORY_EVENT__
{
    CEP_MEMORY_EVENT_GET,
    CEP_MEMORY_EVENT_SET,
} CEP_MEMORY_EVENT;


typedef enum CEP_MEMORY_TYPE__
{
    // === C64 ===
    CEP_MEMORY_TYPE_RAM,
    CEP_MEMORY_TYPE_CHIP,
    CEP_MEMORY_TYPE_ROM_BASIC,
    CEP_MEMORY_TYPE_ROM_CHARACTER,
    CEP_MEMORY_TYPE_ROM_KERNAL,
    CEP_MEMORY_TYPE_CARTRIDGE,

    CEP_MEMORY_TYPE_UNKNOWN,

    // === Floppy 1541 ===
    CEP_MEMORY_TYPE_FLOPPY_RAM = 0,
    CEP_MEMORY_TYPE_FLOPPY_ROM_KERNAL = 1,
    CEP_MEMORY_TYPE_FLOPPY_CHIP = 2,
    CEP_MEMORY_TYPE_FLOPPY_OPEN = 16,

} CEP_MEMORY_TYPE;


typedef enum CEP_INTERRUPT_TYPE__
{
    CEP_INT_IRQ,
    CEP_INT_NMI,
} CEP_INTERRUPT_TYPE;


typedef enum CEP_INTERRUPT_DRIVER__
{
    // === C64 ===
    CEP_INT_DRIVER_CIA1,                  // CIA1 (0xDC00-0xDCFF) [IRQ]
    CEP_INT_DRIVER_CIA2,                  // CIA2 (0xDD00-0xDDFF) [NMI]
    CEP_INT_DRIVER_VIC,                   // VIC [IRQ]
    CEP_INT_DRIVER_CARTRIDGE,             // CARTRIDGE [IRQ/NMI]
    CEP_INT_DRIVER_PLUGIN,                // PLUGIN [IRQ/NMI]
    CEP_INT_DRIVER_RESTORE,               // RESTORE KEY [NMI]

     // === Floppy 1541 ===
    CEP_INT_DRIVER_6522_1 = CEP_INT_DRIVER_CIA1,    // MOS6522-Serial (0x1800) [IRQ]
    CEP_INT_DRIVER_6522_2 = CEP_INT_DRIVER_CIA2,    // MOS6522-Disk   (0x1C00) [IRQ]

} CEP_INTERRUPT_DRIVER;


typedef enum CEP_CPU_STATUS__
{
    CEP_CPU_STATUS_CARRY      = (1<<0),
    CEP_CPU_STATUS_ZERO       = (1<<1),
    CEP_CPU_STATUS_INTERRUPT  = (1<<2),
    CEP_CPU_STATUS_DECIMAL    = (1<<3),
    CEP_CPU_STATUS_BREAK      = (1<<4),
    CEP_CPU_STATUS_EXP        = (1<<5),
    CEP_CPU_STATUS_OVERFLOW   = (1<<6),
    CEP_CPU_STATUS_NEGATIVE   = (1<<7),

} CEP_CPU_STATUS;


typedef enum CEP_JOYSTICK_FLAGS__
{
    CEP_JOY_UP        = 1,
    CEP_JOY_DOWN      = 2,
    CEP_JOY_LEFT      = 4,
    CEP_JOY_RIGHT     = 8,
    CEP_JOY_BUTTTON1  = 16,
    CEP_JOY_BUTTTON2  = 32,
    CEP_JOY_BUTTTON3  = 64,
    CEP_JOY_BUTTTON4  = 128,
} CEP_JOYSTICK_FLAGS;


// === SERBYTE ===
typedef enum CEP_SERIAL_PORT__
{
    CEP_SERIAL_ATN  = 1,                  // acknowlege bit, lo-active
    CEP_SERIAL_CLK  = 2,                  // clock bit, lo-active
    CEP_SERIAL_DTA  = 4,                  // data bit, lo-active
    CEP_SERIAL_RST  = 8,                  // reset bit, lo-active
    CEP_SERIAL_SRQ  = 16,                 // serial request bit, lo-active
    CEP_SERIAL_MASK = 31,                 // mask
} CEP_SERIAL_PORT;


typedef enum CEP_SERIAL_DATA_EOI__
{
    CEP_SERIAL_DATA_CONTINUE,
    CEP_SERIAL_DATA_LAST,
} CEP_SERIAL_DATA_EOI;


typedef enum CEP_SERIAL_MODE__
{
    CEP_SERIAL_MODE_RECEIVE,
    CEP_SERIAL_MODE_REQUEST,
} CEP_SERIAL_MODE;


typedef enum CEP_SERIAL_DEVICE__
{
    ECEP_SERIAL_NONE,
    ECEP_SERIAL_PLUGIN,
    ECEP_SERIAL_1541,
    ECEP_SERIAL_MPS801,
} CEP_SERIAL_DEVICE;


typedef enum CEP_CARTRIDGE_MODE__
{
  CEP_CARTRIDGE_16KB,                     // 0x8000/0x2000  0xA000/0x2000(BASIC ROM)      buffer size: 0x4000 bytes (lo and hi block)
  CEP_CARTRIDGE_8KB,                      // 0x8000/0x2000                                buffer size: 0x2000 bytes (lo block only)
  CEP_CARTRIDGE_ULTIMAX,                  // 0x8000/0x2000  0xE000/0x2000(KERNAL ROM)     buffer size: 0x4000 bytes (lo and hi block)
  CEP_CARTRIDGE_NONE,                     // no mapping
} CEP_CARTRIDGE_MODE;


typedef enum CEP_CARTRIDGE_FLAGS__
{
  CEP_CARTFLAG_READ_WRITE           = 0,
  CEP_CARTFLAG_READ_ONLY            = (1<<0),
  CEP_CARTFLAG_IO1_ALWAYS_VISIBLE   = (1<<4),
  CEP_CARTFLAG_IO2_ALWAYS_VISIBLE   = (1<<5),
} CEP_CARTRIDGE_FLAGS;


// === USERPORT ===
typedef enum CEP_USER_PORT__
{
  CEP_USER_PORTB0  = (1<<0),              // in/out port B0
  CEP_USER_PORTB1  = (1<<1),              // in/out port B1
  CEP_USER_PORTB2  = (1<<2),              // in/out port B2
  CEP_USER_PORTB3  = (1<<3),              // in/out port B3
  CEP_USER_PORTB4  = (1<<4),              // in/out port B4
  CEP_USER_PORTB5  = (1<<5),              // in/out port B5
  CEP_USER_PORTB6  = (1<<6),              // in/out port B6
  CEP_USER_PORTB7  = (1<<7),              // in/out port B7

  CEP_USER_ATN     = (1<<8),              // out serial CBM ATN (equal to CEP_SERIAL_ATN)
  CEP_USER_FLAG2   = (1<<9),              // in CIA2 flag pin - NMI interrupt
  CEP_USER_PORTA2  = (1<<10),             // in/out port A2
  CEP_USER_SP1     = (1<<11),             // in/out CIA1 sp pin
  CEP_USER_CNT1    = (1<<12),             // in/out CIA1 cnt pin
  CEP_USER_SP2     = (1<<13),             // in/out CIA2 sp pin
  CEP_USER_CNT2    = (1<<14),             // in/out CIA2 cnt pin
  CEP_USER_PC2     = (1<<15),             // out CIA2 handshake

  CEP_USER_UNSET_MASK   = (1<<16)-1,
  CEP_USER_INPUT_MASK   = CEP_USER_FLAG2|CEP_USER_PORTA2|CEP_USER_SP1|CEP_USER_CNT1|CEP_USER_SP2|CEP_USER_CNT2,
} CEP_USER_PORT;


typedef enum CEP_PICTURE_FORMAT__
{
    CEP_PICFMT_RGB32,                     // RGB 32 bit color mode (little endian) (DEFAULT)
    CEP_PICFMT_PALETTE8,                  // 8 bit color palette
} CEP_PICTURE_FORMAT;


typedef enum CEP_SOUND_FORMAT__
{
    CEP_SNDFMT_8BIT_PCM,                  // 8 bit PCM samples
    CEP_SNDFMT_16BIT_PCM,                 // 16 bit PCM samples (DEFAULT)
} CEP_SOUND_FORMAT;


// ============================================================>
// ====================== STRCUTURES ==========================>
// ============================================================>


typedef struct PluginHandle__
{
    int unused;
} PluginHandle, *HPLUGIN;


typedef struct CPUInfo__
{
    MEMBYTE                           statusFlags;
    MEMBYTE                           stackPointer;
    MEMADDRESS                        programPointer;
    MEMBYTE                           registerAkku;        
    MEMBYTE                           registerX;        
    MEMBYTE                           registerY;        
    MEMBYTE                           actCommand;        
    MEMBYTE                           actCommandDataCount;        
    MEMBYTE                           actCommandData[3];
    const char*                       actCommandText;
    unsigned int                      interruptMask;
} CPUInfo;


typedef void (*MAKE_CURRENT)(HPLUGIN, CEP_BOOL);                                  // (HPLUGIN pluginHandle, CEP_BOOL set)
typedef HPLUGIN (*CONTEXT_CALLBACK)(CONTEXT_COOKIE*);                                                                 // (CONTEXT_COOKIE* cookieOut)
typedef CEP_RESULT (*MEMSET_CALLBACK)(MEMADDRESS, MEMBYTE);                       // (MEMADDRESS address, MEMBYTE value)
typedef CEP_RESULT (*MEMGET_CALLBACK)(MEMADDRESS, MEMBYTE*, CEP_MEMORY_OPTION);   // (MEMADDRESS address, MEMBYTE* value, CEP_MEMORY_OPTION option)
typedef CEP_RESULT (*MEMREGISTER_EVENT_CALLBACK)(MEMADDRESS, MEMADDRESS);         // (MEMADDRESS address, MEMADDRESS length)
typedef CEP_RESULT (*MEMUNREGISTER_EVENT_CALLBACK)(MEMADDRESS, MEMADDRESS);       // (MEMADDRESS address, MEMADDRESS length)
typedef CEP_RESULT (*KEY_EVENT_CALLBACK)(int, CEP_BOOL);                          // (int vkey, CEP_BOOL keyDown)
typedef CEP_RESULT (*JOY_EVENT_CALLBACK)(int, int);                               // (int port, int CEP_JOYSTICK_FLAGS)
typedef CEP_RESULT (*JOY_PADDLES_CALLBACK)(int, MEMBYTE, MEMBYTE);                // (int port, MEMBYTE paddleX, MEMBYTE paddleY)
typedef void (*TEXT_CALLBACK)(const char*);                                       // (text)
typedef void (*INTERRUPT_CALLBACK)(CEP_INTERRUPT_TYPE, CEP_BOOL);                 // (CEP_INTERRUPT_TYPE type, CEP_BOOL enable)
typedef CEP_RESULT (*CPUINFO_CALLBACK)(CPUInfo*, CEP_DEVICE);                     // (CPUInfo*, CEP_DEVICE device)
typedef CEP_RESULT (*LOADSNAPSHOT_CALLBACK)(const char*, unsigned int);           // (const char* buffer, unsigned int size)
typedef CEP_RESULT (*SAVESNAPSHOT_CALLBACK)(char*, unsigned int*);                // (char* buffer, unsigned int* size(in/out))
typedef const void* (*PROPERTY_CALLBACK)(const char*);                            // (const char*)
typedef CEP_RESULT (*PROPERTY_SET_CALLBACK)(const char*, const void*);            // (const char* name, void* value)
typedef CEP_RESULT (*BREAK_POINT_CALLBACK)(MEMADDRESS, CEP_BOOL);                 // (MEMADDRESS address, CEP_BOOL enable)
typedef const CEP_MEMORY_TYPE* (*MEMTYPE_CALLBACK)();                             // () return CEP_MEMORY_TYPE[16] array
typedef CEP_RESULT (*MEMGET_EX_CALLBACK)(MEMADDRESS, MEMBYTE*, CEP_MEMORY_OPTION, CEP_DEVICE, CEP_MEMORY_TYPE);       // (MEMADDRESS address, MEMBYTE* value, CEP_MEMORY_OPTION option, CEP_DEVICE device, CEP_MEMORY_TYPE memType)
typedef CEP_RESULT (*MEMSET_EX_CALLBACK)(MEMADDRESS, MEMBYTE, CEP_DEVICE, CEP_MEMORY_TYPE);                           // (MEMADDRESS address, MEMBYTE value, CEP_DEVICE device, CEP_MEMORY_TYPE memType)
typedef CEP_RESULT (*SET_DEVICE_CONTEXT_CALLBACK)(CEP_DEVICE);                    // (CEP_DEVICE device)
typedef CEP_RESULT (*SET_SERIAL_DEVICE_CALLBACK)(int, CEP_SERIAL_DEVICE, CEP_BOOL, const char*, unsigned int);         // (int serialPort, CEP_SERIAL_DEVICE device, CEP_BOOL createNew, const char* dataIn, unsigned int size)
typedef CEP_SERIAL_DEVICE (*GET_SERIAL_DEVICE_CALLBACK)(int, char*, unsigned int*);         // (int serialPort, CEP_DEVICE device, char* dataOut, unsigned int* sizeInOut)


typedef struct InitializeInfo__
{
    int                               structSize;             // GET: size in bytes of this structure
    void*                             hwndParent;             // GET: HWND parent window handle
    HPLUGIN                           hPlugin;                // GET: plugin context handle
    const char*                       commandLine;            // GET: command line parameters for plugin
    short                             hostInterfaceVersion;   // GET: C64 emulator interface version
    short                             serialDeviceNumber;     // SET: optional serial device number - see SERIAL DATA/CHANNEL-LEVEL
    const char*                       pluginName;             // SET: your plugin name
    const char*                       pluginVersion;          // SET: your plugin version
    CONTEXT_COOKIE                    contextCookie;          // SET: set a cookie here for later use (callbackGetContext)
    unsigned int                      disableMask;            // SET: disable mask - see CEP_DISABLE_MASK
    MAKE_CURRENT                      callbackMakeCurrent;    // CALLBACK: make plugin callbacks and context available for the current calling thread
    CONTEXT_CALLBACK                  callbackGetContext;     // CALLBACK: get the current context
    MEMSET_CALLBACK                   callbackMemSet;         // CALLBACK: set a byte into the memory
    MEMGET_CALLBACK                   callbackMemGet;         // CALLBACK: get a byte from the memory
    MEMREGISTER_EVENT_CALLBACK        callbackRegisterEvent;  // CALLBACK: register a memory event 	      ==> implement CEP_MemoryEvent()
    MEMUNREGISTER_EVENT_CALLBACK      callbackUnregisterEvent;// CALLBACK: unregister a memory event 	    ==> implement CEP_MemoryEvent()
    KEY_EVENT_CALLBACK                callbackKey;            // CALLBACK: press a keyboard key (up/down)
    JOY_EVENT_CALLBACK                callbackJoystick;       // CALLBACK: set a joystick state			      ==> see CEP_JOYSTICK_FLAGS for joystickFlags
    TEXT_CALLBACK                     callbackText;           // CALLBACK: display a text into the emulator
    INTERRUPT_CALLBACK                callbackInterrupt;      // CALLBACK: set/unset the interrrupt line
    CPUINFO_CALLBACK                  callbackCPUInfo;        // CALLBACK: get cpu information
    LOADSNAPSHOT_CALLBACK             callbackLoadSnapshot;   // CALLBACK: restore the state of emulator
    SAVESNAPSHOT_CALLBACK             callbackSaveSnapshot;   // CALLBACK: load the actual state into the buffer
    PROPERTY_CALLBACK                 callbackProperty;       // CALLBACK: get property by name
    JOY_PADDLES_CALLBACK              callbackJoyPaddles;     // CALLBACK: set paddles values (SID)
    PROPERTY_SET_CALLBACK             callbackSetProperty;    // CALLBACK: set property by name
    BREAK_POINT_CALLBACK              callbackSetBreakPoint;  // CALLBACK: set cpu break point event
    MEMTYPE_CALLBACK                  callbackMemoryTypes;    // CALLBACK: returns an array of 16 CEP_MEMORY_TYPE for every 0x1000 bytes memory
    MEMSET_EX_CALLBACK                callbackMemSetEx;       // CALLBACK: set a byte into a specified memory type
    MEMGET_EX_CALLBACK                callbackMemGetEx;       // CALLBACK: get a byte from a specified memory type
    SET_DEVICE_CONTEXT_CALLBACK       callbackSetDeviceContext; // CALLBACK: set a specified device context
    SET_SERIAL_DEVICE_CALLBACK        callbackSetSerialDevice;// CALLBACK: set a specified device for a serial port - data and size are optional
    GET_SERIAL_DEVICE_CALLBACK        callbackGetSerialDevice;// CALLBACK: get a specified device for a serial port - data and size are optional
} InitializeInfo;



typedef enum CEP_CONFIG_TYPE__
{
    CEP_CONFIG_INITIALIZE,
    CEP_CONFIG_CHANGED,
    CEP_CONFIG_REQUEST_UPDATE,
} CEP_CONFIG_TYPE;

typedef enum CEP_CONFIG_GLOBALS__
{
    CEP_CONF_MAX_ENTRIES  = 8,
    CEP_CONF_MAX_VALUES  = 8,
    CEP_CONF_MAX_NAME  = 16,
} CEP_CONFIG_GLOBALS;

typedef struct ConfigurationEntry__
{
    int                               selectCount;
    char                              name[CEP_CONF_MAX_NAME];
    char                              valueNames[CEP_CONF_MAX_VALUES][CEP_CONF_MAX_NAME];
    int                               valueSelected;
} ConfigurationEntry;

typedef struct Configuration__
{
    int                               valueCount;
    ConfigurationEntry                values[CEP_CONF_MAX_ENTRIES];
} Configuration;



// ============================================================>
// ======================== FUNCTIONS =========================>
// ============================================================>



//============================ GLOBALS =================================
CEP_EXPORT      int                       CEP_API CEP_InterfaceVersion();
CEP_EXPORT      CEP_RESULT                CEP_API CEP_Initialize( InitializeInfo* infoInOut );
CEP_EXPORT      void                      CEP_API CEP_Deinitialize();
CEP_EXPORT      void                      CEP_API CEP_Configuration( CEP_CONFIG_TYPE type, Configuration* config );

//====================== MAIN EMULATION (OPTIONAL) =====================
CEP_EXPORT      void                      CEP_API CEP_Reset();
CEP_EXPORT      void                      CEP_API CEP_Event( CEP_EVENT type, int data );
CEP_EXPORT      unsigned int              CEP_API CEP_PluginSnapshot( CEP_MEMORY_EVENT type, void* buffer, unsigned int size );

//======================== BOARD/CPU (OPTIONAL) ========================
CEP_EXPORT      void                      CEP_API CEP_Calc( int cycles );
CEP_EXPORT      void                      CEP_API CEP_InterruptChanged( CEP_INTERRUPT_TYPE type, CEP_BOOL enabled );
CEP_EXPORT      void                      CEP_API CEP_BreakPointEvent( const CPUInfo* pInfo );

//========================== MEMORY (OPTIONAL) =========================
CEP_EXPORT      CEP_RESULT                CEP_API CEP_MemoryEvent( MEMADDRESS address, MEMBYTE* value, CEP_MEMORY_EVENT type, CEP_MEMORY_OPTION option );
CEP_EXPORT      MEMBYTE*                  CEP_API CEP_InitCartridge( CEP_CARTRIDGE_MODE* mode, CEP_CARTRIDGE_FLAGS* cartridgeFlags );

//====================== SERIAL PORT-LEVEL (OPTIONAL) ==================
CEP_EXPORT      SERBYTE                   CEP_API CEP_GetSerialPort();
CEP_EXPORT      void                      CEP_API CEP_SetSerialPort( SERBYTE data );

//==================== SERIAL DATA/CHANNEL-LEVEL (OPTIONAL) ============
CEP_EXPORT      void                      CEP_API CEP_SerialOpenChannel( int channel, const char* command, int size, CEP_SERIAL_MODE mode );
CEP_EXPORT      void                      CEP_API CEP_SerialCloseChannel( int channel );
CEP_EXPORT      void                      CEP_API CEP_SerialRecvData( int channel, const char* data, int size, CEP_SERIAL_DATA_EOI eoi );
CEP_EXPORT      int                       CEP_API CEP_SerialRequestData( int channel, char* data, int maxSize, CEP_SERIAL_DATA_EOI* eoi );

//====================== USER PORT (OPTIONAL) ==================
CEP_EXPORT      USERPORT                  CEP_API CEP_GetUserPort();
CEP_EXPORT      void                      CEP_API CEP_SetUserPort( USERPORT data, int cycles );

//======================= PICTURE/SOUND (OPTIONAL) ======================
CEP_EXPORT      void                      CEP_API CEP_Picture( CEP_PICTURE_FORMAT format, int pixelSizeX, int pixelSizeY, const char* picture );
CEP_EXPORT      void                      CEP_API CEP_Sound( CEP_SOUND_FORMAT format, int sampleRate, int samples, const char* sound );



#ifdef  __cplusplus
};
#endif

