#ifndef VGI_H_
#define VGI_H_

#include "vgagames4.h"

#include "sml3.h"
#include "opt_disable.h"
#include "extlib/extlib.h"

#include <sys/types.h>
#include <stdarg.h>


/* absolute value of an integer, minimum and maximum value of two integers */
#define ABSVAL(VAL) ((VAL) < 0 ? -(VAL) : (VAL))
#define MINVAL(VAL1, VAL2) ((VAL1) < (VAL2) ? (VAL1) : (VAL2))
#define MAXVAL(VAL1, VAL2) ((VAL1) > (VAL2) ? (VAL1) : (VAL2))

/* return RGBA-values from VG_COLORS-value */
#define GET_RGBA(COLOR, RCP, GCP, BCP, AAP) \
  do { \
    int col = (COLOR); \
    if (col == VG_COLOR_TRANSPARENT || col < 0) { \
      if ((AAP) != NULL) { *(AAP) = 0; } \
      col = 0; \
    } else { \
      if ((AAP) != NULL) { *(AAP) = 0xff; } \
    } \
    if ((RCP) != NULL) { *(RCP) = (unsigned char)((col >> 16) & 0xff); } \
    if ((GCP) != NULL) { *(GCP) = (unsigned char)((col >> 8) & 0xff); } \
    if ((BCP) != NULL) { *(BCP) = (unsigned char)(col & 0xff); } \
  } while (0)

/* whitespaces */
#define VGI_WSPACE  " \t\r\n"
#define VGI_SPACE   " \t\r"

/* default waiting time for internal loops */
#define VGI_WAIT_TIME 80

/* size for paths */
#define VGI_PATHSIZE 512

/* low or high */
#define VGI_SIZE_LOW   "low"
#define VGI_SIZE_HIGH  "high"

/* container struct for image and sprite */
struct vgi_imgcnt {
  enum { VGI_IMGCNT_NONE = 0, VGI_IMGCNT_IMAGE, VGI_IMGCNT_SPRITE } type;
  union {  /* according to issprite */
    struct VG_Image *img;    /* image */
    struct VG_Sprite *sprt;  /* sprite */
  } u;
};

/* internal structs */
struct vgi_input;
struct vgi_audio;
struct vgi_mlang;
struct vgi_nw;
struct vgi_misc;
struct vgi_instance;
struct vgi_objlist;
struct vgi_collision;
struct vgi_astack;


/* main struct */
struct vg4data {
  char gamename[32];
  char *origlocale;

  struct {  /* environ variables */
    /* VG_IO_LIBRARY: IO-library to load according to directories in src/extlib/iolib/, (e.g. "SDL2") */
    /* VG_RENDERER: renderer to use, (e.g. "software") */
    int no_info;           /* VG_NO_INFO: 1 = print no infos, 0 = print infos (default) */
    int no_warn;           /* VG_NO_WARNING: 1 = print no warnings, 0 = print warnings (default) */
    int film_dump;         /* VG_FILM_DUMP: 1 = dump and play film, 2 = only dump film, (default: 0 = play film) */
    int dump_on_exit;      /* VG_DUMP_ON_EXIT: show dumps on: 1 = stdout, 2 = stderr, when calling VG_dest() */
  } env;

  struct {  /* backbuffer */
    struct VG_Image *img;                      /* backbuffer image */
    struct VG_ImagecopyAttrPixel iattr_pixel;  /* pixel-modifying part of image-copy attributes for backbuffer */
    int wbright;                               /* common brightness for window */
    struct {                                   /* shaking window */
      int axe;                                   /* axe: one from VG_AXES */
      int value;                                 /* shake-value */
    } shake;
  } backbuf;

  struct {  /* loaded io-library (environ variable VG_IO_LIBRARY: "" (default), "SDL2", ...) */
    char tag[16];  /* iolib-tag */
    void *stptr;   /* iolib-specific structure */
    struct {       /* iolib-specific functions */
      /* input */
      VG_BOOL (*input_open)(void);
      void (*input_close)(void);
      void (*input_reopen)(void);
      int (*input_update)(void);
      const char * (*input_code2name)(int);
      int (*input_key_uniqpressed)(int);
      void (*input_mouse_warp)(int, int);
      void (*input_mouse_grabbing)(void);
      void (*input_textbuffer)(VG_BOOL);
      /* window */
      VG_BOOL (*window_open)(int *, int *);
      void (*window_close)(void);
      void (*window_flush)(void);
      /* audio */
      VG_BOOL (*audio_open)(int, VG_BOOL, int);
      VG_BOOL (*audio_is_open)(void);
      void (*audio_close)(void);
      VG_BOOL (*audio_load)(const char *, char **, size_t *);
      void (*audio_lock)(VG_BOOL);
      /* image */
      struct VG_Image * (*image_load)(const char *, char *, size_t);
      VG_BOOL (*image_save)(const struct VG_Image *, const char *, VG_BOOL);
    } f;
  } iolib;

