/* canvas-type unique key
 *   [CV-UNIQKEY]
 *   name: <arbitrary unique name>
 *   position-itag: (position): <box-tag of an element in the main text>
 *   position-rect: (position): <rectangle (<x>+<w>,<y>+<h>) within the box-tag or the main text>
 *   disable: <whether is disabled: 1 = yes, 0 = no, or missing = enabled>
 *   font: <fontname, (default: default font)>
 *   fgcolor: <text color (0xRRGGBB) for key-name, (default: white)>
 *   bgcolor: <background color: hex number (0xRRGGBB) or "transparent", (default: transparent)>
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#include "canvas.h"

static int type_no = 0;

struct cv_type {
  int gcid;             /* 0 = keyboard or >0 = gamecontroller-ID */
  int keycode;          /* key-code (VG_INPUT_NOKEY or one of VG_INPUT_KBDCODES/VG_INPUT_GCBUTTONS/VG_INPUT_GCAXES) */
  const char *keyname;  /* key-name */
  char *font;           /* font of key-name */
  char fgcolor[32];     /* color of key-name */
  char bgcolor[32];     /* background color of key-name */
};

void cvinit_uniqkey(struct vgi_canvas_inittype *, int);

static void * t_read_section(const struct VG_Canvas *, struct vgi_canvas_item *, const char *);
static void t_draw(struct vgi_canvas_data *, struct vgi_canvas_item *, const char **);
static void t_destroy(struct vgi_canvas_item *);
static void t_dump(FILE *, struct vgi_canvas_item *);

static void canvas_uniqkey_set(struct VG_Canvas *, const char *, int, int);
static int canvas_uniqkey_get(struct VG_Canvas *, const char *);


void
cvinit_uniqkey(struct vgi_canvas_inittype *cvinittype, int type)
{
  if (cvinittype == NULL) { return; }

  type_no = type;

  /* cvinit */
  cvinittype->mouse_opaque = VG_TRUE;
  cvinittype->uses_cursor = VG_FALSE;
  cvinittype->read_section = t_read_section;
  cvinittype->get_itag_rect = NULL;
  cvinittype->warp_mouse = NULL;
  cvinittype->pre_exec = NULL;
  cvinittype->draw = t_draw;
  cvinittype->destroy = t_destroy;
  cvinittype->dump = t_dump;

  /* functions */
  vg4->canvas->uniqkey_set = canvas_uniqkey_set;
  vg4->canvas->uniqkey_get = canvas_uniqkey_get;
} /* Ende cvinit_uniqkey */


static void *
t_read_section(const struct VG_Canvas *cvas, struct vgi_canvas_item *cvitem, const char *dtptr)
{
  struct SML3_gummi gm1 = SML3_GUM_INITIALIZER;
  struct cv_type *cvtype;
  char bval[256], *pval;

  if (cvas == NULL || cvitem == NULL || dtptr == NULL) { return NULL; }

  cvtype = SML3_calloc(1, sizeof(*cvtype));

  if (canvas_get_lineval(dtptr, "font", NULL, 0, NULL, 0, bval, sizeof(bval), NULL)) {
    vg4_intern_str_with_var(&gm1, bval, cvas->cve.hvar, NULL); pval = SML3_gumgetval(&gm1);
    cvtype->font = SML3_strdup(pval);
  }

  if (canvas_get_lineval(dtptr, "fgcolor", NULL, 0, NULL, 0, bval, sizeof(bval), NULL)) {
    vg4_intern_str_with_var(&gm1, bval, cvas->cve.hvar, NULL); pval = SML3_gumgetval(&gm1);
    vg4->misc->strcpy(cvtype->fgcolor, sizeof(cvtype->fgcolor), pval);
  }

  if (canvas_get_lineval(dtptr, "bgcolor", NULL, 0, NULL, 0, bval, sizeof(bval), NULL)) {
    vg4_intern_str_with_var(&gm1, bval, cvas->cve.hvar, NULL); pval = SML3_gumgetval(&gm1);
    vg4->misc->strcpy(cvtype->bgcolor, sizeof(cvtype->bgcolor), pval);
  }

  cvtype->gcid = -1;
  cvtype->keycode = VG_INPUT_NOKEY;
  cvtype->keyname = "";

  SML3_gumdest(&gm1);

  return cvtype;
} /* Ende t_read_section */


