/*
 * Battlezone string table decoder.
 *
 * Example:
 *  strtab Battlezone 0x5000 0x1d93 0x1f3a 0x20f6 0x2288
 *
 * Copyright 2020 faddenSoft.  Licensed under the Apache License, Version 2.0.
 */
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>

const char CH_COPYR = '@';      // \u00a9
const char CH_SOUNDC = '&';     // \u2117

const char gCharMap[] = {
    ' ', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
    'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
    'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
    ' ', '-', CH_COPYR, CH_SOUNDC
};

#define NELEM(x) (sizeof(x) / sizeof(x[0]))

const int NUM_STRINGS = 24;

uint8_t* loadFile(const char* fileName) {
    FILE* fp = fopen(fileName, "rb");
    if (fp == NULL) {
        perror("fopen");
        return NULL;
    }
    fseek(fp, 0, SEEK_END);
    long fileLen = ftell(fp);
    rewind(fp);

    uint8_t* buf = new uint8_t[fileLen];
    size_t actual = fread(buf, 1, fileLen, fp);
    fclose(fp);
    if (actual != (size_t) fileLen) {
        fprintf(stderr, "Error reading file\n");
        delete[] buf;
        return NULL;
    }

    return buf;
}

void printString(int8_t* buf, int offset) {
    int xc = buf[offset++] * 4;
    int yc = buf[offset++] * 4;
    if ((xc | yc) == 0) {
        printf("(rel) ");
    } else {
        printf("%+d,%+d ", xc, yc);
    }
    putchar('\'');

    int8_t val;
    do {
        val = buf[offset++];
        int idx = (val & 0x7f) / 2;
        if (idx < 0 || idx >= (int)NELEM(gCharMap)) {
            printf(" [?!] ");
        } else {
            char ch = gCharMap[idx];
            if (ch == CH_COPYR) {
                printf("(C)");
            } else if (ch == CH_SOUNDC) {
                printf("(P)");
            } else {
                putchar(ch);
            }
        }
    } while ((val & 0x80) == 0);
    printf("'\n");
}

void usage() {
    fprintf(stderr, "Usage: strtab <filename> <base_addr> <offset0> [<offset1>...]\n");
}

int main(int argc, char** argv) {
    if (argc < 4) {
        usage();
        return 2;
    }

    uint8_t* buf = loadFile(argv[1]);
    int baseAddr = strtol(argv[2], NULL, 0);

    for (int ar = 3; ar < argc; ar++) {
        int tabOffset = strtol(argv[ar], NULL, 0);

        for (int st = 0; st < NUM_STRINGS; st++) {
            uint16_t strAddr = buf[tabOffset + st * 2] + (buf[tabOffset + st * 2 + 1] << 8);
            int strOffset = strAddr - baseAddr;
            printf("set-comment +%06x:", tabOffset + st * 2);
            printString((int8_t*)buf, strOffset);
        }
    }

    return 0;
}
