#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "libs.h"
#include "log.h"
#include "db.h"

static int try_icl_(int logdepth, const char *prefix, const char *test_c_in, const char *includes, const char *cflags, const char *ldflags, int run)
{
	char *out = NULL;
	char *tmp, *inc;
	const char *test_c;
	char c[1024];
	int l, compres;

	if (includes != NULL) {
		l = strlen(includes);
		memcpy(c, includes, l);
		c[l] = '\n';
		l++;
		strcpy(c+l, test_c_in);
		test_c = c;
	}
	else
		test_c = test_c_in;

	logprintf(logdepth, "trying '%s' and '%s' and '%s', %s\n", str_null(includes), str_null(cflags), str_null(ldflags), run ? "with a run" : "with no run");

	if (run)
		compres = compile_run(logdepth+1, test_c, NULL, cflags, ldflags, &out);
	else {
		char *fn_output = NULL;
		compres = compile_code(logdepth+1, test_c, &fn_output, NULL, cflags, ldflags);
		if (fn_output != NULL) {
			unlink(fn_output);
			free(fn_output);
		}
	}


	if (compres == 0) {
		if (!run || target_emu_fail(out) || (strncmp(out, "OK", 2) == 0)) {
			free(out);

			/* no prefix: don't modify the database, the caller will do that */
			if (prefix == NULL)
				return 1;

			if ((cflags != NULL) && (*cflags == '+'))
				cflags++;
			if ((ldflags != NULL) && (*ldflags == '+'))
				ldflags++;

			tmp = malloc(strlen(prefix) + 32);

			if (includes != NULL) {
				if (*includes == '\0')
					inc = strclone("");
				else
					inc = uniq_inc_str(includes, NULL, "\\n", 0);
				sprintf(tmp, "%s/includes", prefix);
				put(tmp, inc);
			}
			else
				inc = NULL;

			if (cflags != NULL) {
				sprintf(tmp, "%s/cflags", prefix);
				if (*cflags == '+')
					put(tmp, cflags+1);
				else
					put(tmp, cflags);
			}

			if (ldflags != NULL) {
				sprintf(tmp, "%s/ldflags", prefix);
				if (*ldflags == '+')
					put(tmp, ldflags+1);
				else
					put(tmp, ldflags);
			}

			if (inc != NULL) {
				report("OK ('%s', '%s' and '%s')\n", str_null(inc), str_null(cflags), str_null(ldflags));
				free(inc);
			}
			else
				report("OK ('%s' and '%s')\n", str_null(cflags), str_null(ldflags));

			sprintf(tmp, "%s/presents", prefix);
			put(tmp, strue);
			free(tmp);
			return 1;
		}
		free(out);
	}
	return 0;
}

int try_icl(int logdepth, const char *prefix, const char *test_c_in, const char *includes, const char *cflags, const char *ldflags)
{
	return try_icl_(logdepth, prefix, test_c_in, includes, cflags, ldflags, 1);
}

int try_icl_norun(int logdepth, const char *prefix, const char *test_c_in, const char *includes, const char *cflags, const char *ldflags)
{
	return try_icl_(logdepth, prefix, test_c_in, includes, cflags, ldflags, 0);
}


int try_fail(int logdepth, const char *prefix)
{
	char *tmp;
	tmp = malloc(strlen(prefix) + 32);
	sprintf(tmp, "%s/presents", prefix);
	put(tmp, sfalse);
	free(tmp);
	report("not found\n");
	logprintf(logdepth, "NOT FOUND.");
	return 1;
}

static int try_pkg_config_(int logdepth, char *pkgname, const char *prefix, const char *test_c)
{
	char *cflags, *ldflags;
	int res;

	logprintf(logdepth, "Trying pkg-config %s\n", pkgname);
	if (run_pkg_config(logdepth+1, pkgname, &cflags, &ldflags) == 0)
		res = try_icl(logdepth+1, prefix, test_c, NULL, cflags, ldflags);
	else
		res = 0;
	free(cflags);
	free(ldflags);

	return res;
}

int try_icl_pkg_config(int logdepth, const char *prefix, const char *test_c, char *includes, const char *pkgpat, const char *reqver)
{
	char **pkg_ver, **s;
	int num_pkg_ver;
	int res;
	(void) includes;  /* not used */

	run_pkg_config_lst(logdepth, pkgpat, &num_pkg_ver, &pkg_ver);
	if (pkg_ver == NULL)
		return 0;

	if (reqver != NULL) {
		/* search the list for the preferred version */
		for(s = pkg_ver; *s != NULL; s+=2) {
			if (strcmp(s[1], reqver) == 0) {
				if (try_pkg_config_(logdepth, s[0], prefix, test_c)) {
					res = 1;
					report("Found version required (%s) using pkg_config.\n", reqver);
					goto out;
				}
				else {
					report("The version required (%s) is found (via pkg_config) but does not work\n", reqver);
					goto out;
				}
			}
		}
		goto out;
	}

	for(s = pkg_ver; *s != NULL; s+=2) {
		if (try_pkg_config_(logdepth, s[0], prefix, test_c)) {
			res = 1;
			goto out;
		}
	}

out:;
	filelist_free(&num_pkg_ver, &pkg_ver);
	return res;
}

