/*
  Copyright ® Olivier Montanuy,
              André Majorel,
              contributors to the DeuTex project.

  DeuTex incorporates code derived from DEU 5.21 that was put in the
  public domain in 1994 by Raphaël Quinet and Brendon Wyber.

  SPDX-License-Identifier: GPL-2.0-or-later
*/

#include "deutex.h"
#include <errno.h>
#include <ctype.h>
#include "mkwad.h"
#include "tools.h"
#include "endianm.h"
#include "sscript.h"

#define PAGESZ   1516
#define OPTIONSZ 228
enum field_type_t {
    FT_I32,
    FT_NAME,
    FT_S16,
    FT_S32,
    FT_S80,
    FT_S320
};

static void dump_field(FILE * fp, const unsigned char *buf,
                       unsigned long *ofs, enum field_type_t type,
                       const char *desc);
static int mem_is_zero(const char *buf, size_t buf_size);

/*
 *      sscript_save - save a script lump to file
 */
int sscript_save(struct WADINFO *wad, int16_t n, const char *file)
{
    FILE *fp = NULL;
    unsigned char *data = NULL;
    int32_t size = 0;
    const char *lumpname = wad->dir[n].name;

    data = (unsigned char *) WADRreadEntry(wad, n, &size);
    if (size % PAGESZ) {
        Warning("SS10", "script %s: weird size %ld", lump_name(lumpname),
                (long) size);
        size = PAGESZ * (size / PAGESZ);
    }
    fp = fopen(file, "w");
    if (fp == NULL) {
        nf_err("SS15", "%s: %s", file, strerror(errno));
        return 1;
    }
    fprintf(fp, "# DeuTex Strife script source version 1\n");
    /* Save all pages */
    {
        int p;
        for (p = 0; p < size / PAGESZ; p++) {
            unsigned long ofs = PAGESZ * p;
            int o;

            fputc('\n', fp);
            fprintf(fp, "page %d {\n", p);
            dump_field(fp, data, &ofs, FT_I32, "    unknown0   ");
            dump_field(fp, data, &ofs, FT_I32, "    unknown1   ");
            dump_field(fp, data, &ofs, FT_I32, "    unknown2   ");
            dump_field(fp, data, &ofs, FT_I32, "    unknown3   ");
            dump_field(fp, data, &ofs, FT_I32, "    unknown4   ");
            dump_field(fp, data, &ofs, FT_I32, "    unknown5   ");
            dump_field(fp, data, &ofs, FT_S16, "    character  ");
            dump_field(fp, data, &ofs, FT_NAME, "    voice      ");
            dump_field(fp, data, &ofs, FT_NAME, "    background ");
            dump_field(fp, data, &ofs, FT_S320, "    statement  ");

            for (o = 0; o < 5; o++) {
                /* If the option is zeroed out, omit it */
                if (mem_is_zero((char *) (data + ofs), OPTIONSZ)) {
                    ofs += OPTIONSZ;
                    continue;
                }

                /* Else, decode it */
                fputc('\n', fp);
                fprintf(fp, "    option %d {\n", o);
                dump_field(fp, data, &ofs, FT_I32, "        whata   ");
                dump_field(fp, data, &ofs, FT_I32, "        whatb   ");
                dump_field(fp, data, &ofs, FT_I32, "        whatc   ");
                dump_field(fp, data, &ofs, FT_I32, "        whatd   ");
                dump_field(fp, data, &ofs, FT_I32, "        whate   ");
                dump_field(fp, data, &ofs, FT_I32, "        price   ");
                dump_field(fp, data, &ofs, FT_I32, "        whatg   ");
                dump_field(fp, data, &ofs, FT_S32, "        option  ");
                dump_field(fp, data, &ofs, FT_S80, "        success ");
                dump_field(fp, data, &ofs, FT_I32, "        whath   ");
                dump_field(fp, data, &ofs, FT_I32, "        whati   ");
                dump_field(fp, data, &ofs, FT_S80, "        failure ");
                fputs("    }\n", fp);
            }

            fputs("}\n", fp);
            /* Sanity check */
            if (ofs % PAGESZ)
                Bug("SS20", "script %s: page %d: bad script offset %d",
                    lump_name(lumpname), p, (int) ofs);
        }
    }

    free(data);
    if (fclose(fp)) {
        nf_err("SS45", "%s: %s", file, strerror(errno));
        return 1;
    }
    return 0;
}

/*
 *      sscript_load
 */
int sscript_load(void)
{
    printf("Oops! sscript_load not written yet!\n");
    return 1;
}

/*
 *      dump_field - write a field of a page to file
 */
static void dump_field(FILE * fp, const unsigned char *buf,
                       unsigned long *ofs, enum field_type_t type,
                       const char *desc)
{
    fprintf(fp, "%-10s ", desc);
    if (type == FT_I32) {
        fprintf(fp, "%ld", (long) peek_i32_le(buf + *ofs));
        *ofs += 4;
    } else if (type == FT_NAME) {
        int n;
        putc('"', fp);
        for (n = 0; n < 8 && buf[*ofs + n] != '\0'; n++)
            putc(tolower(buf[*ofs + n]), fp);
        putc('"', fp);
        *ofs += 8;
    } else if (type == FT_S16) {
        fprintf(fp, "\"%.16s\"", buf + *ofs);
        *ofs += 16;
    } else if (type == FT_S32) {
        fprintf(fp, "\"%.32s\"", buf + *ofs);
        *ofs += 32;
    } else if (type == FT_S80) {
        fprintf(fp, "\"%.80s\"", buf + *ofs);
        *ofs += 80;
    } else if (type == FT_S320) {
        fprintf(fp, "\"%.320s\"", buf + *ofs);
        *ofs += 320;
    } else {
        Bug("SS25", "bad field type %d", (int) type);
    }
    fputs(";\n", fp);
}

static int mem_is_zero(const char *buf, size_t buf_size)
{
    int n;

    for (n = 0; n < buf_size; n++) {
        if (buf[n] != '\0') {
            return 0;
        }
    }
    return 1;
}
