/* 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 <dirent.h>
#include <locale.h>
#include "vgi.h"

struct vg4data vg4data;
struct vg4 *vg4;

VG_BOOL VG_init(const char *);
void VG_dest(void);

void out_error(const char *, const char *, int, ...);
void pinfo(const char *, ...);
void pwarn(const char *, ...);


/* VG_init:
 * do initialization
 * @gamename  name of the game,
 *            may contain just latin letters, digits, hyphen and underscore
 * @return  VG_TRUE = OK or VG_FALSE = error
 */
VG_BOOL
VG_init(const char *gamename)
{
  char *envp;

  memset(&vg4data, 0, sizeof(vg4data));
  vg4 = &vg4data.vg4;

  envp = getenv("VG_NO_INFO");
  if (envp != NULL && atoi(envp) > 0) { vg4data.env.no_info = 1; }
  envp = getenv("VG_NO_WARNING");
  if (envp != NULL && atoi(envp) > 0) { vg4data.env.no_warn = 1; }
  envp = getenv("VG_DUMP_ON_EXIT");
  if (envp != NULL && atoi(envp) > 0) { vg4data.env.dump_on_exit = atoi(envp); }
  envp = getenv("VG_FILM_DUMP");
  if (envp != NULL && atoi(envp) > 0) { vg4data.env.film_dump = atoi(envp); }

  /* get locale of LC_CTYPE */
  vg4data.origlocale = setlocale(LC_CTYPE, NULL);
  if (vg4data.origlocale != NULL) { vg4data.origlocale = SML3_strdup(vg4data.origlocale); }

  /* set sub-functions */
  vg4->hash = SML3_calloc(1, sizeof(*vg4->hash));
  vg4->input = SML3_calloc(1, sizeof(*vg4->input));
  vg4->window = SML3_calloc(1, sizeof(*vg4->window));
  vg4->audio = SML3_calloc(1, sizeof(*vg4->audio));
  vg4->image = SML3_calloc(1, sizeof(*vg4->image));
  vg4->font = SML3_calloc(1, sizeof(*vg4->font));
  vg4->mlang = SML3_calloc(1, sizeof(*vg4->mlang));
  vg4->random = SML3_calloc(1, sizeof(*vg4->random));
  vg4->sprite = SML3_calloc(1, sizeof(*vg4->sprite));
  vg4->nw = SML3_calloc(1, sizeof(*vg4->nw));
  vg4->misc = SML3_calloc(1, sizeof(*vg4->misc));
  vg4->canvas = SML3_calloc(1, sizeof(*vg4->canvas));
  vg4->dialog = SML3_calloc(1, sizeof(*vg4->dialog));
  vg4->object = SML3_calloc(1, sizeof(*vg4->object));
  vg4->collision = SML3_calloc(1, sizeof(*vg4->collision));
  vg4->film = SML3_calloc(1, sizeof(*vg4->film));
  vg4->actionstack = SML3_calloc(1, sizeof(*vg4->actionstack));
  vg4->nodelink = SML3_calloc(1, sizeof(*vg4->nodelink));
  /* FIXME: more sub-functions */

  /* convert game name */
  if (gamename != NULL) { snprintf(vg4data.gamename, sizeof(vg4data.gamename), "%s", gamename); }
#if 0
  { int ipos;
    for (ipos = 0; vg4data.gamename[ipos] != '\0'; ipos++) {
      if (strchr("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_",
                 (int)vg4data.gamename[ipos]) == NULL) {
        vg4data.gamename[ipos] = '_';
      }
    }
  }
#endif
  if (*vg4data.gamename == '\0') {
    snprintf(vg4data.gamename, sizeof(vg4data.gamename), "No-name");
  }

  /* call initializing functions */
  if (!init_iolib()) { return VG_FALSE; }
  init_hash();
  init_input();
  init_window();
  init_audio();
  init_image();
  init_font();
  init_mlang();
  init_random();
  init_sprite();
  init_nw();
  init_misc();
  init_canvas();
  init_dialog();
  init_object();
  init_collision();
  init_film();
  init_actionstack();
  init_nodelink();
  /* FIXME: more initializing functions */

  return VG_TRUE;
} /* Ende VG_init */


