/*
 *                            COPYRIGHT
 *
 *  sch-rnd - modular/flexible schematics editor - Easyeda netlist export
 *  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/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
 */


#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <librnd/core/compat_misc.h>
#include <librnd/core/safe_fs.h>
#include <librnd/core/plugins.h>
#include <librnd/core/error.h>
#include <libcschem/config.h>
#include <libcschem/plug_io.h>

#include <plugins/lib_netlist_exp/lib_netlist_exp.h>

static csch_plug_io_t eeasyeda_net;

static int easyeda_export_prio(const char *fn, const char *fmt, csch_plug_io_type_t type)
{
	if (type != CSCH_IOTYP_NETLIST)
		return 0;
	if (rnd_strcasecmp(fmt, "easyeda") == 0)
		return 100;
	return 0;
}

/* Write a single attribute to f */
static void export_attr(FILE *f, const char *key, const char *val)
{
	if ((key == NULL) || (val == NULL))
		return;
	fprintf(f, ",\n    \"%s\": \"%s\"", key, val);
}

#define IGNORE_COMP_KEY(key) \
	((rnd_strcasecmp(key, "value") == 0) || (rnd_strcasecmp(key, "footprint") == 0) || (rnd_strcasecmp(key, "name") == 0))

/* Export attributes as properites, with special handling (translation) of the
   hardwired ones like FootprintName */
static void export_comp_attrs(FILE *f, csch_ahdr_t *obj, const char *refdes, const char *fp, const char *val, const char *uid)
{
	htsp_entry_t *e;

	fprintf(f, "  \"props\": {");
	fprintf(f, "\n    \"Designator\": \"%s\"", refdes);
	fprintf(f, ",\n    \"Unique ID\": \"%s\"", uid);
	if (fp != NULL)
		fprintf(f, ",\n    \"FootprintName\": \"%s\"", fp);
	if (val != NULL)
		fprintf(f, ",\n    \"Value\": \"%s\"", val);
	for(e = htsp_first(&obj->attr); e != NULL; e = htsp_next(&obj->attr, e)) {
		csch_attrib_t *a = e->value;
		if ((a->export_name != NULL) && (a->val != NULL) && (!IGNORE_COMP_KEY(a->export_name))) {
			export_attr(f, a->export_name, a->val);
		}
	}
	fprintf(f, "\n  },\n");
}

/* Export abstract components; nets are exported as an attachment for
   each pin, so there's only a component list, no list of nets */
static void easyeda_export_comps(FILE *f, csch_abstract_t *abs)
{
	htsp_entry_t *e, *p;
	long UID;
	int need_ccomma = 0;

	for(e = htsp_first(&abs->comps), UID = 0; e != NULL; e = htsp_next(&abs->comps, e)) {
		csch_acomp_t *comp = e->value;
		const char *refdes = sch_nle_get_refdes(comp);
		const char *fp, *val;
		char uid[64];
		int need_comma = 0;

		if (refdes == NULL)
			continue;

		if (comp->hdr.omit)
			continue;

		UID++;
		sprintf(uid, "gge%ld", UID);

		/* Get main symbol attributes the safe way, considering alternate names;
		   these should be always exported and are usually hardwiared in the
		   netlist format. */
		fp = sch_nle_get_alt_attr(&comp->hdr.attr, SCH_NLE_ALTATTR_FOOTPRINT);
		val = sch_nle_get_alt_attr(&comp->hdr.attr, SCH_NLE_ALTATTR_VALUE);
		/* dev = sch_nle_get_alt_attr(&comp->hdr.attr, SCH_NLE_ALTATTR_DEVICE); no special property of this exists in this format */

		if (need_ccomma)
			fprintf(f, ",\n");
		else
			fprintf(f, "\n");


		fprintf(f, " \"%s\": {\n", uid);
		export_comp_attrs(f, &comp->hdr, refdes, fp, val, uid);
		fprintf(f, "  \"pins\": {");

		/* Print terminals so that terminal symbolic names can be preserved.
		   (The netlist uses pin number to reference the terminal, symbolic name
		   is just an useful hint) */
		for(p = htsp_first(&comp->ports); p != NULL; p = htsp_next(&comp->ports, p)) {
			const csch_aport_t *port = p->value;
			const char *pinnums = sch_nle_get_pinnum(port);
			const char *pinname = sch_nle_get_alt_attr(&port->hdr.attr, SCH_NLE_ALTATTR_PINNAME);


			if (pinname == NULL)
				continue;

			/* call export_attr on each pin in pinnums (which can be a list of
			   pin numbers) so that each pinnum -> pinname is written */
			SCH_NLE_FOREACH_PINNUM(pinnums, my_num,
				{
					csch_anet_t *anet = port->conn.net;
					const char *netname = (anet == NULL ? "" : anet->name);

					if (need_comma)
						fprintf(f, ",\n");
					else
						fprintf(f, "\n");

					fprintf(f, "   \"%s\" : \"%s\"", my_num, netname);
					need_comma = 1;
				}
			);
		}
		fprintf(f, "\n  }\n");
		fprintf(f, " }");
		need_ccomma = 1;
	}

}

/* Export netlist from the abstract model */
static int easyeda_export_project_abst(const char *fn, const char *fmt, csch_abstract_t *abs, rnd_hid_attr_val_t *options)
{
	TODO("get hidlib as an arg")
	rnd_design_t *hidlib = NULL;
	FILE *f = rnd_fopen(hidlib, fn, "w");
	if (f == NULL)
		return -1;

	fprintf(f, "{");

	easyeda_export_comps(f, abs);

	fprintf(f, "\n}\n");

	fclose(f);
	return 0;
}

#include "hid_impl.c"

int pplg_check_ver_export_easyeda(int ver_needed) { return 0; }

void pplg_uninit_export_easyeda(void)
{
	csch_plug_io_unregister(&eeasyeda_net);
	rnd_export_remove_opts_by_cookie(easyeda_cookie);
	rnd_hid_remove_hid(&easyeda_hid);
}

int pplg_init_export_easyeda(void)
{
	RND_API_CHK_VER;

	eeasyeda_net.name = "export to Easyeda";
	eeasyeda_net.export_prio = easyeda_export_prio;
	eeasyeda_net.export_project_abst = easyeda_export_project_abst;
	eeasyeda_net.ext_export_project = ".enet";
	csch_plug_io_register(&eeasyeda_net);


	rnd_hid_nogui_init(&easyeda_hid);

	easyeda_hid.struct_size = sizeof(rnd_hid_t);
	easyeda_hid.name = "easyeda";
	easyeda_hid.description = "Exports project's Easyeda netlist";
	easyeda_hid.exporter = 1;

	easyeda_hid.get_export_options = easyeda_get_export_options;
	easyeda_hid.do_export = easyeda_do_export;
	easyeda_hid.parse_arguments = easyeda_parse_arguments;
	easyeda_hid.argument_array = easyeda_values;

	easyeda_hid.usage = easyeda_usage;

	rnd_hid_register_hid(&easyeda_hid);
	rnd_hid_load_defaults(&easyeda_hid, easyeda_options, NUM_OPTIONS);


	return 0;
}

