/*
 *                            COPYRIGHT
 *
 *  cschem - 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 tEDAx backann blocks; included from the common line parser */

#include <plugins/lib_tedax/parse.h>

typedef struct {
	int ver;
} tedax_backann_t;

static int tedax_parse_net_info(sch_rnd_backann_t *ctx, tedax_backann_t *tdx, char *raw, int argc, char *argv[], int lineno)
{
	sch_rnd_ba_t *ba = vtba_alloc_append(&ctx->list, 1);

	if (argc != 4) {
		rnd_message(RND_MSG_ERROR, "backann tEDAx: syntax error: wrong number of arguments for %s %s:%ld\n", argv[0], ctx->fn, lineno);
		return -1;
	}

	ba->type = SCH_RND_BAT_NETINFO;
	ba->raw = raw;
	ba->value.netinfo.net = argv[1];
	ba->value.netinfo.comp = argv[2];
	ba->value.netinfo.term = argv[3];

	return 0;
}

static int tedax_parse_add_del_conn(sch_rnd_backann_t *ctx, tedax_backann_t *tdx, char *raw, int argc, char *argv[], int lineno)
{
	sch_rnd_ba_t *ba = vtba_alloc_append(&ctx->list, 1);

	if (argc != 4) {
		rnd_message(RND_MSG_ERROR, "backann tEDAx: syntax error: wrong number of arguments for %s %s:%ld\n", argv[0], ctx->fn, lineno);
		return -1;
	}

	ba->type = (*(argv[0]) == 'a') ? SCH_RND_BAT_CONN_ADD : SCH_RND_BAT_CONN_DEL;
	ba->raw = raw;
	ba->value.conn_add.net = argv[1];
	ba->value.conn_add.comp = argv[2];
	ba->value.conn_add.term = argv[3];

	return 0;
}

static int tedax_parse_attr_conn(sch_rnd_backann_t *ctx, tedax_backann_t *tdx, char *raw, int argc, char *argv[], int lineno)
{
	sch_rnd_ba_t *ba = vtba_alloc_append(&ctx->list, 1);

	if ((argc != 3) && (argc != 4)) {
		rnd_message(RND_MSG_ERROR, "backann tEDAx: syntax error: wrong number of arguments for %s %s:%ld\n", argv[0], ctx->fn, lineno);
		return -1;
	}

	ba->type = SCH_RND_BAT_NET_ATTR;
	ba->raw = raw;
	ba->value.net_attr.net = argv[1];
	ba->value.net_attr.key = argv[2];
	ba->value.net_attr.val = argv[3];

	return 0;
}

static int tedax_parse_add_del_comp(sch_rnd_backann_t *ctx, tedax_backann_t *tdx, char *raw, int argc, char *argv[], int lineno)
{
	sch_rnd_ba_t *ba = vtba_alloc_append(&ctx->list, 1);

	if (tdx->ver < 2)
		rnd_message(RND_MSG_ERROR, "backann tEDAx: component add/del did not exist in backann v1 in %s:%ld\n", ctx->fn, lineno);

	if (argc != 2) {
		rnd_message(RND_MSG_ERROR, "backann tEDAx: syntax error: wrong number of arguments for %s %s:%ld\n", argv[0], ctx->fn, lineno);
		return -1;
	}

	ba->type = (*(argv[0]) == 'a') ? SCH_RND_BAT_COMP_ADD : SCH_RND_BAT_COMP_DEL;
	ba->raw = raw;
	ba->value.comp_add.comp = argv[1];
	return 0;
}

static int tedax_parse_attr_comp(sch_rnd_backann_t *ctx, tedax_backann_t *tdx, char *raw, int argc, char *argv[], int lineno)
{
	sch_rnd_ba_t *ba = vtba_alloc_append(&ctx->list, 1);

	if ((argc != 3) && (argc != 4)) {
		rnd_message(RND_MSG_ERROR, "backann tEDAx: syntax error: wrong number of arguments for %s %s:%ld\n", argv[0], ctx->fn, lineno);
		return -1;
	}

	ba->type = SCH_RND_BAT_COMP_ATTR;
	ba->raw = raw;
	ba->value.comp_attr.comp = argv[1];
	ba->value.comp_attr.key = argv[2];
	ba->value.comp_attr.val = argv[3];

	return 0;
}

