/*
 *                            COPYRIGHT
 *
 *  sch-rnd - modular/flexible schematics editor - export the abstract model
 *  Copyright (C) 2020 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 <stdarg.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 <libcschem/util_export.h>

static csch_plug_io_t eabst;

static int abst_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, "abst") == 0) || (rnd_strcasecmp(fmt, "abstract") == 0))
		return 100;
	if (rnd_strcasecmp(fmt, "txt") == 0)
		return 50;
	return 0;
}

#include "hid_impl.c"

static void abst_export_attrs(FILE *f, csch_ahdr_t *obj, const char *ind)
{
	htsp_entry_t *e;

	fprintf(f, "%sattributes\n", ind);
	for(e = htsp_first(&obj->attr); e != NULL; e = htsp_next(&obj->attr, e)) {
		csch_attrib_t *a = e->value;
		if (a->val == NULL) {
			long n;
			fprintf(f, "%s %s []\n", ind, a->key);
			for(n = 0; n < a->arr.used; n++)
			fprintf(f, "%s  %s\n", ind, a->arr.array[n]);
		}
		else
			fprintf(f, "%s %s=%s\n", ind, a->key, a->val);

	}
}

static void abst_export_comps(FILE *f, csch_abstract_t *abs)
{
	htsp_entry_t *e, *p;
	fprintf(f, "components\n");
	for(e = htsp_first(&abs->comps); e != NULL; e = htsp_next(&abs->comps, e)) {
		csch_acomp_t *comp = e->value;
	
		if (comp->hdr.ghost && !abst_values[HA_ghost].lng)
			continue;
	
		fprintf(f, " %s\n", comp->name);
		if (comp->hdr.ghost)
			fprintf(f, "  GHOST\n");
		if (comp->hdr.omit)
			fprintf(f, "  OMIT\n");

		if (abst_values[HA_comp_attrs].lng)
			abst_export_attrs(f, &comp->hdr, "  ");

		fprintf(f, "  ports\n");
		for(p = htsp_first(&comp->ports); p != NULL; p = htsp_next(&comp->ports, p)) {
			csch_aport_t *port = p->value;
			fprintf(f, "   %s\n", p->key);
			if (abst_values[HA_port_attrs].lng)
				abst_export_attrs(f, &port->hdr, "    ");
		}
		TODO("bus: export bus ports");
	}
}

static void abst_export_nets(FILE *f, csch_abstract_t *abs)
{
	htsp_entry_t *e;
	long n;

	fprintf(f, "nets\n");
	for(e = htsp_first(&abs->nets); e != NULL; e = htsp_next(&abs->nets, e)) {
		csch_anet_t *net = e->value;

		if (net->hdr.ghost && !abst_values[HA_ghost].lng)
			continue;

		fprintf(f, " %s\n", net->name);
		if (net->hdr.ghost)
			fprintf(f, "  GHOST\n");
		if (net->hdr.omit)
			fprintf(f, "  OMIT\n");


		if (abst_values[HA_net_attrs].lng)
			abst_export_attrs(f, &net->hdr, "  ");

		fprintf(f, "  conns %lu\n", (unsigned long)net->conns.used);
		for(n = 0; n < net->conns.used; n++) {
			const char *paop = "", *pacl = "";
			csch_aport_t *port = net->conns.array[n];
			csch_acomp_t *comp = port->parent;
			const char *comp_name = comp == NULL ? "<invalid_comp>" : comp->name;
			const char *port_name = port == NULL ? "<invalid_port>" : port->name;

			if (port->hdr.omit) {
				paop = "(omit ";
				pacl = ")";
			}

			if (port->referer != NULL)
				fprintf(f, "   (via %s-%s)\n", port->referer->name, port_name);
			else
				fprintf(f, "   %s%s-%s%s\n", paop, comp_name, port_name, pacl);
		}
	}
}


static int abst_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, "cschem abstract model v1\n");

	abst_export_comps(f, abs);
	abst_export_nets(f, abs);
	TODO("bus: export buses");

	fclose(f);
	return 0;
}


int pplg_check_ver_export_abst(int ver_needed) { return 0; }

void pplg_uninit_export_abst(void)
{
	csch_plug_io_unregister(&eabst);
	rnd_export_remove_opts_by_cookie(abst_cookie);
	rnd_hid_remove_hid(&abst_hid);
}

int pplg_init_export_abst(void)
{
	RND_API_CHK_VER;

	eabst.name = "export abstract model to text";
	eabst.export_prio = abst_export_prio;
	eabst.export_project_abst = abst_export_project_abst;
	eabst.ext_export_project = ".txt";
	csch_plug_io_register(&eabst);


	rnd_hid_nogui_init(&abst_hid);

	abst_hid.struct_size = sizeof(rnd_hid_t);
	abst_hid.name = "abst";
	abst_hid.description = "Exports project's abstract model to text";
	abst_hid.exporter = 1;

	abst_hid.get_export_options = abst_get_export_options;
	abst_hid.do_export = abst_do_export;
	abst_hid.parse_arguments = abst_parse_arguments;
	abst_hid.argument_array = abst_values;

	abst_hid.usage = abst_usage;

	rnd_hid_register_hid(&abst_hid);
	rnd_hid_load_defaults(&abst_hid, abst_options, NUM_OPTIONS);

	return 0;
}

