#include <stdio.h>
#include <string.h>
#include "arg.h"
#include "log.h"
#include "dep.h"
#include "db.h"
#include "libs.h"
#include "tmpasm_scconfig.h"
#include "Rev.h"
#include "../util/arg_auto_set.h"

#include <librnd/src_3rd/libfungw/scconfig_hooks.h>

/* we are doing /local/csch/ */
#define LIBRND_SCCONFIG_APP_TREE "csch"

#include <librnd/src_3rd/puplug/scconfig_hooks.h>
#include <librnd/scconfig/plugin_3state.h>
#include <librnd/scconfig/hooks_common.h>
#include <librnd/scconfig/rnd_hook_detect.h>

#define version "1.0.9"

#define REQ_LIBRND_MAJOR 4
#define REQ_LIBRND_MINOR 2


const arg_auto_set_t disable_libs[] = { /* list of --disable-LIBs and the subtree they affect */
	{"enable-bison",      "/local/csch/want_bison",        arg_true,      "$enable generating language files using bison/flex"},
	{"disable-bison",     "/local/csch/want_bison",        arg_false,     "$disable generating language files using bison/flex"},
	{"enable-byaccic",    "/local/csch/want_byaccic",      arg_true,      "$enable generating language files using byaccic/ureglex"},
	{"disable-byaccic",   "/local/csch/want_byaccic",      arg_false,     "$disable generating language files byaccic/ureglex"},

#undef plugin_def
#undef plugin_header
#undef plugin_dep
#define plugin_def(name, desc, default_, all_) plugin3_args(name, desc)
#define plugin_header(sect)
#define plugin_dep(plg, on)
#include "plugins.h"

	{NULL, NULL, NULL, NULL}
};

#define TO_STR_(payload) #payload
#define TO_STR(payload) TO_STR_(payload)


static void help1(void)
{
	rnd_help1("sch-rnd");
	printf(" --dot_sch_rnd=path         .sch-rnd config path under $HOME/\n");
}

/* Runs when a custom command line argument is found
 returns true if no furhter argument processing should be done */
int hook_custom_arg(const char *key, const char *value)
{
	rnd_hook_custom_arg(key, value, disable_libs); /* call arg_auto_print_options() instead */

	if (strcmp(key, "dot_sch_rnd") == 0) {
		need_value("use --dot_sch_rnd=dir");
		put("/local/csch/dot_sch_rnd", value);
		return 1;
	}
	if (strcmp(key, "fontdir") == 0) {
		fprintf(stderr, "*** WARNING ***\n *** --fontdir is obsolete, please remove it from your command line!\n\n");
		return 1;
	}
/*	if (strcmp(key, "debug") == 0) {
		put("/local/csch/debug", strue);
		return 1;
	}
	if (strcmp(key, "profile") == 0) {
		put("/local/csch/profile", strue);
		return 1;
	}*/

	if (arg_auto_set(key, value, disable_libs) == 0) {
		fprintf(stderr, "Error: unknown argument %s\n", key);
		exit(1);
	}
	return 1; /* handled by arg_auto_set() */

}


/* Runs before anything else */
int hook_preinit()
{
	return 0;
}

void librnd_ver_req_min(int exact_major, int min_minor);

/* Runs after initialization */
int hook_postinit()
{
	db_mkdir("/local");
	db_mkdir("/local/csch");
	rnd_hook_postinit();

	/* defaults */
	put("/local/csch/debug", sfalse);
	put("/local/csch/profile", sfalse);

	put("/local/csch/librnd_prefix", TO_STR(LIBRND_PREFIX));
	put("/local/csch/dot_sch_rnd", ".sch-rnd");

	librnd_ver_req_min(REQ_LIBRND_MAJOR, REQ_LIBRND_MINOR);

	return 0;
}

/* Runs after all arguments are read and parsed */
int hook_postarg()
{
	char *tmp;
	const char *libad;

	put("/local/csch/librnd_template", tmp = str_concat("", TO_STR(LIBRND_PREFIX), "/", get("/local/libarchdir"), "/librnd4/scconfig/template", NULL));
	free(tmp);

	/* if librnd is installed at some custom path, we'll need to have a -I on CFLAGS and -L on LDFLAGS */
	libad = get("/local/libarchdir");
	if (((strncasecmp(TO_STR(LIBRND_PREFIX), "/usr/include", 12) != 0) && (strncasecmp(TO_STR(LIBRND_PREFIX), "/usr/local/include", 18) != 0)) || (strcmp(libad, "lib") != 0)) {
		put("/local/csch/librnd_extra_inc", "-I" TO_STR(LIBRND_PREFIX) "/include");
		put("/local/csch/librnd_extra_ldf", tmp = str_concat("", "-L" TO_STR(LIBRND_PREFIX) "/", libad, NULL));
		free(tmp);
	}

	return rnd_hook_postarg(TO_STR(LIBRND_PREFIX), "sch-rnd");
}

/* Runs when things should be detected for the host system */
int hook_detect_host()
{
	return rnd_hook_detect_host();
}