/* VG_dest:
 * clean all up
 */
void
VG_dest(void)
{
  if (vg4data.env.dump_on_exit > 0) {
    FILE *ffout;
    if (vg4data.env.dump_on_exit == 1) {
      ffout = stdout;
    } else {
      ffout = stderr;
    }
    /* call dump functions */
    /* FIXME: more dump functions */
    vg4->collision->dump(ffout);
    vg4->object->dump(ffout);
    vg4->canvas->dump(ffout);
    vg4->sprite->dump(ffout);
    vg4->mlang->dump(ffout);
    vg4->font->dump(ffout);
    vg4->image->dump(ffout);
    vg4->audio->dump(ffout);
    vg4->input->dump(ffout);
    vg4->hash->dump(ffout);
  }

  /* call destroying functions */
  /* FIXME: more destroying functions */
  dest_nodelink();
  dest_actionstack();
  dest_film();
  dest_collision();
  dest_object();
  dest_dialog();
  dest_canvas();
  dest_misc();
  dest_nw();
  dest_sprite();
  dest_random();
  dest_mlang();
  dest_font();
  dest_image();
  dest_audio();
  dest_window();
  dest_input();
  dest_hash();
  dest_iolib();

  /* destroy sub-functions */
  /* FIXME: more sub-functions */
  if (vg4->nodelink != NULL) { free(vg4->nodelink); }
  if (vg4->actionstack != NULL) { free(vg4->actionstack); }
  if (vg4->film != NULL) { free(vg4->film); }
  if (vg4->collision != NULL) { free(vg4->collision); }
  if (vg4->object != NULL) { free(vg4->object); }
  if (vg4->dialog != NULL) { free(vg4->dialog); }
  if (vg4->canvas != NULL) { free(vg4->canvas); }
  if (vg4->misc != NULL) { free(vg4->misc); }
  if (vg4->nw != NULL) { free(vg4->nw); }
  if (vg4->sprite != NULL) { free(vg4->sprite); }
  if (vg4->random != NULL) { free(vg4->random); }
  if (vg4->mlang != NULL) { free(vg4->mlang); }
  if (vg4->font != NULL) { free(vg4->font); }
  if (vg4->image != NULL) { free(vg4->image); }
  if (vg4->audio != NULL) { free(vg4->audio); }
  if (vg4->window != NULL) { free(vg4->window); }
  if (vg4->input != NULL) { free(vg4->input); }
  if (vg4->hash != NULL) { free(vg4->hash); }

  if (vg4data.origlocale != NULL) { free(vg4data.origlocale); }

  memset(&vg4data, 0, sizeof(vg4data));
} /* Ende VG_dest */


/* out_error:
 * print error-message to stderr
 */
void
out_error(const char *file, const char *function, int line, ...)
{
  va_list ap;
  char *fmt;

  if (file == NULL || *file == '\0') { file = "(nofile)"; }
  if (function == NULL || *function == '\0') { function = "(nofunction)"; }

  fprintf(stderr, "%s[%s(), line %d]: ", file, function, line);

  va_start(ap, line);
  fmt = va_arg(ap, char *);
  if (fmt == NULL) { fmt = "(no message)"; }
  vfprintf(stderr, fmt, ap);
  va_end(ap);

  fprintf(stderr, "\n");
  fflush(stderr);
} /* Ende out_error */


/* pinfo:
 * print info-message to stderr
 */
void
pinfo(const char *fmt, ...)
{
  va_list ap;

  if (vg4data.env.no_info) { return; }

  va_start(ap, fmt);
  if (fmt == NULL) { fmt = "(no info)"; }
  vfprintf(stderr, fmt, ap);
  va_end(ap);

  fflush(stderr);
} /* Ende pinfo */


/* pwarn:
 * print warning-message to stderr
 */
void
pwarn(const char *fmt, ...)
{
  va_list ap;

  if (vg4data.env.no_warn) { return; }

  va_start(ap, fmt);
  if (fmt == NULL) { fmt = "(no warning)"; }
  vfprintf(stderr, fmt, ap);
  va_end(ap);

  fflush(stderr);
} /* Ende pwarn */