  struct {  /* internal lists and data */
    struct VG_Hash *hash;          /* hash-list */
    struct {                       /* input-data */
      struct vgi_input *s;           /* input struct */
    } input;
    struct {                       /* window-data */
      int wsize;                     /* window size (from VG_WINDOW_SIZES) */
      int scale;                     /* used element of VG_WINDOW_SCALES */
      VG_BOOL size_extended;         /* whether extended window size */
      VG_BOOL scale_nearest;         /* VG_FALSE = linear (default), VG_TRUE = nearest scaling */
      VG_BOOL scale_integer;         /* VG_FALSE = scale using float (default), VG_TRUE = scale using integer */
      struct {                       /* border size */
        VG_BOOL isset;                 /* whether border is set */
        int top, right, bottom, left;  /* border side */
      } border;
    } window;
    struct {                       /* audio-data */
      struct vgi_audio *s;           /* audio struct */
    } audio;
    struct {                       /* image-data */
      struct VG_Image *list;         /* read-write image-list */
      struct VG_Hash *hash;          /* read-only image-lists */
    } image;
    struct {                       /* font-data */
      char userdir[VGI_PATHSIZE];    /* user font directory */
      char dflfont[64];              /* default fontname */
      struct VG_Hash *hash;          /* font-list */
    } font;
    struct {                       /* multilang-data */
      struct vgi_mlang *s;           /* multilang struct */
    } mlang;
    struct {                       /* random-data */
      struct vgi_random *s;          /* random struct */
    } random;
    struct {                       /* sprite-data */
      struct VG_Sprite *list;        /* sprite-list */
    } sprite;
    struct {                       /* network-data */
      unsigned int nw_seed;          /* network-seed, or 0 = no connection */
      struct vgi_nw *s;              /* network struct */
    } nw;
    struct {                       /* misc-data */
      struct vgi_misc *s;            /* misc struct */
    } misc;
    struct {                       /* canvas-data */
      struct VG_Canvas *list;        /* canvas-list */
      struct {                       /* mouse pointer images */
        VG_BOOL point_centered;        /* whether mouse point is centered, else it is upper left */
        struct vgi_imgcnt img_dfl;     /* default image, or NULL = don't show mouse */
        struct vgi_imgcnt img_act;     /* activated image, or NULL = default image */
      } mouse;
    } canvas;
    struct {                       /* dialog-data */
      int dummy;                     /* just dummy for struct */
    } dialog;
    struct {                       /* object-data */
      struct vgi_instance *i;        /* instance data */
      struct vgi_objlist *list;      /* object-list */
      struct SML3_hash *hmgmt;       /* object-management-list: <object-ID> = <object-management> */
      struct SML3_hash *hcoll;       /* collision-fn-list: <object-ID 1> + <object-ID 2> = <collision-function> */
    } object;
    struct {                       /* collision-data */
      struct vgi_collision *list;    /* object-list */
    } collision;
    struct {                       /* film-data */
      int dummy;                     /* just dummy for struct */
    } film;
    struct {                       /* actionstack-data */
      struct vgi_astack *stack;      /* actionstack */
      void (*freefn)(unsigned int, void *);   /* free-function for element-data */
    } actionstack;
    struct {                       /* nodelink-data */
      struct VG_Nodelink *list;      /* nodelink-list */
    } nodelink;
  } lists;

  struct vg4 vg4;  /* main-struct for functions */
};

extern struct vg4data vg4data;


/* vgi.c */
#define outerr(...)  out_error(__FILE__, SML3_funcname, __LINE__, __VA_ARGS__)
extern void out_error(const char *, const char *, int, ...);
extern void pinfo(const char *, ...);
extern void pwarn(const char *, ...);

