/*
 *                            COPYRIGHT
 *
 *  sch-rnd - modular/flexible schematics editor - gEDA file format support
 *  Copyright (C) 2022..2024 Tibor 'Igor2' Palinkas
 *
 *  (Supported by NLnet NGI0 PET Fund in 2022, 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
 */

/*** post processing - fixups after load; #included from read.c ***/

/* Look up terminals for net_pinname (which is really a pin number) and
   make an attribute based connection to neta for each terminal that matches.
   Returns whether any connection is made */
static int postproc_sym_net_by_pinname(read_ctx_t *ctx, csch_cgrp_t *sym, gds_t *tmp, const char *neta, int neta_len, const char *net_pinname)
{
	htip_entry_t *e;
	int found = 0;

	/* look up pin name for pin number and bind */
	for(e = htip_first(&sym->id2obj); e != NULL; e = htip_next(&sym->id2obj, e)) {
		csch_cgrp_t *t = e->value;
		const char *pinnum;

		if (!csch_obj_is_grp(&t->hdr) || (t->role != CSCH_ROLE_TERMINAL))
			continue;

		pinnum = csch_attrib_get_str(&t->attr, "pinnumber");

/*		rnd_trace("  term pin: '%s' target '%s'\n", pinnum, net_pinname);*/
		if ((pinnum != NULL) && (net_pinname != NULL) && (strcmp(pinnum, net_pinname) == 0)) {
			csch_source_arg_t *src;

			tmp->used = 0;
			gds_append_str(tmp, pinnum);
			gds_append(tmp, ':');
			gds_append_len(tmp, neta, neta_len);

			src = csch_attrib_src_c(ctx->fn, 0, 0, NULL);
			csch_attrib_append(&sym->attr, CSCH_ATP_USER_DEFAULT, "connect", tmp->array, src);
			found = 1;
/*			rnd_trace("    found! append '%s'\n", tmp->array, res); */
		}
	}

	return found;
}

static void postproc_sym_net_from_str(read_ctx_t *ctx, csch_cgrp_t *sym, gds_t *tmp, const char *refdes, const char *neta)
{
	char *sep, *net_pinname;

	/* figure net_pinname */
	sep = strchr(neta, ':');
	if (sep == NULL) {
		rnd_message(RND_MSG_ERROR, "Invalid net attrib '%s' on sym '%s' (missing colon)\n", neta, refdes);
		return;
	}
	net_pinname = sep+1;

/*	rnd_trace("neta='%s'\n", neta);*/
	if (postproc_sym_net_by_pinname(ctx, sym, tmp, neta, sep-neta, net_pinname) == 0) {
		/* terminal not found by pinnum: assume implicit pin connection */
		csch_source_arg_t *src;

		tmp->used = 0;
		gds_append_str(tmp, net_pinname);
		gds_append(tmp, ':');
		gds_append_len(tmp, neta, sep-neta);

		src = csch_attrib_src_c(ctx->fn, 0, 0, NULL);
		csch_attrib_append(&sym->attr, CSCH_ATP_USER_DEFAULT, "connect", tmp->array, src);
	}
}

/* convert geda net= attribute to sch-rnd connect= attribute on a symbol;
   geda net attrib is net=netname:pinnumber */
static void postproc_sym_net(read_ctx_t *ctx, csch_cgrp_t *sym, gds_t *tmp)
{
	const char *refdes;
	csch_attrib_t *a = csch_attrib_get(&sym->attr, "net");

	if (a == NULL)
		return;

	refdes = csch_attrib_get_str(&sym->attr, "refdes");
	if (refdes == NULL) refdes = "<no refdes>";

	if ((a->val == NULL) && (a->arr.used > 0)) {
		long n;
		for(n = 0; n < a->arr.used; n++)
			postproc_sym_net_from_str(ctx, sym, tmp, refdes, a->arr.array[n]);
	}
	else
		postproc_sym_net_from_str(ctx, sym, tmp, refdes, a->val);
}

/* On each symbol (runs before configured/flexible/user postproc):
    - recalc conns so terminal-terminal connections are established
    - convert geda net= attribute to sch-rnd connect= attribute
*/
static void postproc_symbols(read_ctx_t *ctx)
{
	htip_entry_t *e;
	vtp0_t syms = {0};
	gds_t tmp = {0};
	long n;

	/* first collect all syms; can't do the actual job here becuase it may modify
	   the hash */
	for(e = htip_first(&ctx->sheet->direct.id2obj); e != NULL; e = htip_next(&ctx->sheet->direct.id2obj, e)) {
		csch_chdr_t *o = e->value;
		if (csch_obj_is_grp(o) && (((csch_cgrp_t *)o)->role == CSCH_ROLE_SYMBOL))
			vtp0_append(&syms, o);
	}

	/* recalc conns on all collected symbols */
	for(n = 0; n < syms.used; n++) {
		postproc_sym_net(ctx, syms.array[n], &tmp);
		csch_conn_auto_recalc(ctx->sheet, syms.array[n]);
	}

	vtp0_uninit(&syms);
	gds_uninit(&tmp);
}
