#ifndef _FC_API_H
#define _FC_API_H 1

/*
 * Expected signature of main function 
 * non-zero return indicates error to ForceCommand.
 *   This may trigger additional environment restoration upon return.
 * command line parameters are passed as a single un-parsed buffer.
 */
int fc_main(char* args);

#define FC_SYS *(int *)0x2000

#define DECL_FC_API_CALL(index, func, return_type, arg_sig, args)     \
    static inline return_type func arg_sig                            \
    {                                                                 \
        __asm__("li r0,%0"                                            \
                :                                                     \
                : "i"(index));                                        \
        return_type(*tramp) arg_sig = (return_type(*) arg_sig)FC_SYS; \
        return tramp args;                                            \
    }

#define FC_SAMS_TRAMP_DATA *((int*)0x2002)
#define FC_SAMS_TRAMP *(int *)0x2004

/*
 * Use FC_SAMS_BANKED to declare (prototype) a non-void function that can be called 
 * with SAMS bank switching.
 * 
 * Define the function in the module (.c) with FC_SAMS(function_name) 
 */
#define FC_SAMS_BANKED(bank_id, return_type, function_name, param_signature, param_list)          \
    static inline return_type function_name param_signature                                       \
    {                                                                                             \
      return_type b##bank_id##_##function_name param_signature ;                                  \
      if (bank_id == SAMS_CURRENT_BANK) {                                                         \
        return b##bank_id##_##function_name param_list ;                                          \
      }                                                                                           \
      static const int fcsams_data_##function_name[] = {                                          \
        (int)bank_id,                                                                             \
        (int)SAMS_CURRENT_BANK,                                                                   \
        (int)b##bank_id##_##function_name                                                         \
      };                                                                                          \
      FC_SAMS_TRAMP_DATA = (int) fcsams_data_##function_name;                                     \
      return_type (*fcstramp) param_signature = (return_type (*) param_signature) FC_SAMS_TRAMP;  \
      return fcstramp param_list;                                                                 \
    }                                                                                             \

/*
 * Use FC_SAMS_VOIDBANKED to declare (prototype) a void function that can be called 
 * with SAMS bank switching.
 * 
 * Define the function in the module (.c) with FC_SAMS(function_name) 
 */
#define FC_SAMS_VOIDBANKED(bank_id, function_name, param_signature, param_list)          \
    static inline void function_name param_signature                                     \
    {                                                                                    \
      void b##bank_id##_##function_name param_signature ;                                \
      if (bank_id == SAMS_CURRENT_BANK) {                                                \
        b##bank_id##_##function_name param_list ;                                        \
        return;                                                                          \
      }                                                                                  \
      static const int fcsams_data_##function_name[] = {                                 \
        (int)bank_id,                                                                    \
        (int)SAMS_CURRENT_BANK,                                                          \
        (int)b##bank_id##_##function_name                                                \
      };                                                                                 \
      FC_SAMS_TRAMP_DATA = (int) fcsams_data_##function_name;                            \
      void (*fcstramp) param_signature = (void (*) param_signature) FC_SAMS_TRAMP;       \
      fcstramp param_list;                                                               \
    }                                                                                    \

/*
 * add bank identifier to function_name when defining for SAMS banking in module (.c)
 * files.
 */
#define FC_SAMS(bank_id, function_name) b##bank_id##_##function_name

/*
  Device Service Routine pre-loaded entry
*/
struct __attribute__((__packed__)) DeviceServiceRoutine {
    char name[8];
    int crubase;
    unsigned int addr;
    char unit;
};

/*
  System information structure
*/
struct __attribute__((__packed__)) SystemInformation {
  struct DeviceServiceRoutine* dsrList; // points to array of 20 dsrs
  struct DeviceServiceRoutine* currentDsr;
  const char* currentPath;
  unsigned int vdp_io_buf;
};

// Values for vdp_type in DisplayInformation
#define VDP_F18A 0xF18A
#define VDP_9938 0x9938
#define VDP_9958 0x9958
#define VDP_9918 0x9918

// Color attribute values
#define COLOR_TRANS 0x00
#define COLOR_BLACK 0x01
#define COLOR_MEDGREEN 0x02
#define COLOR_LTGREEN 0x03
#define COLOR_DKBLUE 0x04
#define COLOR_LTBLUE 0x05
#define COLOR_DKRED 0x06
#define COLOR_CYAN 0x07
#define COLOR_MEDRED 0x08
#define COLOR_LTRED 0x09
#define COLOR_DKYELLOW 0x0A
#define COLOR_LTYELLOW 0x0B
#define COLOR_DKGREEN 0x0C
#define COLOR_MAGENTA 0x0D
#define COLOR_GRAY 0x0E
#define COLOR_WHITE 0x0F

