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

static void AddData(char *);
static char *my_strtok(char *, char c);

struct MultiCase {
	unsigned short Val;
	unsigned short ToVals[4];
	unsigned Cnt;
	bool bConditional;
};

static MultiCase ToUC[256], ToLC[256];
static unsigned uc, lc;
static bool bConditional = false;

//int main() { return BuildSpecial(); }

int BuildSpecial() {
	// Open UnicodeData.txt
	FILE *in;
	char Buf[512];
	fopen_s(&in, "SpecialCasing.txt", "rt");
	fgets(Buf, sizeof(Buf), in);
	while (!feof(in)) {
		char *jnk;
		if (*Buf != '#' && strlen(Buf) > 3) {
			strtok_s(Buf, "\r\n", &jnk);
			AddData(Buf);
		}
		else if (!strncmp(Buf, "# Conditional Mappings", 22)) {
			bConditional = true;
		}
		fgets(Buf, sizeof(Buf), in);
	}

	printf ("\n\n");
	printf ("/***************************************************************/\n");
	printf ("/*  AUTO-GENERATED-CODE !!! DO NOT EDIT BELOW THIS POINT !!!!  */\n");
	printf ("/***************************************************************/\n");
	printf ("/* There are %d uc's and %d lc's                                */\n", uc, lc);
	printf ("/* This data, generated from the SpecialCasing.txt file        */\n");
	printf ("/***************************************************************/\n");

	printf ("struct MultiCase {\n");
	printf ("\tunsigned short Val;\n");
	printf ("\tunsigned Cnt;\n");
	printf ("\tunsigned short ToVals[4];\n");
	printf ("\tint bIsUp2Low;\n");
	printf ("};\n static struct MultiCase uniMultiCase[] = {\n", lc+uc+1);

	for (unsigned i = 0; i < lc; ++i) {
		if (ToUC[i].bConditional)
			printf ("//");
		printf ("\t{0x%X,%d,{", ToUC[i].Val, ToUC[i].Cnt);
		for (int j = 0; j < (int)ToUC[i].Cnt; ++j)
			printf ("0x%X,", ToUC[i].ToVals[j]);
		printf ("},0},\n");
	}
	for (unsigned i = 0; i < uc; ++i) {
		if (ToLC[i].bConditional)
			printf ("//");
		printf ("\t{0x%X,%d,{", ToLC[i].Val, ToLC[i].Cnt);
		for (int j = 0; j < (int)ToLC[i].Cnt; ++j)
			printf ("0x%X,", ToLC[i].ToVals[j]);
		printf ("},1},\n");
	}
	printf ("\t{0, 0, {0}, 0}\n};\n");

	return 0;
}

static void AddData(char *Buf) {
	char *cp = my_strtok(Buf, ';');
	unsigned code, code2;
	sscanf_s(cp, "%X", &code);
	char *cpLC = my_strtok(NULL, ';');
	if (*cpLC == ' ') ++cpLC;
	char *cpTitle = my_strtok(NULL, ';'); // we ignore title case.
	char *cpUC = my_strtok(NULL, ';');
	if (*cpUC == ' ') ++cpUC;

	// Ok, see if there is a space in the LC or the UC.  If not, then we return.
	if (strchr(cpUC, ' ')) {
		// Ok, single LC (assumed) into multiple UC
		if (strchr(cpLC, ' ')) return;
		sscanf_s(cpLC, "%X", &code2);
		if (code != code2)
			return;

		ToUC[lc].Val = code;
		ToUC[lc].Cnt = 0;
		ToUC[lc].bConditional = bConditional;
		cp = my_strtok(cpUC, ' ');
		while (cp) {
			sscanf_s(cp, "%X", &code);
			ToUC[lc].ToVals[ToUC[lc].Cnt++] = code;
			cp = my_strtok(NULL, ' ');
		}
		if (ToUC[lc].Cnt)
			++lc;
		return;
	}
	if (strchr(cpLC, ' ')) {
		// Ok, single UC (assumed) into multiple LC

		if (strchr(cpUC, ' ')) return;
		sscanf_s(cpUC, "%X", &code2);
		if (code != code2)
			return;

		ToLC[uc].Val = code;
		ToLC[uc].Cnt = 0;
		ToLC[uc].bConditional = bConditional;
		cp = my_strtok(cpLC, ' ');
		while (cp) {
			sscanf_s(cp, "%X", &code);
			ToLC[uc].ToVals[ToLC[uc].Cnt++] = code;
			cp = my_strtok(NULL, ' ');
		}
		if (ToLC[uc].Cnt)
			++uc;
		return;
	}
}

static char *my_strtok(char *in, char c) {
	static char *pBuf;
	if (in)
		pBuf = in;
	char *p = pBuf;
	if (!p || !p[0])
		return NULL;
	while (*pBuf && *pBuf != c)
		++pBuf;
	if (*pBuf)
		*pBuf++ = 0;
	return p;
}
