/*
 * lib/amal.c
 * https://gitlab.com/bztsrc/assetpack
 *
 * Copyright (C) 2024 bzt, MIT license
 *
 * 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 ANY
 * DEVELOPER OR DISTRIBUTOR 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 Creates the single header amalgamation
 */

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *getfile(char *fn, uint32_t *size)
{
    FILE *f;
    char *buf;

    if(!(f = fopen(fn, "rb"))) {
        fprintf(stderr, "unable to open '%s'\r\n", fn);
        return NULL;
    }
    fseek(f, 0, SEEK_END);
    *size = (uint32_t)ftell(f);
    fseek(f, 0, SEEK_SET);
    if(!(buf = (char*)malloc((*size) + 1))) {
        fprintf(stderr, "unable to allocate memory for '%s'\r\n", fn);
        fclose(f);
        return NULL;
    }
    fread(buf, 1, *size, f);
    buf[*size] = 0;
    fclose(f);
    return buf;
}

int main(int argc, char **argv)
{
    FILE *f;
    uint32_t len, size;
    char *h, *s, *l, *buf, *src, *dst, fn[256];
    int i, n;

    if(argc < 3) {
        printf("amal output input\r\n");
        return 1;
    }

    if(!(f = fopen(argv[1], "wb"))) {
        fprintf(stderr, "unable to open '%s'\r\n", argv[1]);
        return 1;
    }
    if((h = getfile(argv[2], &len))) {
        for(s = l = h; s < h + len && *s; s++) {
            if(!memcmp(s, "#include \"", 10) && memcmp(s, "#include \"apck.h\"", 17)) {
                if(l < s) fwrite(l, 1, s - l, f);
                s += 10;
                for(i = 0; s[i] && s[i] != '\"' && s[i] != '>'; i++) fn[i] = s[i];
                fn[i] = 0;
                if((buf = getfile(fn, &size))) {
                    fprintf(f, "/**************** embeded %s ****************/\n", fn);
                    for(src = dst = buf; src < buf + size; src++) {
                        if(src[0] == '/' && src[1] == '*') {
                            for(src += 2; *src && src[-1] != '/' || src[-2] != '*'; src++);
                            while(dst > buf + 1 && dst[-1] == ' ') dst--;
                        }
                        if(src[0] == '/' && src[1] == '/') {
                            for(src += 2; *src && *src != '\n'; src++);
                            if(src[1] == '\n') src++;
                            while(dst > buf + 1 && dst[-1] == ' ') dst--;
                        }
                        /* fix some broken stb_image ifdef guards */
                        if(!memcmp(src, "return stbi__errpuc(\"unknown image type\"", 40)) {
                            memcpy(dst, "(void)bpc;\n   ", 14); dst += 14;
                        }
                        if(!memcmp(src, "STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len)", 67) ||
                           !memcmp(src, "STBIDEF int      stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user)", 86) ||
                           !memcmp(src, "static int stbi__addints_valid(int a, int b)", 44) ||
                           !memcmp(src, "static int stbi__mul2shorts_valid(int a, int b)", 47)) {
                            for(src += 44; src[-1] != '}'; src++);
                        }
                        if(!memcmp(src, "#ifdef  __cplusplus", 19) ||
                           !memcmp(src, "#ifndef STBI_NO_STDIO", 21) ||
                           !memcmp(src, "#ifndef STBI_NO_GIF", 19) ||
                           !memcmp(src, "#ifndef STBI_NO_LINEAR", 22) ||
                           !memcmp(src, "#ifndef STBI_NO_HDR", 19) ||
                           !memcmp(src, "#ifndef STBI_NO_JPEG", 20) ||
                           !memcmp(src, "#ifndef STBI_NO_BMP", 19) ||
                           !memcmp(src, "#ifndef STBI_NO_TGA", 19) ||
                           !memcmp(src, "#ifndef STBI_NO_PSD", 19) ||
                           !memcmp(src, "#ifndef STBI_NO_PIC", 19) ||
                           !memcmp(src, "#ifndef STBI_NO_GIF", 19) ||
                           !memcmp(src, "#ifndef STBI_NO_PNM", 19) ||
                           !memcmp(src, "#ifndef STB_VORBIS_NO_STDIO", 27) ||
                           !memcmp(src, "#ifndef STB_VORBIS_NO_PUSHDATA_API", 34) ||
                           !memcmp(src, "#ifndef SSFN_MAXLINES", 21) ||
                           !memcmp(src, "#if !defined(M3D_NOIMPORTER) && !defined(STBI_INCLUDE_STB_IMAGE_H)", 66) ||
                           !memcmp(src, "#ifdef M3D_ASCII", 16) ||
                           !memcmp(src, "#ifdef M3D_PROFILING", 20) ||
                           !memcmp(src, "#ifdef M3D_EXPORTER", 19) ||
                           !memcmp(src, "#ifndef M3D_NOTEXTURE", 21) ||
                           !memcmp(src, "#if defined(M3D_EXPORTER) && !defined(INCLUDE_STB_IMAGE_WRITE_H)", 64) ||
                           !memcmp(src, "#if !defined(M3D_NOIMPORTER) && defined(M3D_ASCII)", 50) ||
                           !memcmp(src, "#if !defined(M3D_NOIMPORTER) && defined(M3D_EXPORTER)", 53) ||
                           !memcmp(src, "#if !defined(M3D_NODUP) && (!defined(M3D_NOIMPORTER) || defined(M3D_ASCII) || defined(M3D_EXPORTER))", 100)) {
                            for(n = 1, src += 19; *src && n; src++) {
                                if(!memcmp(src, "#if", 3)) n++;
                                if(!memcmp(src, "#endif", 6)) n--;
                            }
                            for(; *src && *src != '\n'; src++);
                            if(src[1] == '\n') src++;
                            while(dst > buf + 1 && dst[-1] == ' ') dst--;
                        }
                        if(dst == buf || *src != '\n' || (*src == '\n' && dst[-1] != '\n'))
                            *dst++ = *src;
                    }
                    fwrite(buf, 1, dst - buf, f);
                    free(buf);
                }
                while(s < h + len && *s && *s != '\n') s++;
                l = s;
            }
        }
        if(l < s) fwrite(l, 1, s - l, f);
    }
    fclose(f);
    free(h);
    return 0;
}
