#ifndef CANVAS_H_
#define CANVAS_H_

#include "vgi.h"

#define VGI_CANVAS_NAMESIZE  32
#define VGI_CANVAS_TAGSIZE   32
#define VGI_CANVAS_REPWMAX   6

#define CV_WAIT_TIME 50

#define IS_RECT_EMPTY(PRECT)  ((PRECT)->w <= 0 || ((PRECT)->h <= 0))
#define CLEAR_RECT(PRECT)     ((PRECT)->x = (PRECT)->w = (PRECT)->y = (PRECT)->h = 0)
#define IS_IN_RECT(PRECT, XPOS, YPOS, XADD, YADD) \
  (!IS_RECT_EMPTY(PRECT) \
  && (XPOS) >= (XADD) + (PRECT)->x \
  && (XPOS) < (XADD) + (PRECT)->x + (PRECT)->w \
  && (YPOS) >= (YADD) + (PRECT)->y \
  && (YPOS) < (YADD) + (PRECT)->y + (PRECT)->h)

#define DETECT_BOOLEAN(PSTRING, PBOOL) \
  do { \
    if (strcmp((PSTRING), "no") == 0 || strcmp((PSTRING), "off") == 0 || strcmp((PSTRING), "0") == 0) { \
      (PBOOL) = VG_FALSE; \
    } else if (strcmp((PSTRING), "yes") == 0 || strcmp((PSTRING), "on") == 0 || strcmp((PSTRING), "1") == 0) { \
      (PBOOL) = VG_TRUE; \
    } \
  } while (0)


/* variables for a canvas-item */
struct vgi_canvas_item {
  char name[VGI_CANVAS_NAMESIZE];  /* name */
  char itag[VGI_CANVAS_TAGSIZE];   /* image-tag, or empty = image of main text */
  struct VG_Rect limrect;          /* limitating position within main text */
  struct VG_Rect rect;             /* absolute position within main text */
  struct VG_Image *rimg;           /* image with rect-size */
  VG_BOOL isdisabled;              /* whether is disabled */
  VG_BOOL isselectable;            /* whether is selectable */
  int type;                        /* canvas-type: one of CANVAS_TYPE_* */
  void *vstrct;                    /* private struct of canvas-type */
};

/* keys */
enum { CV_KEY_LSHIFT = 0,
       CV_KEY_RSHIFT,
       CV_KEY_TAB,
       CV_KEY_LEFT,
       CV_KEY_UP,
       CV_KEY_PGUP,
       CV_KEY_HOME,
       CV_KEY_RIGHT,
       CV_KEY_DOWN,
       CV_KEY_PGDOWN,
       CV_KEY_END,
       CV_KEY_SPACE,
       CV_KEY_RETURN,
       CV_KEY_ESCAPE,
       CV_KEY_MAXENUM  /* last entry */
};

/* key-values */
enum { CVKEY_IS_NONE = 0,
       CVKEY_IS_NEWPRESSED,
       CVKEY_IS_PRESSED,
       CVKEY_IS_RELEASED
};

/* for checking key-values */
#define VGI_CVKEY_NONE(KEY)        ((KEY) == CVKEY_IS_NONE)
#define VGI_CVKEY_NEWPRESSED(KEY)  ((KEY) == CVKEY_IS_NEWPRESSED)
#define VGI_CVKEY_PRESSED(KEY)     ((KEY) == CVKEY_IS_NEWPRESSED || (KEY) == CVKEY_IS_PRESSED)
#define VGI_CVKEY_RELEASED(KEY)    ((KEY) == CVKEY_IS_RELEASED)

/* struct for drawing a canvas-item */
struct vgi_canvas_data {
  struct VG_Canvas *cvas;
  int xadd, yadd;
  VG_BOOL hasfocus;
  struct {
    int k[CV_KEY_MAXENUM];  /* keyboard:    k[CV_KEY_*] = CVKEY_IS_* */
    int m_left;             /* mouse-left:  m_left = CVKEY_IS_* */
  } keys;
};

/* individual functions for each canvas-item */
struct vgi_canvas_init {
  struct vgi_canvas_inittype {
    VG_BOOL mouse_opaque;  /* whether mouse shall be rather opaque */
    VG_BOOL uses_cursor;   /* whether cursor-keys are used in canvas-item */
    void * (*read_section)(const struct VG_Canvas *, struct vgi_canvas_item *, const char *);
    struct VG_Rect * (*get_itag_rect)(struct vgi_canvas_item *, const char *);
    void (*warp_mouse)(struct VG_Canvas *, struct vgi_canvas_item *, int, int, int *, int *);
    void (*pre_exec)(struct VG_Canvas *, struct vgi_canvas_item *);
    void (*draw)(struct vgi_canvas_data *, struct vgi_canvas_item *, const char **);
    void (*destroy)(struct vgi_canvas_item *);
    void (*dump)(FILE *, struct vgi_canvas_item *);
  } *type;
};
extern struct vgi_canvas_init cvinit;

