/* Copyright 2022-2026 Kurt Nienhaus
 *
 * This file is part of VgaGames.
 * VgaGames is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 2 of the License, or
 * (at your option) any later version.
 * VgaGames is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with VgaGames.  If not, see <http://www.gnu.org/licenses/>.
 */

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

void init_dialog_sysmenu(void);

static VG_BOOL dialog_sysmenu(const char *, const struct VG_Position *, struct VG_Hash *, void *, void (*)(const char *, void *), void (*)(const char *, void *), const char *);


/* set functions */
void
init_dialog_sysmenu(void)
{
  vg4->dialog->sysmenu = dialog_sysmenu;
} /* Ende init_dialog_sysmenu */


/* dialog_sysmenu:
 * open a canvas-dialog for the system-menu
 * which will call appropriate dialog-functions
 * @param cvasdir     directory to load canvas from, or NULL = system-canvas
 * @param posdst      canvas-position on window, or NULL = centered
 * @param hvar        hash with variable-values for text control-commands "var", or NULL
 *                      hash-format:
 *                       - key:   variable name
 *                       - value: variable value
 *                    (see below)
 * @param vdata       2. param for cb_load() and cb_save()
 * @param cb_load     callback-function for loading from file
 *                     - parameters
 *                       1. param: selected file, or NULL = vg4->dialog->file_select() not called
 *                       2. param: vdata (arbitrary data passed to cb_load())
 *                    if NULL: disable load-button
 * @param cb_save     callback-function for saving to file
 *                     - parameters
 *                       1. param: selected file, or NULL = vg4->dialog->file_select() not called
 *                       2. param: vdata (arbitrary data passed to cb_save())
 *                    if NULL: disable save-button
 * @param startdir    topmost directory to start selecting filename from
 *                     - path:                    relative path from current directory
 *                     - beginning with "~":      path beginning from the HOME-directory
 *                     - NULL:                    don't call vg4->dialog->file_select(), just the callback-functions
 * @return  VG_TRUE = OK or VG_FALSE = exit-request
 *
 * The canvas-name must be:
 *  - sysmenu.top.cvas: for showing the system-menu
 *    - with items:
 *      - [CV-TEXT]   with name "title": text for title
 *      - [CV-BUTTON] with name "done": for returning
 *      - [CV-BUTTON] with name "bt-exit": for clicking the exit-button, calling vg4->dialog->exit()
 *      - [CV-BUTTON] with name "bt-volume": for clicking the volume-button, calling vg4->dialog->volume()
 *      - [CV-BUTTON] with name "bt-keydef-kbd": for clicking the keyboard-redefining-button, calling vg4->dialog->keydef() for keyboard
 *      - [CV-BUTTON] with name "bt-keydef-gc": for clicking the gamecontroller-redefining-button, calling vg4->dialog->keydef() for gamecontrollers
 *      - [CV-BUTTON] with name "bt-windowsize": for clicking the windowsize-button, calling vg4->dialog->windowsize()
 *      - [CV-BUTTON] with name "bt-winbright": for clicking the window-brightness-button, calling vg4->dialog->winbright()
 *      - [CV-BUTTON] with name "bt-load": for clicking the load-button, calling vg4->dialog->file_select() and cb_load()
 *      - [CV-BUTTON] with name "bt-save": for clicking the save-button, calling vg4->dialog->file_select() and cb_save()
 *    - uses following variables:
 *      - key: "title", value: <title of canvas>
 *    - hvar should contain:
 *      - key: "top:title", value: <title of canvas>
 *      - keys for dialog-functions with prefix of appropriate dialog-name,
 *        - "exit:"
 *        - "volume:"
 *        - "keydef:"
 *        - "windowsize:"
 *        - "winbright:"
 *        - "load:"
 *        - "save:"
 *        e.g. "keydef:press:title" for vg4->dialog->keydef(), canvas-file keydef.press.cvas
 */
