/*
 *                            COPYRIGHT
 *
 *  sch-rnd - modular/flexible schematics editor - suite level features
 *  Copyright (C) 2025 Tibor 'Igor2' Palinkas
 *
 *  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., 31 Milk Street, # 960789 Boston, MA 02196 USA.
 *
 *  Contact:
 *    Project page: http://repo.hu/projects/pcb-rnd
 *    lead developer: http://repo.hu/projects/pcb-rnd/contact.html
 *    mailing list: pcb-rnd (at) list.repo.hu (send "subscribe")
 */



/* Hash table for export-name to abstract object */
#define HT_HAS_CONST_KEY
typedef struct htea_key_s {
	csch_atype_t type;
	const char *name1; /* name of a component or net */
	const char *name2; /* name of a terminal (only for terminals) */
} htea_key_t;
typedef const htea_key_t htea_const_key_t;
typedef csch_ahdr_t *htea_value_t;
#define HT(x) htea_ ## x
#include <genht/ht.h>
#include <genht/ht.c>
#undef HT

static unsigned htea_keyhash(const htea_key_t key)
{
	unsigned t = key.type;
	unsigned n1 = strhash(key.name1);
	unsigned n2 = key.name2 == NULL ? 0 : strhash(key.name2);
	return jenhash32(t) ^ n1 ^ n2;
}

static int htea_keyeq(const htea_key_t k1, const htea_key_t k2)
{
	if (k1.type != k2.type) return 0;
	if (strcmp(k1.name1, k2.name1) != 0) return 0;
	if ((k1.name2 == NULL) && (k2.name2 != NULL)) return 0;
	if ((k1.name2 != NULL) && (k2.name2 == NULL)) return 0;
	if ((k1.name2 != NULL) && (strcmp(k1.name2, k2.name2) != 0)) return 0;
	return 1;
}

static csch_abstract_t *abst_cache_abstract;
static long abst_cache_comp_cnt;
static int abst_cache_inited;
static htea_t abst_cache;

static void abst_cache_clear(void)
{
	htea_clear(&abst_cache);
}

static void abst_cache_fill(void)
{
	htsp_entry_t *e, *ep;
	csch_abstract_t *abst = abst_cache_abstract;
	
	for(e = htsp_first(&abst->comps); e != NULL; e = htsp_next(&abst->comps, e)) {
		csch_acomp_t *c = e->value;
		htea_key_t key;

		key.type = CSCH_ATYPE_COMP;
		key.name1 = sch_nle_get_refdes(c);
		key.name2 = NULL;

		if (key.name1 == NULL)
			continue;

		htea_set(&abst_cache, key, &c->hdr);

		/* also add all ports */
		key.type = CSCH_ATYPE_PORT;
		for(ep = htsp_first(&c->ports); ep != NULL; ep = htsp_next(&c->ports, ep)) {
			csch_aport_t *p = ep->value;

			key.name2 = sch_nle_get_pinnum(p);

			if (key.name2 != NULL)
				htea_set(&abst_cache, key, &p->hdr);
		}
	}

	for(e = htsp_first(&abst->nets); e != NULL; e = htsp_next(&abst->nets, e)) {
		csch_anet_t *n = e->value;
		htea_key_t key;

		key.type = CSCH_ATYPE_NET;
		key.name1 = sch_nle_get_netname(n);
		key.name2 = NULL;

		if (key.name1 != NULL)
			htea_set(&abst_cache, key, &n->hdr);
	}
}


static void abst_cache_init(void)
{
	htea_init(&abst_cache, htea_keyhash, htea_keyeq);
	abst_cache_inited = 1;
}

static void abst_cache_uninit(void)
{
	if (abst_cache_inited) {
		htea_uninit(&abst_cache);
		abst_cache_inited = 0;
	}
	abst_cache_abstract = NULL;
	abst_cache_comp_cnt = -1;
}




static void abst_cache_update(csch_abstract_t *abst)
{
	if ((abst_cache_abstract != abst) || (abst_cache_comp_cnt != abst->comp_cnt)) {
		if (!abst_cache_inited)
			abst_cache_init();
		abst_cache_clear();
		abst_cache_abstract = abst;
		abst_cache_comp_cnt = abst->comp_cnt;
		abst_cache_fill();
	}
}

