/*
 * Kangaroo Punch MultiPlayer Game Server Mark II
 * Copyright (C) 2020-2021  Scott Duensing
 *
 * This program 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 3 of the License, or
 * (at your option) any later version.
 *
 * This program 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 this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 */


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

#define MEMWATCH
#include "memwatch/memwatch.h"

#include "thirdparty/SHA256/sha256.h"

#include "stddclmr.h"


#define SUCCESS 1
#define FAIL    0


#define CLIENT  "/home/scott/code/kpmpgsmkii/client/in/"
#define FONT    "/home/scott/code/kpmpgsmkii/font/out/"
#define OUT     "/home/scott/code/kpmpgsmkii/precache/out/"


typedef struct CachePreMakeListS {
	char *filename;
	char *virtualPath;
} CachePreMakeListT;


uint8_t cachePrePack(char *name, CachePreMakeListT *list) {

	FILE           *in           = NULL;
	FILE           *out          = NULL;
	uint16_t        i            = 0;
	uint8_t         result       = SUCCESS;
	uint32_t        length       = 0;
	uint32_t        total        = 0;
	uint32_t        temp         = 0;
	int8_t          buffer[8192] = { 0 };
	sha256_context  ctx          = { 0 };
	uint8_t         hv[32]       = { 0 };

	// Prebuilt cache format:
	// - Virtual Path (zero terminated)
	// - x bytes hash
	// - 4 bytes unsigned length of data
	// - length bytes of data
	// ... repeat for each file ...
	// - 4 bytes length of entire cache (used for embedding cache data)

	out = fopen(name, "wb");
	if (out) {
		while (list[i].filename != NULL) {
			in = fopen(list[i].filename, "rb");
			if (in) {
				// Get length of file.
				fseek(in, 0, SEEK_END);
				length = ftell(in);
				fseek(in, 0, SEEK_SET);
				// Generate SHA256.
				sha256_init(&ctx);
				do {
					temp = fread(buffer, 1, sizeof(buffer), in);
					if (temp) sha256_hash(&ctx, (uint8_t *)buffer, temp);
				} while (temp > 0);
				sha256_done(&ctx, hv);
				fseek(in, 0, SEEK_SET);
				// Write header.
				temp = strlen(list[i].virtualPath) + 1;
				fwrite(list[i].virtualPath, temp, 1, out);
				fwrite(hv, sizeof(hv), 1, out);
				fwrite(&length, sizeof(uint32_t), 1, out);
				total += temp + sizeof(hv) + sizeof(uint32_t) + length;
				// Copy data.
				do {
					temp = fread(buffer, 1, sizeof(buffer), in);
					if (temp) fwrite(buffer, 1, temp, out);
				} while (temp > 0);
				fclose(in);
			} else {
				result = FAIL;
			}
			i++;
		}
		// Write length of entire block.
		total += sizeof(uint32_t);
		fwrite(&total, sizeof(uint32_t), 1, out);
		fclose(out);
	} else {
		result = FAIL;
	}

	return result;
}


int main(int argc, char *argv[]) {

	CachePreMakeListT list[] = {
		{ CLIENT"welcome/dconnect.png", "welcome:connect.png" },
		{ CLIENT"welcome/ddialing.png", "welcome:dialing.png" },
		{ CLIENT"welcome/dinit.png",    "welcome:init.png"    },
		{ CLIENT"welcome/logo.png",     "welcome:logo.png"    },
		{ CLIENT"gui/mbie32.png",       "gui:exclamation.png" },
		{ CLIENT"gui/mbii32.png",       "gui:information.png" },
		{ CLIENT"gui/mbim32.png",       "gui:message.png"     },
		{ CLIENT"gui/mbiq32.png",       "gui:question.png"    },
		{ CLIENT"gui/mbiw32.png",       "gui:warning.png"     },
		{ CLIENT"gui/mouse.png",        "gui:mouse.png"       },
		{ CLIENT"gui/wait.png",         "gui:wait.png"        },
		{ FONT"vga8x14.dat",            "gui:vga8x14.dat"     },
		{ NULL,                         NULL                  }
	 };

	(void)argc;
	(void)argv;

	// Also run optipng -o7 on images.

	cachePrePack(OUT"client.pre", list);
	//cachePreUnpack(OUT"client.pre");

	return 0;
}
