/*
 * Copyright (C) 2017 FAUmachine Team <info@faumachine.org>.
 * This program is free software. You can redistribute it and/or modify it
 * under the terms of the GNU General Public License, either version 2 of
 * the License, or (at your option) any later version. See COPYING.
 */

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

typedef struct {
	const char *c_name;
	const char *alias;
} datatype_t;

typedef struct {
	const char *c_name;
	const char *alias;
} comparator_t;

typedef unsigned int uint;

static datatype_t datatypes[] = {
        { "uint8_t",	"DATA_TYPE_UINT8_T"},
        { "uint16_t",	"DATA_TYPE_UINT16_T"},
        { "uint32_t",	"DATA_TYPE_UINT32_T"},
        { "uint64_t",	"DATA_TYPE_UINT64_T"},
        { "int8_t",	"DATA_TYPE_INT8_T"},
        { "int16_t",	"DATA_TYPE_INT16_T"},
        { "int32_t",	"DATA_TYPE_INT32_T"},
        { "int64_t",	"DATA_TYPE_INT64_T"},
        { "int",	"DATA_TYPE_INT"},
        { "uint",	"DATA_TYPE_UINT"},
};

static const unsigned n_datatypes = sizeof(datatypes) / sizeof(datatype_t);

static comparator_t comparators[] = {
        { "eq", "COMPARATOR_EQ"},
        { "ne", "COMPARATOR_NEQ"},
        { "lt", "COMPARATOR_LT"},
        { "gt", "COMPARATOR_GT"},
        { "le", "COMPARATOR_LE"},
        { "ge", "COMPARATOR_GE"},
};

static const unsigned n_comparators = sizeof(comparators) / sizeof(comparator_t);

static void print_licence_text(FILE *out)
{
	fprintf(out,
	        "/*\n"
	        " * Copyright (C) 2017 FAUmachine Team <info@faumachine.org>.\n"
	        " * This program is free software. You can redistribute it and/or modify it\n"
	        " * under the terms of the GNU General Public License, either version 2 of\n"
	        " * the License, or (at your option) any later version. See COPYING.\n"
	        " */\n");
}

static void print_generic_func_definitions(FILE *out)
{
	unsigned i;

	for (i=0; i<n_datatypes; i++) {
		unsigned j;

		for (j=0; j<n_datatypes; j++) {
			fprintf(out, "#define TYPE0 %s\n", datatypes[i].c_name);
			fprintf(out, "#define TYPE1 %s\n", datatypes[j].c_name);
			fprintf(out, "#include \"lib/inspector_test_condition.c\"\n");
		}
		fprintf(out, "\n");
	}
}

static void print_declare_array(FILE *out)
{
	fprintf(out, "static inspector_test_condition_t inspector_test_functions[%d][%d][%d];\n",
	        n_datatypes, n_datatypes, n_comparators);
}

static void print_fill_array(FILE *out)
{
	unsigned i;

	fprintf(out, "static void init_function_array(void) {\n");

	for (i=0; i<n_datatypes; i++) {
		unsigned j;

		for (j=0; j<n_datatypes; j++) {
			unsigned k;

			for (k=0; k<n_comparators; k++) {
				fprintf(out, "\tinspector_test_functions[%s][%s][%s] = &inspector_test_%s_%s_%s;\n",
				        datatypes[i].alias, datatypes[j].alias, comparators[k].alias,
				        comparators[k].c_name, datatypes[i].c_name, datatypes[j].c_name);
			}
			fprintf(out, "\n");
		}
		fprintf(out, "\n");
	}

	fprintf(out, "}\n");
}

static void print_getter_func(FILE *out)
{
	fprintf(out, "static inspector_test_condition_t get_compare_func(data_type_t type_a,\n");
	fprintf(out, "                                                   data_type_t type_b,\n");
	fprintf(out, "                                                   int comparator)\n");
	fprintf(out, "{\n");
	fprintf(out, "\treturn inspector_test_functions[type_a][type_b][comparator];\n");
	fprintf(out, "}\n");
}

void main(void) {
	FILE *out = stdout;

	fprintf(out, "\n");

	print_licence_text(out);

	fprintf(out, "\n");

	print_generic_func_definitions(out);

	fprintf(out, "\n");

	print_declare_array(out);

	fprintf(out, "\n");

	print_fill_array(out);

	fprintf(out, "\n");

	print_getter_func(out);

	fprintf(out, "\n");

	fflush(out);
}
