#ifndef _GIT_H
#define _GIT_H

#include <string>

#include "file.h"

#define GIT_CART        0       /* Cart. */
#define GIT_VSUNI       1       /* VS Unisystem. */
#define GIT_FDS         2       /* Famicom Disk System. */
#define GIT_NSF         3       /* NES Sound Format. */

#define GIV_NTSC        0       /* NTSC emulation. */
#define GIV_PAL         1       /* PAL emulation. */
#define GIV_USER        2       /* What was set by MDFNI_SetVidSys(). */

#define GISYS_NES       0
#define GISYS_GB        1
#define GISYS_GBA       2
#define GISYS_SNES      3
#define GISYS_PCE	4
#define GISYS_LYNX	5
#define GISYS_PCFX	6
#define GISYS_NGP	7
#define MDFN_EMULATED_SYSTEM_COUNT	8

typedef struct {
        int type;       /* GIT_* */
        int vidsys;     /* Current emulated video system; GIV_* */
        int input[2];   /* Desired input for emulated input ports 1 and 2; -1
                           for unknown desired input. */
        int inputfc;    /* Desired Famicom expansion port device. -1 for unknown
                           desired input. */
        int cspecial;   /* Special cart expansion: DIP switches, barcode
                           reader, etc.
                        */
} MDFNGI_NES;

#include "state.h"
#include "settings-common.h"

#define CONTROLLERDT_UINT8	0
#define CONTROLLERDT_UINT16	1
#define CONTROLLERDT_UINT32	2
#define CONTROLLERDT_UINT64	3
typedef struct
{
 int total_controllers; // Total controllers offered by the system.
 int controller_data_type; // Controller data type.
} NetplaySystemInfoStruct;

#define BPOINT_READ             1
#define BPOINT_WRITE            2
#define BPOINT_PC               3

typedef struct
{
        std::string name;
        unsigned int bsize; // Byte size, 1, 2, 4
} RegType;

typedef struct
{
 RegType *Regs[4];

 uint32 MaxInstructionSize; // Maximum instruction size in bytes

 uint32 LogAddrBits; // Logical address bits
 uint32 PhysAddrBits; // Physical address bits

 uint32 DefaultWatchAddr;

 // If logical is true, then do the peek/poke on logical address A, else do the
 // peek/poke on physical address A.  For now, this distinction only exists
 // on CPUs with built-in bank-switching, like the HuC6280.

 // If hl is true, do not cause any change in the underlying hardware state.
 uint32 (*MemPeek)(uint32 A, unsigned int bsize, bool hl, bool logical);

 // If hl is true, write to the underlying ROM or RAM directly, if present
 void (*MemPoke)(uint32 A, uint32 V, unsigned int bsize, bool, bool logical);

 // If hl is true, do not cause any change in the underlying hardware state.
 uint32 (*GfxMemPeek)(uint32 A, unsigned int bsize, bool hl);

 // If hl is true, write to the underlying ROM or RAM directly, if present
 void (*GfxMemPoke)(uint32 A, uint32 V, unsigned int bsize, bool hl);

 // Disassemble one instruction at logical address A, and increment A to point to the next instruction.
 std::string (*Disassemble)(uint32 &A, uint32 SpecialA);

 // Force an IRQ at the desired level(IRQ0, IRQ1, or whatever).  Pass -1 to cause an NMI, if available.
 // Note that this should cause an interrupt regardless of any flag settings or interrupt status.
 void (*IRQ)(int level);

 // Get the vector for the specified IRQ level.  -1 is NMI(if available), and -2 is RESET.
 uint32 (*GetVector)(int level);

 uint32 (*GetRegister)(std::string name);
 
 void (*SetRegister)(std::string name, uint32 value);

 void (*FlushBreakPoints)(int type);

 void (*AddBreakPoint)(int type, unsigned int A1, unsigned int A2, bool logical);

 void (*SetCPUCallback)(void (*callb)(uint32 PC));

 void (*SetBPCallback)(void (*callb)(uint32 PC));

 std::vector<uint32> (*GetBranchTrace)(void);

} DebuggerInfoStruct;

typedef struct
{
 /* Semi-private: */
 int system;

 /* Private functions to Mednafen.  Do not call directly
    from the driver code, or else bad things shall happen.  Maybe.  Probably not, but don't
    do it(yet)!
 */
 char *shortname;
 DebuggerInfoStruct *Debugger;
 int (*Load)(const char *name, MDFNFILE *fp);
 int (*LoadCD)(void);
 void (*CloseGame)(void);
 bool (*ToggleLayer)(int which);
 const char *LayerNames;
 void (*InstallReadPatch)(uint32 address);
 void (*RemoveReadPatches)(void);
 uint8 (*MemRead)(uint32 addr);

 int (*StateAction)(StateMem *sm, int load, int data_only);
 void (*DoRewind)(void);
 void (*Emulate)(uint32 *pXBuf, MDFN_Rect *LineWidths, int16 **SoundBuf, int32 *SoundBufSize, int skip);
 void (*SetPixelFormat)(int rshift, int gshift, int bshift);
 void (*SetInput)(int port, int type, void *ptr, int attrib);
 void (*SetSoundMultiplier)(double multiplier);
 void (*SetSoundVolume)(uint32 volume);
 void (*Sound)(int32 Rate);
 void (*DoSimpleCommand)(int cmd);
 bool (*StartNetplay)(NetplaySystemInfoStruct *);

 MDFNSetting *Settings;

 uint32 fps; // frames per second * 65536 * 256, truncated
 void *fb;
 int width, height;
 int pitch;
 MDFN_Rect DisplayRect;

 int rotated;
 uint8 *name;    /* Game name, UTF8 encoding */
 uint8 MD5[16];
 int soundrate;  /* For Ogg Vorbis expansion sound wacky support.  0 for default. */
 int soundchan;  /* Number of sound channels. */

 MDFNGI_NES nes;

 /* Private to Mednafen: */
 int rshift, gshift, bshift;
} MDFNGI;
#endif