/* Runs when things should be detected for the target system */
int hook_detect_target()
{
	const char *host_ansi, *host_ped, *target_ansi, *target_ped, *target_pg, *target_no_pie;
	int want_xml2 = plug_is_enabled("io_tinycad");

	require("cc/cc", 0, 1);
	require("cc/fpic",  0, 0);

	rnd_hook_detect_cc();
	if (rnd_hook_detect_sys() != 0)
		return 1;

	/* detect inline after fixing up the flags */
	require("cc/inline", 0, 0);

	require("sys/types/size/4_u_int", 0, 1);

	/* yacc/lex - are we able to regenerate languages? */
	if (istrue(get("/local/csch/want_bison"))) {
		require("parsgen/flex/*", 0, 0);
		require("parsgen/bison/*", 0, 0);
		if (!istrue(get("parsgen/flex/presents")) || !istrue(get("parsgen/bison/presents")))
			put("/local/csch/want_parsgen", sfalse);
		else
			put("/local/csch/want_parsgen", strue);
	}
	else {
		report("Bison/flex are disabled, along with parser generation.\n");
		put("/local/csch/want_parsgen", sfalse);
	}

	/* byaccic - are we able to regenerate languages? */
	if (istrue(get("/local/csch/want_byaccic"))) {
		require("parsgen/byaccic/*", 0, 0);
		require("parsgen/ureglex/*", 0, 0);
		if (!istrue(get("parsgen/byaccic/presents")) || !istrue(get("parsgen/ureglex/presents")))
			put("/local/csch/want_parsgen_byaccic", sfalse);
		else
			put("/local/csch/want_parsgen_byaccic", strue);
	}
	else {
		report("byaccic/ureglex are disabled, along with parser generation.\n");
		put("/local/csch/want_parsgen_byaccic", sfalse);
	}

	if (want_xml2) {
		require("libs/sul/libxml2/presents", 0, 0);
		if (!istrue(get("libs/sul/libxml2/presents"))) {
			report("libxml2 is not available, disabling io_tinycad...\n");
			report_repeat("WARNING: Since there's no libxml2 found, disabling the tinycad plugin...\n");
			hook_custom_arg("disable-io_tinycad", NULL);
		}
		put("/local/csch/want_libxml2", strue);
	}
	else
		put("/local/csch/want_libxml2", sfalse);

	return 0;
}

static const char *IS_OK(int *generr, int val)
{
	*generr |= val;
	if (val == 0) return "ok";
	return "ERROR";
}

/* Runs after detection hooks, should generate the output (Makefiles, etc.) */
int hook_generate()
{
	int generr = 0;
	char *tmp, *rev = "non-svn";

	tmp = svn_info(0, "..", "Revision:");
	if (tmp != NULL) {
		rev = str_concat("", "svn r", tmp, NULL);
		free(tmp);
	}

	logprintf(0, "scconfig generate version info: version='%s' rev='%s'\n", version, rev);
	put("/local/revision", rev);
	put("/local/version",  version);

	put("/local/pup/sccbox", "../../scconfig/sccbox");

	printf("Generating src/libcschem/config.h... %s\n", IS_OK(&generr, tmpasm(NULL, "../src/libcschem/config.h.in", "../src/libcschem/config.h")));
	printf("Generating src/libcschem/config.sh... %s\n", IS_OK(&generr, tmpasm(NULL, "../src/libcschem/config.sh.in", "../src/libcschem/config.sh")));
	printf("Generating src/libcschem/Makefile... %s\n", IS_OK(&generr, tmpasm(NULL, "../src/libcschem/Makefile.in", "../src/libcschem/Makefile")));
	printf("Generating src/sch-rnd/Makefile... %s\n", IS_OK(&generr, tmpasm(NULL, "../src/sch-rnd/Makefile.in", "../src/sch-rnd/Makefile")));
	printf("Generating src/sch-rnd/config.h... %s\n", IS_OK(&generr, tmpasm(NULL, "../src/sch-rnd/config.h.in", "../src/sch-rnd/config.h")));
	printf("Generating Makefile.conf... %s\n", IS_OK(&generr, tmpasm(NULL, "../Makefile.conf.in", "../Makefile.conf")));

	if (!generr) {
		printf("\n\n");
		printf("=====================\n");
		printf("Configuration summary\n");
		printf("=====================\n");

		print_sum_setting("/local/csch/debug",          "Compilation for debugging");
		print_sum_setting_or("/local/csch/symbols",     "Include debug symbols", istrue(get("/local/csch/debug")));
		print_sum_cfg_val("/local/prefix",              "installation prefix (--prefix)");
		print_sum_cfg_val("/local/confdir",             "configuration directory (--confdir)");
		print_sum_cfg_val("/local/csch/dot_sch_rnd",    ".sch_rnd config dir under $HOME");

#undef plugin_def
#undef plugin_header
#undef plugin_dep
#define plugin_def(name, desc, default_, all_) plugin3_stat(name, desc)
#define plugin_header(sect) printf(sect);
#define plugin_dep(plg, on)
#include "plugins.h"

		if (all_plugin_check_explicit()) {
			printf("\nNevertheless the configuration is complete, if you accept these differences\nyou can go on compiling.\n\n");
			generr = 1;
		}
		else
			printf("\nConfiguration complete, ready to compile.\n\n");


		{
			FILE *f;
			f = fopen("Rev.stamp", "w");
			fprintf(f, "%d", myrev);
			fclose(f);
		}

	}
	else
		fprintf(stderr, "\nError generating some of the files\n");

	return generr;
}

/* Runs before everything is uninitialized */
void hook_preuninit()
{
}

/* Runs at the very end, when everything is already uninitialized */
void hook_postuninit()
{
}