static void
t_draw(struct vgi_canvas_data *cvdata, struct vgi_canvas_item *cvitem, const char **selname)
{
  struct cv_type *cvtype;

  if (cvdata == NULL || cvdata->cvas == NULL || cvitem == NULL || selname == NULL) { return; }
  if (cvitem->rimg == NULL) { return; }
  cvtype = (struct cv_type *)cvitem->vstrct;
  if (cvtype == NULL) { return; }

  /* draw */
  { struct VG_Image *imgp;
    struct VG_ImagecopyAttr iattr;
    struct VG_Position posb;

    imgp = NULL;
    VG_IMAGECOPY_ATTR_DEFAULT(&iattr);

    if (*cvtype->keyname != '\0') {  /* key-name available */
      struct SML3_gummi gm1 = SML3_GUM_INITIALIZER;
      int gmpos;
      gmpos = (int)SML3_gumcpy(&gm1, 0, "[");
      gmpos += SML3_gumprintf(&gm1, gmpos, "orientation=center boxwidth=%d", cvitem->rect.w);
      if (cvtype->font != NULL) {
        gmpos += SML3_gumprintf(&gm1, gmpos, " font=%s", cvtype->font);
      }
      if (*cvtype->fgcolor != '\0') {
        gmpos += SML3_gumprintf(&gm1, gmpos, " fgcolor=%s", cvtype->fgcolor);
      }
      if (*cvtype->bgcolor != '\0') {
        gmpos += SML3_gumprintf(&gm1, gmpos, " bgcolor=%s", cvtype->bgcolor);
      }
      gmpos += (int)SML3_gumcpy(&gm1, gmpos, "]");
      { char afont[64];
        vg4->font->getdefault(afont, sizeof(afont));
        if (*cvdata->cvas->cve.dflfont != '\0') { vg4->font->setdefault(cvdata->cvas->cve.dflfont); }
        imgp = vg4_font_totext_nolist(cvtype->keyname, SML3_gumgetval(&gm1), cvdata->cvas->cve.dirname, NULL, NULL);
        vg4->font->setdefault(afont);
      }
      SML3_gumdest(&gm1);
    }

    if (cvdata->hasfocus && !VGI_CVKEY_NEWPRESSED(cvdata->keys.k[CV_KEY_ESCAPE])) {  /* has focus */
      int keycode;
      const char *keyname;
      keycode = vg4->input->key_uniqpressed(cvtype->gcid, &keyname);
      if (keycode == VG_INPUT_KBDCODE_RETURN && !VGI_CVKEY_NEWPRESSED(cvdata->keys.k[CV_KEY_RETURN])) { keycode = VG_INPUT_NOKEY; }
      if (keycode != VG_INPUT_NOKEY) {
        cvtype->keycode = keycode;
        cvtype->keyname = keyname;
        *selname = cvitem->name;
      }
    } else if (cvitem->isdisabled) {  /* disabled */
      iattr.pixel.pixelcolor = VG_PIXELCOLOR_GREY;
      iattr.pixel.brightness = iattr.pixel.brightness * 4 / 5;
    }

    /* draw out */
    vg4->image->clear(cvitem->rimg);
    if (imgp != NULL) {
      int h1;
      vg4->image->getsize(imgp, NULL, NULL, &h1);
      posb.pos = VG_POS_UPPER_LEFT;
      posb.x = 0;
      posb.y = (cvitem->rect.h - h1) / 2;
      vg4->image->copy(cvitem->rimg, imgp, &posb, &iattr);
      vg4->image->destroy(imgp);
    }
    if (cvdata->hasfocus) {  /* has focus */
      canvas_draw_actborder(&cvitem->rect, cvdata->xadd, cvdata->yadd);
    }

    posb.pos = VG_POS_UPPER_LEFT;
    posb.x = cvdata->xadd + cvitem->rect.x;
    posb.y = cvdata->yadd + cvitem->rect.y;
    vg4->window->copy(cvitem->rimg, &posb, NULL);
  }
} /* Ende t_draw */