/*
  Display parameter structure
*/
struct __attribute__((__packed__)) DisplayInformation {
  int isPal;
  int vdp_type;
  int displayWidth;
  int displayHeight;
  int imageAddr;
  int patternAddr;
  int colorAddr;
  int spritePatternAddr;
};

struct __attribute__((__packed__)) SamsInformation {
  int next_page;
  int total_pages;
};

/*
  Peripheral Access Block
*/
struct __attribute__((__packed__)) PAB {
    unsigned char OpCode;		// see DSR_xxx list above
    unsigned char Status;		// file type and error code (DSR_ERR_xxx and DSR_TYPE_xxx)
    unsigned int  VDPBuffer;		// address of the data buffer in VDP memory
    unsigned char RecordLength;		// size of records. Not used for PROGRAM type. >00 on open means autodetect
    unsigned char CharCount;		// number of bytes read or number of bytes to write
    unsigned int  RecordNumber;		// record number for normal files, available bytes (LOAD or SAVE) for PROGRAM type
    unsigned char ScreenOffset;		// Used in BASIC for screen BIAS. Also returns file status on Status call. (DSR_STATUS_xxx)
    unsigned char NameLength;		// for this implementation only, set to zero to read the length from the string
    char *pName;			// for this implementation only, must be a valid C String even if length is set
};

/*
  For direct input and direct file meta data is represented as AddInfo ( or additional information )
*/
struct __attribute__((__packed__)) AddInfo {
  unsigned int buffer;
  unsigned int first_sector;
  unsigned char flags;
  unsigned char recs_per_sec;
  unsigned char eof_offset;
  unsigned char rec_length;
  unsigned int records; // swizzled
};

/*
  File open mode types, default DISPLAY, FIXED, UPDATE, SEQUENTIAL
*/
#define DSR_TYPE_VARIABLE	0x10
#define DSR_TYPE_INTERNAL	0x08
#define DSR_TYPE_OUTPUT		0x02
#define DSR_TYPE_INPUT		0x04
#define DSR_TYPE_APPEND		0x06
#define DSR_TYPE_RELATIVE	0x01

/*
  catalog call back functions
*/
struct __attribute__((__packed__)) DirEntry {
  char name[11];
  int type;
  int sectors;
  int reclen;
  char ts_hour;
  char ts_min;
  char ts_second;
  int ts_year;
  char ts_month;
  char ts_day;
};

struct __attribute__((__packed__)) VolInfo {
  char volname[11];
  int total;
  int available;
  char timestamps;
  struct DeviceServiceRoutine* dsr;
};

typedef void (*vol_entry_cb)(struct VolInfo*);
typedef void (*dir_entry_cb)(struct DirEntry*);

/*
  clock DateTime structure
*/
struct __attribute__((__packed__)) DateTime {
  unsigned char dayOfWeek;
  unsigned int year;
  unsigned char month;
  unsigned char day;
  unsigned char hours;
  unsigned char minutes;
  unsigned char seconds;
  unsigned char pm;
};

/*
  fc_parse_path_param option constants
 */
#define PR_OPTIONAL 0x0000
#define PR_REQUIRED 0x0001
#define PR_WILDCARD 0x0002

/*
  response hook for terminal CSI commands that
  transmit back to server. For use fc_set_identify_hook.
  If flag is 1, send ANSI identify code, if 52, send vt52 code
 */
typedef void (*identify_callback)(int flag);

/*
  speech LPC code tracking cursor structure
 */
struct __attribute__((__packed__)) LpcPlaybackCtx {
    char* addr;
    int remaining;
};

/*
  TIPI Mouse return data and butten masks
 */
struct __attribute__((__packed__)) MouseData {
  char mx;
  char my;
  char buttons;
  int pointerx;
  int pointery;
};

#define MB_LEFT 0x01
#define MB_RIGHT 0x02
#define MB_MID 0x04

/*
  State for reentrant bufferedio socket api
 */
struct __attribute__((__packed__)) SocketBuffer {
  unsigned int socket_id;
  char buffer[256];
  int available;
  char lastline[256];
  int loaded;
  int tls;
};

#define TLS 1
#define TCP 0

/*
 Linked List stack that shoves oldest items off to make room if necessary.
 Use with fc_list_ functions.
 */
struct __attribute__((__packed__)) List {
  char* addr;
  char* end;
  char* ceiling;
};
  
struct __attribute__((__packed__)) ListEntry {
  int length;
  char data[];
};



/*
  Rom address tables
*/

// memcpy is special, it is in all bank of the cartridge
extern void* memcpy(void* dest, const void* src, int count);