/* arrow-images for one direction */
struct vgi_canvas_img {
  struct VG_Image *img_dfl;  /* pointer to default arrow-image */
  struct VG_Image *img_act;  /* pointer to activated arrow-image */
  struct VG_Image *img_sel;  /* pointer to selected arrow-image */
  struct VG_Image *img_end;  /* pointer to arrowend-image */
};

struct vgi_canvas_arrow {  /* for one direction */
  struct vgi_canvas_img *img;  /* images */
  int scrollcount;             /* counter for mouse-scrolling */
  struct VG_Rect rect;         /* rectangle for image */
};

struct vgi_canvas_dirs {  /* for each direction */
  struct vgi_canvas_img up;     /* images for up-arrow */
  struct vgi_canvas_img down;   /* images for down-arrow */
  struct vgi_canvas_img left;   /* images for left-arrow */
  struct vgi_canvas_img right;  /* images for right-arrow */
};

/* canvas struct */
struct vgi_canvas {
  char *fname;                          /* filename */
  char dirname[VGI_PATHSIZE];           /* correction of path for files to load */
  VG_BOOL intolist;                     /* whether insert into list when reloading */
  VG_BOOL ishigh;                       /* whether is designed for VG_WINDOW_SIZE_HIGH */

  int audc_hover;                       /* audio descriptor for hover */

  struct VG_Hash *hvar;                 /* variables: key=<variable name>, value=<variable value> */

  struct {                              /* arrow-images */
    VG_BOOL user_set;                     /* whether user-defined is set */
    struct vgi_canvas_dirs low;           /* for low window-size */
    struct vgi_canvas_dirs high;          /* for high window-size */
    struct vgi_canvas_dirs user;          /* user-defined */
  } arrow;

  struct VG_Image *w_img;               /* last drawn window-image */
  int midx, midy;                       /* center of canvas-image */

  char aname[VGI_CANVAS_NAMESIZE];      /* name to activate, or empty */

  struct {                              /* main text */
    struct VG_Image *img;                 /* image of main text */
    struct VG_Hash *htags;                /* tags of main text: key=<name>, value=<rectangle> */
  } main;

  struct {                              /* sprites */
    int max;                              /* number of sprites */
    struct {                              /* elements */
      char itag[VGI_CANVAS_TAGSIZE];        /* image-tag, or empty = image of main text */
      struct VG_Rect limrect;               /* limitating position within main text or text-box */
      struct VG_Rect rect;                  /* absolute position within main text or text-box */
      struct VG_Image *rimg;                /* created image with size of rect */
      struct VG_Sprite *sprt;               /* sprite */
      char textbox[VGI_CANVAS_NAMESIZE];    /* item-name of text-box or empty = main text */
    } *e;
  } sprites;

  struct {                              /* mouse pointer images */
    VG_BOOL show;                         /* whether show mouse */
    VG_BOOL point_centered;               /* whether mouse point is centered, else it is upper left */
    int xm, ym, counter;                  /* for reducing mouse opaquness if not moved */
    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;

  char dflfont[64];                     /* default font */

  struct {                              /* canvas-item list */
    int max;                              /* number of canvas-items */
    struct vgi_canvas_item *e;            /* canvas-items */
  } canvas;
};

struct VG_Canvas {
  struct VG_Canvas *prev, *next;
  struct vgi_canvas cve;
};

/* cvtypes.c */
extern struct vgi_canvas_item * cvtype_get_item(const struct VG_Canvas *, const char *, int);
extern struct VG_Rect * cvtypes_get_itag_rect(struct vgi_canvas_init *, const struct VG_Canvas *, const char *, const char *);

/* misc.c */
extern void canvas_calc_rect(const struct VG_Canvas *, int, VG_BOOL);
extern VG_BOOL canvas_get_lineval(const char *, const char *, char *, size_t, char *, size_t, char *, size_t, char **);
extern VG_BOOL canvas_load_image(const struct VG_Canvas *, const char *, const char *, struct vgi_imgcnt *);
extern void canvas_draw_actborder(struct VG_Rect *, int, int);
extern struct VG_Position canvas_set_posi(struct VG_Rect *, struct VG_Image *, struct VG_ImagecopyAttrImage *, int, int);
extern void canvas_draw_arrow(const struct VG_Canvas *, struct vgi_canvas_arrow *, struct vgi_canvas_item *, int, int, int, VG_BOOL, int);

#endif /* CANVAS_H_ */