static void
t_destroy(struct vgi_canvas_item *cvitem)
{
  struct cv_type *cvtype;

  if (cvitem == NULL) { return; }
  cvtype = (struct cv_type *)cvitem->vstrct;
  if (cvtype == NULL) { return; }

  if (cvtype->font != NULL) { free(cvtype->font); }

  free(cvtype);
} /* Ende t_destroy */


static void
t_dump(FILE *outfp, struct vgi_canvas_item *cvitem)
{
  struct cv_type *cvtype;
  const char *namptr;

  if (outfp == NULL || cvitem == NULL) { return; }
  cvtype = (struct cv_type *)cvitem->vstrct;
  if (cvtype == NULL) { return; }

  fprintf(outfp, "    type=unique-key-pressing\n");
  fprintf(outfp, "    gcid=%d\n", cvtype->gcid);
  fprintf(outfp, "    keycode=%d\n", cvtype->keycode);
  fprintf(outfp, "    keyname=%s\n", cvtype->keyname);
  namptr = cvtype->font;
  fprintf(outfp, "    font=%s\n", (namptr == NULL ? "" : namptr));
  fprintf(outfp, "    fgcolor=%s\n", cvtype->fgcolor);
  fprintf(outfp, "    bgcolor=%s\n", cvtype->bgcolor);
} /* Ende t_dump */


/* canvas_uniqkey_set:
 * set gamecontroller-ID and key-code of a unique-key-pressing
 * @param cvas     canvas
 * @param iname    name of unique-key-pressing
 * @param gcid     0 = keyboard or >0 = gamecontroller-ID
 * @param keycode  key-code (VG_INPUT_NOKEY or one of VG_INPUT_KBDCODES/VG_INPUT_GCBUTTONS/VG_INPUT_GCAXES)
 */
static void
canvas_uniqkey_set(struct VG_Canvas *cvas, const char *iname, int gcid, int keycode)
{
  struct vgi_canvas_item *cvitem;
  struct cv_type *cvtype;

  if (cvas == NULL || iname == NULL || *iname == '\0') { return; }
  if (gcid < 0 || gcid > vg4->input->gclist(NULL)) { return; }

  cvitem = cvtype_get_item(cvas, iname, type_no);
  if (cvitem == NULL) { return; }
  cvtype = (struct cv_type *)cvitem->vstrct;
  if (cvtype == NULL) { return; }

  cvtype->gcid = gcid;
  cvtype->keycode = keycode;
  cvtype->keyname = vg4_input_code2name(keycode);
} /* Ende canvas_uniqkey_set */


/* canvas_uniqkey_get:
 * get key-code of a unique-key-pressing
 * @param cvas     canvas
 * @param iname    name of unique-key-pressing
 * @return  key-code (VG_INPUT_NOKEY or one of VG_INPUT_KBDCODES/VG_INPUT_GCBUTTONS/VG_INPUT_GCAXES)
 */
static int
canvas_uniqkey_get(struct VG_Canvas *cvas, const char *iname)
{
  struct vgi_canvas_item *cvitem;
  struct cv_type *cvtype;

  if (cvas == NULL || iname == NULL || *iname == '\0') { return VG_INPUT_NOKEY; }

  cvitem = cvtype_get_item(cvas, iname, type_no);
  if (cvitem == NULL) { return VG_INPUT_NOKEY; }
  cvtype = (struct cv_type *)cvitem->vstrct;
  if (cvtype == NULL) { return VG_INPUT_NOKEY; }

  return cvtype->keycode;
} /* Ende canvas_uniqkey_get */
