/*
 * mtsedit/main.c
 *
 * Copyright (C) 2019 bzt (bztsrc@gitlab)
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 * @brief Main function
 *
 */

#define STB_IMAGE_IMPLEMENTATION
#include "main.h"
/* those SDL guys are not familiar with the C standard. They redefine main(), but incorrectly, they lack envp */
#ifdef main
#undef main
int main(int argc, char** argv, char** envp);
#endif

/* translation dictionary */
extern char *dict[NUMLANGS][NUMTEXTS + 1];
char **lang = &dict[0][1];

/**
 * Windows workaround
 */
#ifdef __WIN32__

/* these two functions were borrowed from sdl_windows_main.c */
static void UnEscapeQuotes(char *arg)
{
    char *last = NULL, *c_curr, *c_last;

    while (*arg) {
        if (*arg == '"' && (last != NULL && *last == '\\')) {
            c_curr = arg;
            c_last = last;

            while (*c_curr) {
                *c_last = *c_curr;
                c_last = c_curr;
                c_curr++;
            }
            *c_last = '\0';
        }
        last = arg;
        arg++;
    }
}

/* Parse a command line buffer into arguments */
static int ParseCommandLine(char *cmdline, char **argv)
{
    char *bufp;
    char *lastp = NULL;
    int argc, last_argc;

    argc = last_argc = 0;
    for (bufp = cmdline; *bufp;) {
        /* Skip leading whitespace */
        while (SDL_isspace(*bufp)) {
            ++bufp;
        }
        /* Skip over argument */
        if (*bufp == '"') {
            ++bufp;
            if (*bufp) {
                if (argv) {
                    argv[argc] = bufp;
                }
                ++argc;
            }
            /* Skip over word */
            lastp = bufp;
            while (*bufp && (*bufp != '"' || *lastp == '\\')) {
                lastp = bufp;
                ++bufp;
            }
        } else {
            if (*bufp) {
                if (argv) {
                    argv[argc] = bufp;
                }
                ++argc;
            }
            /* Skip over word */
            while (*bufp && !SDL_isspace(*bufp)) {
                ++bufp;
            }
        }
        if (*bufp) {
            if (argv) {
                *bufp = '\0';
            }
            ++bufp;
        }

        /* Strip out \ from \" sequences */
        if (argv && last_argc != argc) {
            UnEscapeQuotes(argv[last_argc]);
        }
        last_argc = argc;
    }
    if (argv) {
        argv[argc] = NULL;
    }
    return (argc);
}

/* Windows entry point */
int APIENTRY WinMain(_unused HINSTANCE hInstance, _unused HINSTANCE hPrevInstance, _unused LPSTR lpCmdLine, _unused int nCmdShow)
{
    char *cmdline = GetCommandLine();
    int ret, argc = ParseCommandLine(cmdline, NULL);
    char **argv = SDL_stack_alloc(char*, argc+2);
    ParseCommandLine(cmdline, argv);
    if(!argv[1]) {
        argc++;
        argv[1] = ".";
    }
    SDL_SetMainReady();
    ret = main(argc, argv, (char**)GetEnvironmentStrings());
    SDL_stack_free(argv);
    exit(ret);
    return ret;
}
#endif

/**
 * The real main procedure
 */
