/* canvas-type switch
 *   [CV-SWITCH]
 *   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>
 *   is-on: <whether switch is ON: 1 = yes, 0 = no, or missing = OFF>
 *   img-on-dfl: (default image for ON):     [img:]<image file> or txt:<text file> or sprt:<sprite file> or missing
 *   img-on-act: (activated image for ON):   [img:]<image file> or txt:<text file> or sprt:<sprite file> or missing = img-on-dfl
 *   img-off-dfl: (default image for OFF):   [img:]<image file> or txt:<text file> or sprt:<sprite file> or missing
 *   img-off-act: (activated image for OFF): [img:]<image file> or txt:<text file> or sprt:<sprite file> or missing = img-off-dfl
 *   orientation: <left|center|right>
 *   v-orientation: <top|center|bottom>
 */

#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 {
  VG_BOOL is_on;                  /* whether switch is ON */
  int orientation;                /* one of VG_ORIENTATIONS */
  int v_orientation;              /* one of VG_ORIENTATIONS */
  struct vgi_imgcnt img_on_dfl;   /* ON: default image, or NULL */
  struct vgi_imgcnt img_on_act;   /* ON: activated image, or NULL = default image */
  struct vgi_imgcnt img_off_dfl;  /* OFF: default image, or NULL */
  struct vgi_imgcnt img_off_act;  /* OFF: activated image, or NULL = default image */
};

