#include <stdio.h>

#include <signatures.h>

extern patterns32[SIGNATURE_PATTERNS_NUMBER][16];

int isPowerOf2(int val)
{
	switch (val)
	{
		case 1:   return 0;
		case 2:   return 1;
		case 4:   return 2;
		case 8:   return 3;
		case 16:  return 4;
		case 32:  return 5;
		case 64:  return 6;
		case 128: return 7;
	}

	return -1;
}

// This version compiles for sse2
int main (int argC, char *ArgV[])
{

	FILE *Out;
	if (argC == 2)
	{
		printf("Redirecting output to %s\n", ArgV[1]);
		/*FILE *Out = fopen(ArgV[1], "wt");
		if (Out == NULL)
			return 1;
		fclose(stdout);
		dup2(Out, stdout);*/
		freopen(ArgV[1], "wt", stdout);
	}
	printf( "// This is a precompiled pattern\n"
			"\n"
			"int epsilon;\n"
			"int patSum;\n"
			"int patSums[SIGNATURE_PATTERNS_NUMBER];\n"
			"\n");


	int sum[SIGNATURE_PATTERNS_NUMBER];
	int pat;
	int val;


	for (val = 0; val < 16; val++)
	{
		printf("int16_t pattern%d_1[8] __attribute__((aligned(16))) = {", val);
		for (pat = 0; pat < 8; pat++)
		{
			printf("%s%d", (pat == 0 ? "" : ", ") , patterns32[pat][val]);
		}
		printf("};\n");
		printf("int16_t pattern%d_2[8] __attribute__((aligned(16))) = {", val);

		for (; pat < SIGNATURE_PATTERNS_NUMBER; pat++)
		{
			printf("%s%d", (pat == 8 ? "" : ", ") , patterns32[pat][val]);
		}
		printf("};\n");
	}

	printf(	"int16_t acc1mem[8] __attribute__((aligned(16)));\n"
			"int16_t acc2mem[8] __attribute__((aligned(16)));\n"
			"__m128i data;\n"
			"__m128i pat;\n"
			"__m128i acc1 = _mm_set1_epi16 (0);\n"
			"__m128i acc2 = _mm_set1_epi16 (0);\n\n");

	for (val = 0; val < 16; val++)
	{
		printf(	"dat = _mm_set1_epi16 ((uint16_t)data[%d]);\n"
				"pat = _mm_load_si128((__m128i *)pattern%d_1);\n"
				"pat = _mm_mullo_epi16(dat, pat);\n"
				"acc1 = _mm_add_epi16(acc1, pat);\n"
				"\n"
				"pat = _mm_load_si128((__m128i *)pattern%d_2);\n"
				"pat = _mm_mullo_epi16(dat, pat);\n"
				"acc2 = _mm_add_epi16(acc2, pat);\n"
				"\n", val, val, val );
	}

	printf(	"_mm_store_si128((__m128i *)acc1mem, acc1);\n"
			"_mm_store_si128((__m128i *)acc2mem, acc2);\n");

	return 0;
}


int main1 (int argC, char *ArgV[])
{

	FILE *Out;
	if (argC == 2)
	{
		printf("Redirecting output to %s\n", ArgV[1]);
		/*FILE *Out = fopen(ArgV[1], "wt");
		if (Out == NULL)
			return 1;
		fclose(stdout);
		dup2(Out, stdout);*/
		freopen(ArgV[1], "wt", stdout);
	}
	printf( "// This is a precompiled pattern\n"
			"\n"
			"int epsilon;\n"
			"int patSum;\n"
			"int patSums[SIGNATURE_PATTERNS_NUMBER];\n"
			"\n");


	int sum[SIGNATURE_PATTERNS_NUMBER];
	int pat;
	int val;

	for (pat = 0; pat < SIGNATURE_PATTERNS_NUMBER; pat++)
	{
		sum[pat] = 0;
		for (val = 0; val < 16; val++)
		{
			int patValue = patterns32[pat][val];
			sum[pat] += (patValue > 0 ? patValue : -patValue);
		}
	}


	for (pat = 0; pat < SIGNATURE_PATTERNS_NUMBER; pat++)
	{
		printf("\n//The result for pattern %i\n", pat);
		printf("	patSums[%i] = (", pat);

		for (val = 0; val < 16; val++)
		{
			int koef = patterns32[pat][val];
			if (koef == 0)
				continue;

			if (koef < 0)
			{
				printf(" -");
				koef = -koef;
			}
			else
			{
				printf(" +");
			}

			if (koef != 1)
				printf(" %i *", koef);
			printf(" data[%i]", val);
		}
		printf(");\n");

	}

	for (pat = 0; pat < SIGNATURE_PATTERNS_NUMBER; pat++)
	{
		printf("patSum = patSums[%i];\n", pat);
		printf("do {\n");
		printf("// %i nonzero elements\n", sum[pat]);
		int power = isPowerOf2(sum[pat]);
		if (power != -1)
			printf("	epsilon = baseEpsilon << %i;\n", power);
		else
			printf("	epsilon = baseEpsilon * %i;\n", sum[pat]);

		printf(""
		"	accumulator *= TENARY_SYSTEM_BASE; \n"
		"	if (patSum >  epsilon) { accumulator += MORE_EPS_BIT; break; }\n"
		"	if (patSum < -epsilon) { accumulator += LESS_EPS_BIT; break; }\n"
		"	accumulator += MIDDLE_EPS_BIT;\n");

		printf("} while (0);\n");
	}

	return 0;
}