/* intern.c */
extern const char * vg4_get_prefix(int *);
extern void vg4_intern_skip_ws(const char **, const char *);
extern void vg4_intern_skip_sp(const char **, const char *);
extern struct VG_Hash * vg4_intern_parser_keyval(const char *, size_t, char **);
extern VG_BOOL vg4_intern_recurs_dir(const char *, VG_BOOL (*)(const char *, void *), void *);
extern struct VG_Image * vg4_intern_get_img_from_imgcnt(struct vgi_imgcnt *, struct VG_ImagecopyAttr *);
extern const char * vg4_intern_get_name_from_imgcnt(struct vgi_imgcnt *);
extern void vg4_intern_free_imgcnt(struct vgi_imgcnt *);
extern struct VG_Rect vg4_intern_read_rect(const char *);
extern void vg4_intern_str_with_var(struct SML3_gummi *, const char *, struct VG_Hash *, const char *);
extern void vg4_intern_fpath_with_var(char *, size_t, struct VG_Hash *);
extern struct VG_Image * vg4_intern_ok_cancel_img(struct VG_Position *, int);

/* hash/ */
extern void init_hash(void);
extern void dest_hash(void);
extern struct VG_Hash * vg4_hash_create_nolist(void);
extern struct VG_Hash * vg4_hash_clone_nolist(struct VG_Hash *);

/* input/ */
extern void init_input(void);
extern void dest_input(void);
extern int vg4_input_nw_keyref(int);
extern void vg4_input_nw_getkeys(unsigned char *, int);
extern const char * vg4_input_code2name(int);
extern VG_BOOL vg4_input_tbuf_allowed(const char *);

/* window/ */
extern void init_window(void);
extern void dest_window(void);
extern struct VG_Image * vg4_window_clone_nolist(const struct VG_Rect *, const struct VG_ImagecopyAttr *);

/* audio/ */
extern void init_audio(void);
extern void dest_audio(void);
extern int vg4_audio_load_nolist(const char *, int, int);
extern int vg4_audio_clone(int);

/* image/ */
extern void init_image(void);
extern void dest_image(void);
extern struct VG_Image * vg4_image_create_nolist(int, int);
extern struct VG_Image * vg4_image_load_nolist(const char *);
extern struct VG_Image * vg4_image_clone_nolist(const struct VG_Image *, const struct VG_Rect *, const struct VG_ImagecopyAttr *);
extern VG_BOOL vg4_rect_overlap(const struct VG_Position *, struct VG_Rect *, struct VG_Rect *);
extern VG_BOOL vg4_attrpixel_is_default(const struct VG_ImagecopyAttrPixel *);
extern VG_BOOL vg4_attrimage_is_default(const struct VG_ImagecopyAttrImage *);
extern struct VG_Image * vg4_image_loadfile(const char *);
extern struct VG_Image * vg4_image_loadmem(char *, size_t);
extern VG_BOOL vg4_image_savefile(const struct VG_Image *, const char *, VG_BOOL);
extern VG_BOOL vg4_image_tobase64(const struct VG_Image *, VG_BOOL, char **, size_t *);

/* font/ */
extern void init_font(void);
extern void dest_font(void);
extern struct VG_Font * vg4_font_loaddefault(void);
extern void vg4_font_gap_remove(const char *, int, int, VG_BOOL, int *, int);
extern struct vgi_font * vg4_font_loadfile(const char *);
extern VG_BOOL vg4_font_savefile(const struct vgi_font *, const char *);
extern struct VG_Image * vg4_font_loadtext_nolist(const char *, const char *, struct VG_Hash *, struct VG_Hash **);
extern struct VG_Image * vg4_font_totext_nolist(const char *, const char *, const char *, struct VG_Hash *, struct VG_Hash **);

/* mlang/ */
extern void init_mlang(void);
extern void dest_mlang(void);

/* random/ */
extern void init_random(void);
extern void dest_random(void);

/* sprite/ */
extern void init_sprite(void);
extern void dest_sprite(void);
extern struct VG_Sprite * vg4_sprite_load_nolist(const char *);

/* nw/ */
extern void init_nw(void);
extern void dest_nw(void);
extern void vg4_nw_sendping(VG_BOOL);

/* misc/ */
extern void init_misc(void);
extern void dest_misc(void);

/* canvas/ */
extern void init_canvas(void);
extern void dest_canvas(void);
struct VG_Canvas * vg4_canvas_load_nolist(const char *, struct VG_Hash *);

/* dialog/ */
extern void init_dialog(void);
extern void dest_dialog(void);

/* object/ */
extern void init_object(void);
extern void dest_object(void);

/* collision/ */
extern void init_collision(void);
extern void dest_collision(void);
extern void vg4_collision_removeid(unsigned int);

/* film/ */
extern void init_film(void);
extern void dest_film(void);

/* actionstack/ */
extern void init_actionstack(void);
extern void dest_actionstack(void);

/* nodelink/ */
extern void init_nodelink(void);
extern void dest_nodelink(void);

#endif /* VGI_H_ */