int main(int argc, char** argv, char** envp)
{
    int i, j, opt = 0, ret = 0;
    char **env, *newmap = NULL, *lc = NULL;

    /* detect the language (or get from command line) and load dictionary for it */
    for(env = envp; env && *env; env++) if(!memcmp(*env, "LANG=", 5)) { lc = *env + 5; break; }
    for(i = 1; i < argc; i++) if(argv[i][0] == '-' && argv[i][1] == 'l') { lc = argv[i+1]; break; }
    if(lc)
        for(i = 0; i < NUMLANGS; i++) {
            if(!memcmp(lc, dict[i][0], strlen(dict[i][0]))) {
                lang = &dict[i][1];
                break;
            }
        }
    /* get blocks data */
    blocks_getdir(argv, envp);

#ifndef __WIN32__
    /* MacOSX does not allow specifying arguments when started from Launchpad,
     * and it won't show the output in a terminal either. So fake home dir.  */
    if(argc < 2 && !isatty(1)) { argc++; argv[1] = "~"; }
    /* Instead MacOSX likes to append unwanted arguments to the command line... */
    if(argc == 2 && !memcmp(argv[1], "-psn_", 5)) argv[1] = "~";
#endif

    if(argc < 2) {
usage:  printf("MineTest Schematics Editor by bzt Copyright (C) 2019 MIT license\r\n\r\n"
            "./mtsedit [-h] [-v] [-l lang] [-d|-p|-P|-b|-B|-V] [-r remapfile] [-m map] <schematic> [out.mts]\r\n"
            "./mtsedit [-G|-C|-T]\r\n"
            "./mtsedit -g <block.png>\r\n"
            "./mtsedit -t <blockimgs.csv> [blockid]\r\n"
            "./mtsedit -i [Minetest mods dir]\r\n"
            "\r\n  -v: %s\r\n  -l lang: %s\r\n  -d: %s\r\n  -p: %s\r\n  -P: %s\r\n  -b, -B: %s\r\n  -r remapfile: %s\r\n"
            "  -m map: %s\r\n  -g: %s\r\n  -t: %s\r\n  -i: %s\r\n  -V: %s\r\n  out.mts: %s\r\n",
            lang[INF_VERB], lang[INF_LANG], lang[INF_DUMP], lang[INF_PRE1], lang[INF_PRE2], lang[INF_BPRINT], lang[INF_REMAP],
            lang[INF_MAP], lang[INF_GEN], lang[INF_BLK], lang[INF_MOD], lang[INF_VOX], lang[INF_OUT]);
        exit(0);
    }
    for(i = j = 1; j < argc; j++) {
        if(argv[j][0] == '-') {
            switch(argv[j][1]) {
                case 'v': verbose++; break;
                case 'd': opt = 1; break;
                case 'p': opt = 2; break;
                case 'P': opt = 3; break;
                case 'b': opt = 4; break;
                case 'B': opt = 4; shift = 1; break;
                case 'g': opt = 5; break;
                case 't': opt = 6; break;
                case 'i': opt = 7; break;
                case 'm': if(!opt) { opt = 8; } newmap = argv[++j]; i++; break;
                case 'V': opt = 9; break;
                case 'r': remapfile = argv[++j]; i++; break;
                case 'l': j++; i++; break;
                case 'G': gimppal(); return 0; break;
                case 'C':
                    blocks_parse();
                    if(newmap) {
                        j = atoi(newmap);
                        if(j) savepal = j - 1;
                        else {
                            for(j = 0; j < numpalettes; j++)
                                if(!strcmp(palettes[j], newmap)) { savepal = j; break; }
                        }
                    }
                    mapperpal();
                    return 0;
                break;
                case 'T': tileremap(); return 0; break;
                default: goto usage; break;
            }
            i++;
        } else {
            i = j; break;
        }
    }
    if(i >= argc || !argv[i]) goto usage;
#ifndef __WIN32__
    if(argv[i][0] == '~') {
        strncpy(mtsfile, home, sizeof(mtsfile) - 1);
        strncat(mtsfile, argv[i] + 1, sizeof(mtsfile) - 1);
    } else
#endif
        strncpy(mtsfile, argv[i], sizeof(mtsfile) - 1);
    savelen = savepos = strlen(mtsfile);
    tmpblk = (unsigned char*)malloc(32 * 32 * 4);
    if(!tmpblk) error(lang[ERR_MEM]);

    mts_x = mts_y = mts_z = 0;
    if(i+1 < argc && argv[i+1] && !opt) opt = 8;
    if(opt && (opt < 5 || opt >= 8)) {
        blocks_parse();
        readschem();
        if(!mts_y || !mts_y || !mts_x)
            fprintf(stderr, "mtsedit: %s: %s\r\n", mtsfile, lang[ERR_LOAD]);
        if(newmap) {
            j = atoi(newmap);
            if(j) savepal = j - 1;
            else {
                for(j = 0; j < numpalettes; j++)
                    if(!strcmp(palettes[j], newmap)) { savepal = j; break; }
            }
        }
        if(argv[i+1]) {
#ifndef __WIN32__
            if(argv[i+1][0] == '~') {
                strncpy(mtsfile, home, sizeof(mtsfile) - 1);
                strncat(mtsfile, argv[i+1] + 1, sizeof(mtsfile) - 1);
            } else
#endif
                strncpy(mtsfile, argv[i+1], sizeof(mtsfile) - 1);
            ret = opt == 9 ? vox_save() : mts_save();
        }
    }
    switch(opt) {
        case 1: ret = mts_dump(); break;
        case 2:
        case 3: ret = mts_view(opt-2); break;
        case 5: ret = stairgen(); break;
        case 6: ret = blockgen(argv[i+1]); break;
        case 4: /* handle these in sdl.c, because extern does not know sizeof() */
        case 7:
        case 0:
            /* start the main user interface */
            ret = sdlmain(opt);
        break;
    }

    free(path);
    free(tmpblk);
    return ret;
}