static int tedax_parse_attr_pin(sch_rnd_backann_t *ctx, tedax_backann_t *tdx, char *raw, int argc, char *argv[], int lineno)
{
	sch_rnd_ba_t *ba = vtba_alloc_append(&ctx->list, 1);

	if ((argc != 4) && (argc != 5)) {
		rnd_message(RND_MSG_ERROR, "backann tEDAx: syntax error: wrong number of arguments for %s %s:%ld\n", argv[0], ctx->fn, lineno);
		return -1;
	}

	ba->type = SCH_RND_BAT_TERM_ATTR;
	ba->raw = raw;
	ba->value.term_attr.comp = argv[1];
	ba->value.term_attr.term = argv[2];
	ba->value.term_attr.key = argv[3];
	ba->value.term_attr.val = argv[4];

	return 0;
}




static int backann_parse_tedax(sch_rnd_backann_t *ctx, tedax_backann_t *tdx, char *line, int lineno)
{
	char *tmp, *argv[16], *vers;
	int argc, len;

	len = strlen(line)+1;
	tmp = malloc(len);

	memset(argv, 0, sizeof(argv));
	argc = tedax_getline_mem(&line, tmp, len, argv, sizeof(argv)/sizeof(argv[0]));
	if (argc < 0) {
		rnd_message(RND_MSG_ERROR, "backann tEDAx: failed to tokenize in %s:%ld\n", ctx->fn, lineno);
		goto error;
	}

	switch(backann_bap_sphash(argv[0])) {
		case backann_bap_begin:
			if (strcmp(argv[1], "backann") != 0)  {
				rnd_message(RND_MSG_ERROR, "backann tEDAx: wrong block '%s'; expected backann %s:%ld\n", argv[1], ctx->fn, lineno);
				goto error;
			}
			vers = argv[2];
			tdx->ver = atoi(vers+1);
			if (*vers != 'v') {
				rnd_message(RND_MSG_ERROR, "backann tEDAx: wrong block version; expected backann %s:%ld\n", ctx->fn, lineno);
				goto error;
			}
			free(tmp);
			return 0;
		case backann_bap_end:           free(tmp); return 0;
		case backann_bap_net_info:      return tedax_parse_net_info(ctx, tdx, tmp, argc, argv, lineno);
		case backann_bap_add_conn:      return tedax_parse_add_del_conn(ctx, tdx, tmp, argc, argv, lineno);
		case backann_bap_del_conn:      return tedax_parse_add_del_conn(ctx, tdx, tmp, argc, argv, lineno);
		case backann_bap_attr_conn:     return tedax_parse_attr_conn(ctx, tdx, tmp, argc, argv, lineno);
		case backann_bap_add_comp:      return tedax_parse_add_del_comp(ctx, tdx, tmp, argc, argv, lineno);
		case backann_bap_del_comp:      return tedax_parse_add_del_comp(ctx, tdx, tmp, argc, argv, lineno);
		case backann_bap_attr_comp:     return tedax_parse_attr_comp(ctx, tdx, tmp, argc, argv, lineno);
		case backann_bap_fattr_comp:    return tedax_parse_attr_comp(ctx, tdx, tmp, argc, argv, lineno);
		case backann_bap_attr_pin:      return tedax_parse_attr_pin(ctx, tdx, tmp, argc, argv, lineno);
		default:
			rnd_message(RND_MSG_ERROR, "backann tEDAx: invalid instruction '%s' %s:%ld\n", argv[0], ctx->fn, lineno);
			goto error;
	}

	return 0;

	error:;
	free(tmp);
	return 1;
}
