/*
 *  tslib/src/ts_config_filter.c
 *
 *  Copyright (C) 2018 Martin Kepplinger.
 *
 * This file is placed under the LGPL.  Please see the file
 * COPYING for more details.
 *
 * SPDX-License-Identifier: LGPL-2.1
 *
 *
 * Interface for editing ts.conf. This edits "module" filters, not
 * "module_raw" access plugins.
 */
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include "tslib-private.h"

#define MAX_LINES	200
#define LINE_MAX	1024

/* return a ordered list of structs. Each struct is one commented-in module */
static struct ts_module_conf *get_first(struct ts_module_conf *conf)
{
	struct ts_module_conf *conf_first = NULL;

	while (conf) {
		if (!conf->prev)
			conf_first = conf;

		conf = conf->prev;
	}
	conf = conf_first;

	return conf;
}

struct ts_module_conf *ts_conf_get(struct tsdev *ts)
{
	struct ts_module_conf *conf = NULL;
	struct ts_module_conf *conf_next = NULL;
	char **modulebuf = NULL;
	char **parambuf = NULL;
	int *raw = NULL;
	int ret;
	int i;
	int nr = 0;

	modulebuf = calloc(MAX_LINES, sizeof(char *));
	if (!modulebuf)
		goto fail;

	parambuf = calloc(MAX_LINES, sizeof(char *));
	if (!parambuf)
		goto fail;

	raw = calloc(MAX_LINES, sizeof(int));
	if (!raw)
		goto fail;

	for (i = 0; i < MAX_LINES; i++) {
		modulebuf[i] = calloc(1, LINE_MAX);
		if (!modulebuf[i])
			goto fail;

		parambuf[i] = calloc(1, LINE_MAX);
		if (!parambuf[i])
			goto fail;
	}

	ret = ts_config_ro(ts, modulebuf, parambuf, raw);
	if (ret)
		goto fail;

	for (i = 0; i < MAX_LINES; i++) {
		if (!modulebuf[i][0])
			continue;
	#ifdef DEBUG
		printf("ts_conf_get: module found at line %d\n", i);
	#endif

		conf_next = calloc(1, sizeof(struct ts_module_conf));
		if (!conf_next)
			goto fail;

		conf_next->name = calloc(1, LINE_MAX);
		if (!conf_next->name)
			goto fail;

		sprintf(conf_next->name, "%s", modulebuf[i]);

		conf_next->params = calloc(1, LINE_MAX);
		if (!conf_next->params)
			goto fail;

		sprintf(conf_next->params, "%s", parambuf[i]);

		conf_next->raw = raw[i];

		if (conf) {
			conf_next->prev = conf;
			conf->next = conf_next;
		}
		conf_next->nr = nr;
		nr++;

		conf = conf_next;
		conf_next = NULL;
	}

	for (i = 0; i < MAX_LINES; i++) {
		free(modulebuf[i]);
		free(parambuf[i]);
	}
	free(modulebuf);
	free(parambuf);
	free(raw);

	return get_first(conf);

fail:
	for (i = 0; i < MAX_LINES; i++) {
		if (modulebuf)
			free(modulebuf[i]);
		if (parambuf)
			free(parambuf[i]);
	}

	free(modulebuf);
	free(parambuf);
	free(raw);

	return NULL;
}

int ts_conf_set(struct ts_module_conf *conf)
{
	FILE *f;
	short strdup_allocated = 0;
	char *conffile;
	struct ts_module_conf *conf_next = NULL;

	if (!conf) {
		ts_error("Nothing to write\n");
		return -1;
	}

	if ((conffile = getenv("TSLIB_CONFFILE")) == NULL) {
		conffile = strdup(TS_CONF);
		if (conffile) {
			strdup_allocated = 1;
		} else {
			ts_error("Couldn't find tslib config file: %s\n",
				strerror(errno));
			return -1;
		}
	}

#ifdef DEBUG
	printf("writing %s\n", conffile);
#endif
	f = fopen(conffile, "w");
	if (!f) {
		if (strdup_allocated)
			free(conffile);

		ts_error("Couldn't open tslib config file: %s\n",
				strerror(errno));
		return -1;
	}

	if (strdup_allocated)
		free(conffile);

	fprintf(f, "# generated by libts\n");

	conf = get_first(conf);

	/* write the module_raw first */
	while (conf) {
		if (conf->raw) {
			fprintf(f, "module_raw %s %s\n", conf->name, conf->params);
			break;
		}
		conf = conf->next;
	}

	while (conf) {
		if (!conf->raw)
			fprintf(f, "module %s %s\n", conf->name, conf->params);
		conf = conf->next;
	}

	fclose(f);

	conf = get_first(conf);
	while (conf) {
		free(conf->name);
		free(conf->params);
		conf_next = conf->next;
		free(conf);
		conf = conf_next;
	}

	return 0;
}
