/*
 *                            COPYRIGHT
 *
 *  sch-rnd - modular/flexible schematics editor - back annotation parser
 *  Copyright (C) 2022, 2023 Tibor 'Igor2' Palinkas
 *
 *  (Supported by NLnet NGI0 PET Fund in 2022 and Entrust in 2023)
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 *  Contact:
 *    Project page: http://repo.hu/projects/sch-rnd
 *    contact lead developer: http://www.repo.hu/projects/sch-rnd/contact.html
 *    mailing list: http://www.repo.hu/projects/sch-rnd/contact.html
 */

/* Parse line based text formats for back annotation */

#include <libcschem/config.h>

#include <stdio.h>
#include <ctype.h>

#include <librnd/core/safe_fs.h>
#include <librnd/core/compat_misc.h>

static void backann_free_entry(sch_rnd_backann_t *ctx, sch_rnd_ba_t *ba)
{
	free(ba->raw);
	ba->raw = NULL;
	ba->type = SCH_RND_BAT_invalid;
}

static void backann_free_list(sch_rnd_backann_t *ctx)
{
	long n;
	for(n = 0; n < ctx->list.used; n++)
		backann_free_entry(ctx, &ctx->list.array[n]);
	vtba_uninit(&ctx->list);
}

static sch_rnd_ba_t *ba_find_conn_del(sch_rnd_backann_t *ctx, const char *net, const char *comp, const char *term)
{
	long n;
	for(n = 0; n < ctx->list.used; n++) {
		sch_rnd_ba_t *ba = &ctx->list.array[n];
		if (ba->type == SCH_RND_BAT_CONN_DEL) {
			if ((strcmp(net, ba->value.conn_del.net) == 0) && (strcmp(comp, ba->value.conn_del.comp) == 0) && (strcmp(term, ba->value.conn_del.term) == 0))
				return ba;
		}
	}
	return NULL;
}

static void backann_postproc(sch_rnd_backann_t *ctx)
{
	long n;
	for(n = 0; n < ctx->list.used; n++) {
		sch_rnd_ba_t *ba = &ctx->list.array[n];
		ba->optional = 0;
		if (ba->type != SCH_RND_BAT_NETINFO) continue;
		if (ba_find_conn_del(ctx, ba->value.netinfo.net, ba->value.netinfo.comp, ba->value.netinfo.term) != NULL)
			ba->optional = 1;
	}
}

#include "parse_bap.c"
#include "parse_tedax.c"

typedef enum {
	FT_UNKNOWN,
	FT_BAP,
	FT_TEDAX
} file_type_t;

static int backann_parse(sch_rnd_backann_t *ctx)
{
	FILE *f;
	char *line, buff[1024];
	long lineno = 0;
	int err = 0;
	file_type_t ft = FT_UNKNOWN;
	tedax_backann_t tdx = {0};

	f = rnd_fopen(&ctx->sheet->hidlib, ctx->fn, "r");
	if (f == NULL) {
		rnd_message(RND_MSG_ERROR, "Failed to open back annotation pack '%s'\n", ctx->fn);
		return -1;
	}

	while((line = fgets(buff, sizeof(buff), f)) != NULL) {
		lineno++;
		while(isspace(*line)) line++;
		if ((*line == '#') || (*line == '\0')) continue;

		switch(ft) {
			case FT_UNKNOWN:
				if ((strncmp(line, "tEDAx", 5) == 0) && (isspace(line[5]))) {
					char *ver = line+5;
					while(isspace(*ver)) ver++;
					if (*ver != 'v') {
						rnd_message(RND_MSG_ERROR, "backann tEDAx: invalid version tag '%s' in %s:%ld\n", ver, ctx->fn, lineno);
						err = 1;
						break;
					}
					ver++;
					if (atoi(ver) != 1) {
						rnd_message(RND_MSG_ERROR, "backann tEDAx: invalid version number '%s' in %s:%ld\n", ver, ctx->fn, lineno);
						err = 1;
						break;
					}
					ft = FT_TEDAX;
					break; /* parse from the next line */
				}
				ft = FT_BAP;
				/* fall through: first line of a bap (unfortunately has no header) */
			case FT_BAP:
				err |= backann_parse_bap(ctx, line, lineno);
				break;
			case FT_TEDAX:
				err |= backann_parse_tedax(ctx, &tdx, line, lineno);
				break;
		}

		if (err)
			break;
	}

	fclose(f);

	if (err)
		backann_free_list(ctx);
	else
		backann_postproc(ctx);

	return err;
}