void cvinit_switch(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_switch_set(struct VG_Canvas *, const char *, VG_BOOL);
static VG_BOOL canvas_switch_get(struct VG_Canvas *, const char *);


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

  type_no = type;

  /* cvinit */
  cvinittype->mouse_opaque = VG_FALSE;
  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->switch_set = canvas_switch_set;
  vg4->canvas->switch_get = canvas_switch_get;
} /* Ende cvinit_switch */


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 bprefix[32], bval[256], *pval;

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

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

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

  if (canvas_get_lineval(dtptr, "img-on-dfl", NULL, 0, bprefix, sizeof(bprefix), bval, sizeof(bval), NULL)) {
    canvas_load_image(cvas, bprefix, bval, &cvtype->img_on_dfl);
  }

  if (canvas_get_lineval(dtptr, "img-on-act", NULL, 0, bprefix, sizeof(bprefix), bval, sizeof(bval), NULL)) {
    canvas_load_image(cvas, bprefix, bval, &cvtype->img_on_act);
  }

  if (canvas_get_lineval(dtptr, "img-off-dfl", NULL, 0, bprefix, sizeof(bprefix), bval, sizeof(bval), NULL)) {
    canvas_load_image(cvas, bprefix, bval, &cvtype->img_off_dfl);
  }

  if (canvas_get_lineval(dtptr, "img-off-act", NULL, 0, bprefix, sizeof(bprefix), bval, sizeof(bval), NULL)) {
    canvas_load_image(cvas, bprefix, bval, &cvtype->img_off_act);
  }

  if (canvas_get_lineval(dtptr, "orientation", NULL, 0, NULL, 0, bval, sizeof(bval), NULL)) {
    vg4_intern_str_with_var(&gm1, bval, cvas->cve.hvar, NULL); pval = SML3_gumgetval(&gm1);
    if (strcmp(pval, "left") == 0) {
      cvtype->orientation = VG_ORI_LEFT;
    } else if (strcmp(pval, "center") == 0) {
      cvtype->orientation = VG_ORI_CENTER;
    } else if (strcmp(pval, "right") == 0) {
      cvtype->orientation = VG_ORI_RIGHT;
    } else {
      cvtype->orientation = VG_ORI_CENTER;
    }
  }

  if (canvas_get_lineval(dtptr, "v-orientation", NULL, 0, NULL, 0, bval, sizeof(bval), NULL)) {
    vg4_intern_str_with_var(&gm1, bval, cvas->cve.hvar, NULL); pval = SML3_gumgetval(&gm1);
    if (strcmp(pval, "top") == 0) {
      cvtype->v_orientation = VG_ORI_LEFT;
    } else if (strcmp(pval, "center") == 0) {
      cvtype->v_orientation = VG_ORI_CENTER;
    } else if (strcmp(pval, "bottom") == 0) {
      cvtype->v_orientation = VG_ORI_RIGHT;
    } else {
      cvtype->v_orientation = VG_ORI_CENTER;
    }
  }

  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;
    VG_BOOL drawborder;

    imgp = NULL;
    drawborder = VG_FALSE;

    if (cvdata->hasfocus) {  /* has focus */
      if (VGI_CVKEY_NEWPRESSED(cvdata->keys.k[CV_KEY_RETURN]) || VGI_CVKEY_NEWPRESSED(cvdata->keys.m_left)) {
        cvtype->is_on = !cvtype->is_on;
        *selname = cvitem->name;
      }
      if (cvtype->is_on) {
        imgp = vg4_intern_get_img_from_imgcnt(&cvtype->img_on_act, &iattr);
      } else {
        imgp = vg4_intern_get_img_from_imgcnt(&cvtype->img_off_act, &iattr);
      }
    }

    if (imgp == NULL) {  /* default */
      if (cvtype->is_on) {
        imgp = vg4_intern_get_img_from_imgcnt(&cvtype->img_on_dfl, &iattr);
      } else {
        imgp = vg4_intern_get_img_from_imgcnt(&cvtype->img_off_dfl, &iattr);
      }
      if (cvitem->isdisabled) {  /* disabled */
        iattr.pixel.pixelcolor = VG_PIXELCOLOR_GREY;
        iattr.pixel.brightness = iattr.pixel.brightness * 4 / 5;
      } else {
        drawborder = VG_TRUE;
      }
    }

    /* draw out */
    if (imgp != NULL) {
      vg4->image->clear(cvitem->rimg);
      posb = canvas_set_posi(&cvitem->rect, imgp, NULL, cvtype->orientation, cvtype->v_orientation);
      vg4->image->copy(cvitem->rimg, imgp, &posb, &iattr);
      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);
      if (cvdata->hasfocus && drawborder) {
        canvas_draw_actborder(&cvitem->rect, cvdata->xadd, cvdata->yadd);
      }
    }
  }
} /* 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; }

  vg4_intern_free_imgcnt(&cvtype->img_on_dfl);
  vg4_intern_free_imgcnt(&cvtype->img_on_act);
  vg4_intern_free_imgcnt(&cvtype->img_off_dfl);
  vg4_intern_free_imgcnt(&cvtype->img_off_act);

  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=switch\n");
  fprintf(outfp, "    is-on=%s\n", (cvtype->is_on ? "yes" : "no"));
  namptr = vg4_intern_get_name_from_imgcnt(&cvtype->img_on_dfl);
  fprintf(outfp, "    img-on-dfl=%s\n", namptr);
  namptr = vg4_intern_get_name_from_imgcnt(&cvtype->img_on_act);
  fprintf(outfp, "    img-on-act=%s\n", namptr);
  namptr = vg4_intern_get_name_from_imgcnt(&cvtype->img_off_dfl);
  fprintf(outfp, "    img-off-dfl=%s\n", namptr);
  namptr = vg4_intern_get_name_from_imgcnt(&cvtype->img_off_act);
  fprintf(outfp, "    img-off-act=%s\n", namptr);
} /* Ende t_dump */


/* canvas_switch_set:
 * set switch-item to on or off
 * @param cvas   canvas
 * @param iname  name of switch-item
 * @param onoff  VG_TRUE = set on, VG_FALSE = set off
 */
static void
canvas_switch_set(struct VG_Canvas *cvas, const char *iname, VG_BOOL onoff)
{
  struct vgi_canvas_item *cvitem;
  struct cv_type *cvtype;

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

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

  cvtype->is_on = onoff;
} /* Ende canvas_switch_set */


/* canvas_switch_get:
 * get whether switch-item is on or off
 * @param cvas     canvas
 * @param iname    name of switch-item
 * @return  VG_TRUE = is on, VG_FALSE = is off
 */
static VG_BOOL
canvas_switch_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_FALSE; }

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

  return cvtype->is_on;
} /* Ende canvas_switch_get */