static VG_BOOL
dialog_sysmenu(const char *cvasdir, const struct VG_Position *posdst, struct VG_Hash *hvar,
               void *vdata, void (*cb_load)(const char *, void *), void (*cb_save)(const char *, void *), const char *startdir)
{
  const char *cvprefix = "sysmenu";
  const char *cvfile_top = "sysmenu.top.cvas";
  const char *cvfile_topnofile = "sysmenu.topnofile.cvas";
  const char *cvname_done = "done";
  const char *cvname_bt_exit = "bt-exit";
  const char *cvname_bt_volume = "bt-volume";
  const char *cvname_bt_keydef_kbd = "bt-keydef-kbd";
  const char *cvname_bt_keydef_gc = "bt-keydef-gc";
  const char *cvname_bt_windowsize = "bt-windowsize";
  const char *cvname_bt_winbright = "bt-winbright";
  const char *cvname_bt_load = "bt-load";
  const char *cvname_bt_save = "bt-save";
  struct VG_Hash *hvar_top, *hvar_dialog;
  char cvaspath[512];
  VG_BOOL retw;
  struct VG_Canvas *cvas_top;
  const char *selname;
  struct VG_Position possub;
  struct VG_Image *wclone;
  struct VG_ImagecopyAttrPixel iattr_pixel;

  hvar_top = hvar_dialog = NULL;

  /* don't use absolute path */
  if (startdir != NULL) { startdir += strspn(startdir, "/"); }

  /* set variables and load canvas */

  hvar_dialog = vg4->hash->create();

  /* top-canvas */
  hvar_top = vg4->hash->create();
  dialog_transfer_variables(hvar, hvar_top, "top");
  cvas_top = NULL;
  if (cb_load == NULL && cb_save == NULL) {  /* load canvas without load- and save-button */
    dialog_cvasfile(cvprefix, cvfile_topnofile, cvasdir, cvaspath, sizeof(cvaspath));
    cvas_top = vg4->canvas->load(cvaspath, hvar_top);
  }
  if (cvas_top == NULL) {
    dialog_cvasfile(cvprefix, cvfile_top, cvasdir, cvaspath, sizeof(cvaspath));
    cvas_top = vg4->canvas->load(cvaspath, hvar_top);
  }
  if (cvas_top == NULL) {
    outerr("%s [at cvasdir=%s] not found", cvfile_top, (cvasdir == NULL ? "(null)" : cvasdir));
    return VG_TRUE;
  }

  /* check for disabling buttons */
  if (vg4->input->gclist(NULL) == 0) {
    vg4->canvas->disable(cvas_top, cvname_bt_keydef_gc, VG_TRUE);
  }
  if (vg4->input->keylist(NULL, 0) == 0) {
    vg4->canvas->disable(cvas_top, cvname_bt_keydef_kbd, VG_TRUE);
    vg4->canvas->disable(cvas_top, cvname_bt_keydef_gc, VG_TRUE);
  }
  if (!vg4->audio->is_open()) {
    vg4->canvas->disable(cvas_top, cvname_bt_volume, VG_TRUE);
  }
  if (cb_load == NULL) {
    vg4->canvas->disable(cvas_top, cvname_bt_load, VG_TRUE);
  }
  if (cb_save == NULL) {
    vg4->canvas->disable(cvas_top, cvname_bt_save, VG_TRUE);
  }

  /* prepare background for dialog-function */
  VG_IMAGECOPY_ATTRPIXEL_DEFAULT(&iattr_pixel);
  iattr_pixel.brightness = 60;
  { struct VG_ImagecopyAttr iattr;
    VG_IMAGECOPY_ATTR_DEFAULT(&iattr);
    iattr.pixel = iattr_pixel;
    vg4->window->copy(NULL, NULL, &iattr);
  }
  wclone = vg4->window->clone(NULL, NULL);

  /* loop */

  retw = VG_TRUE;
  for (;;) {
    /* execute top-canvas */
    if (!vg4->canvas->exec(cvas_top, posdst, &selname)) { retw = VG_FALSE; break; }
    if (selname == NULL) { break; }  /* cancel */

    /* act according to selection */

    if (*selname == '\0' || strcmp(selname, cvname_done) == 0) { break; }

    if (strcmp(selname, cvname_bt_exit) == 0) {
      vg4->hash->clear(hvar_dialog);
      dialog_transfer_variables(hvar, hvar_dialog, "exit");
      possub = vg4->canvas->subcanvas(cvas_top, &iattr_pixel);
      if (vg4->dialog->exit(cvasdir, &possub, hvar_dialog)) { retw = VG_FALSE; break; }

    } else if (strcmp(selname, cvname_bt_volume) == 0) {
      vg4->hash->clear(hvar_dialog);
      dialog_transfer_variables(hvar, hvar_dialog, "volume");
      possub = vg4->canvas->subcanvas(cvas_top, &iattr_pixel);
      if (!vg4->dialog->volume(cvasdir, &possub, hvar_dialog)) { retw = VG_FALSE; break; }

    } else if (strcmp(selname, cvname_bt_keydef_kbd) == 0) {
      vg4->hash->clear(hvar_dialog);
      dialog_transfer_variables(hvar, hvar_dialog, "keydef");
      possub = vg4->canvas->subcanvas(cvas_top, &iattr_pixel);
      if (!vg4->dialog->keydef(cvasdir, &possub, hvar_dialog, 0)) { retw = VG_FALSE; break; }

    } else if (strcmp(selname, cvname_bt_keydef_gc) == 0) {
      vg4->hash->clear(hvar_dialog);
      dialog_transfer_variables(hvar, hvar_dialog, "keydef");
      possub = vg4->canvas->subcanvas(cvas_top, &iattr_pixel);
      if (!vg4->dialog->keydef(cvasdir, &possub, hvar_dialog, -1)) { retw = VG_FALSE; break; }

    } else if (strcmp(selname, cvname_bt_windowsize) == 0) {
      vg4->hash->clear(hvar_dialog);
      dialog_transfer_variables(hvar, hvar_dialog, "windowsize");
      possub = vg4->canvas->subcanvas(cvas_top, &iattr_pixel);
      if (!vg4->dialog->windowsize(cvasdir, &possub, hvar_dialog)) { retw = VG_FALSE; break; }

    } else if (strcmp(selname, cvname_bt_winbright) == 0) {
      vg4->hash->clear(hvar_dialog);
      dialog_transfer_variables(hvar, hvar_dialog, "winbright");
      possub = vg4->canvas->subcanvas(cvas_top, &iattr_pixel);
      if (!vg4->dialog->winbright(cvasdir, &possub, hvar_dialog)) { retw = VG_FALSE; break; }

    } else if (cb_load != NULL && strcmp(selname, cvname_bt_load) == 0) {
      char fname[512];
      vg4->hash->clear(hvar_dialog);
      dialog_transfer_variables(hvar, hvar_dialog, "load");
      possub = vg4->canvas->subcanvas(cvas_top, &iattr_pixel);
      if (startdir != NULL) {
        if (!vg4->dialog->file_select(fname, sizeof(fname), cvasdir, &possub, hvar_dialog, startdir, VG_FALSE, VG_FALSE)) {
          retw = VG_FALSE;
          break;
        }
        if (*fname != '\0') { cb_load(fname, vdata); }
      } else {
        cb_load(NULL, vdata);
      }

    } else if (cb_save != NULL && strcmp(selname, cvname_bt_save) == 0) {
      char fname[512];
      vg4->hash->clear(hvar_dialog);
      dialog_transfer_variables(hvar, hvar_dialog, "save");
      possub = vg4->canvas->subcanvas(cvas_top, &iattr_pixel);
      if (startdir != NULL) {
        if (!vg4->dialog->file_select(fname, sizeof(fname), cvasdir, &possub, hvar_dialog, startdir, VG_TRUE, VG_FALSE)) {
          retw = VG_FALSE;
          break;
        }
        if (*fname != '\0') { cb_save(fname, vdata); }
      } else {
        cb_save(NULL, vdata);
      }
    }

    /* restore background */
    vg4->window->clear();
    vg4->window->copy(wclone, NULL, NULL);
  }

  /* restore background */
  vg4->window->clear();
  vg4->window->copy(wclone, NULL, NULL);

  vg4->image->destroy(wclone);
  vg4->canvas->destroy(cvas_top);
  if (hvar_dialog != NULL) { vg4->hash->destroy(hvar_dialog); }
  if (hvar_top != NULL) { vg4->hash->destroy(hvar_top); }

  return retw;
} /* Ende dialog_sysmenu */
