/*
 * (c) 2015-2017 Marcos Del Sol Vives
 * (c) 2016      javiMaD
 *
 * SPDX-License-Identifier: MIT
 */

#include <amiibo.h>
#include <stdio.h>
#include <string.h>
#include "../loclass/fileutil.h"

#define NTAG215_SIZE 540

static char * self;

void amiitool_usage() {
	fprintf(stderr,
		"amiitool build %i (commit %s-%08x)\n"
		"by Marcos Del Sol Vives <marcos@dracon.es>\n"
		"\n"
		"Usage: %s (-e|-d|-c) -k keyfile [-i input] [-s input2] [-o output]\n"
		"   -e encrypt and sign amiibo\n"
		"   -d decrypt and test amiibo\n"
		"   -c decrypt, copy AppData and encrypt amiibo\n"
		"   -k key set file. For retail amiibo, use \"retail unfixed\" key set\n"
		"   -i input file. If not specified, stdin will be used.\n"
		"   -s input save file, save from this file will replace input file ones.\n"
		"   -o output file. If not specified, stdout will be used.\n"
		"   -l decrypt files with invalid signatures.\n",
		, self
	);
}

static bool LoadAmiikey(nfc3d_amiibo_keys keys, char* keyfile) {
	
	if (!nfc3d_amiibo_load_keys(&keys, keyfile)) {
		PrintAndLogEx(ERR, "Could not load keys from '%s'", keyfile);
		return false;
	}
	return true;
}

int main(int argc, char ** argv) {
	self = argv[0];

	char * infile = NULL;
	char * savefile = NULL;
	char * outfile = NULL;
	char * keyfile = NULL;
	char op = '\0';
	bool lenient = false;

	char c;
	while ((c = getopt(argc, argv, "edci:s:o:k:l")) != -1) {
		switch (c) {
			case 'e':
			case 'd':
			case 'c':
				op = c;
				break;
			case 'i':
				infile = optarg;
				break;
			case 's':
				savefile = optarg;
				break;
			case 'o':
				outfile = optarg;
				break;
			case 'l':
				lenient = true;
				break;
			default:
				amiitool_usage();
				return 2;
		}
	}

	if (op == '\0' || keyfile == NULL) {
		amiitool_usage();
		return 1;
	}

	nfc3d_amiibo_keys amiiboKeys;

	
	uint8_t original[NTAG215_SIZE];
	uint8_t modified[NFC3D_AMIIBO_SIZE];

	FILE * f = stdin;
	if (infile) {
		f = fopen(infile, "rb");
		if (!f) {
			fprintf(stderr, "Could not open input file\n");
			return 3;
		}
	}
	size_t readPages = fread(original, 4, NTAG215_SIZE / 4, f);
	if (readPages < NFC3D_AMIIBO_SIZE / 4) {
		fprintf(stderr, "Could not read from input\n");
		fclose(f);
		return 3;
	}
	fclose(f);


	if (op == 'e') {
		nfc3d_amiibo_pack(&amiiboKeys, original, modified);
	} else if (op == 'd') {
		if (!nfc3d_amiibo_unpack(&amiiboKeys, original, modified)) {
			fprintf(stderr, "!!! WARNING !!!: Tag signature was NOT valid\n");
			if (!lenient) {
				return 6;
			}
		}
	} else { /* copy */
		uint8_t plain_base[NFC3D_AMIIBO_SIZE];
		uint8_t plain_save[NFC3D_AMIIBO_SIZE];

		if (!nfc3d_amiibo_unpack(&amiiboKeys, original, plain_base)) {
			fprintf(stderr, "!!! WARNING !!!: Tag signature was NOT valid\n");
			if (!lenient) {
				return 6;
			}
		}
		if (savefile) {
			f = fopen(savefile, "rb");
			if (!f) {
				fprintf(stderr, "Could not open save file\n");
				return 3;
			}
		}
		size_t readPages = fread(original, 4, NTAG215_SIZE / 4, f);
		if (readPages < NFC3D_AMIIBO_SIZE / 4) {
			fprintf(stderr, "Could not read from save\n");
			fclose(f);
			return 3;
		}
		fclose(f);

		if (!nfc3d_amiibo_unpack(&amiiboKeys, original, plain_save)) {
			fprintf(stderr, "!!! WARNING !!!: Tag signature was NOT valid\n");
			if (!lenient) {
				return 6;
			}
		}

		nfc3d_amiibo_copy_app_data(plain_save, plain_base);
		nfc3d_amiibo_pack(&amiiboKeys, plain_base, modified);
	}

	f = stdout;
	if (outfile) {
		f = fopen(outfile, "wb");
		if (!f) {
			fprintf(stderr, "Could not open output file\n");
			return 4;
		}
	}
	if (fwrite(modified, NFC3D_AMIIBO_SIZE, 1, f) != 1) {
		fprintf(stderr, "Could not write to output\n");
		fclose(f);
		return 4;
	}
	if (readPages > NFC3D_AMIIBO_SIZE / 4) {
		if (fwrite(original + NFC3D_AMIIBO_SIZE, readPages * 4 - NFC3D_AMIIBO_SIZE, 1, f) != 1) {
			fprintf(stderr, "Could not write to output:\n");
			fclose(f);
			return 4;
		}
	}
	fclose(f);
	return 0;
}