/*
 *                            COPYRIGHT
 *
 *  sch-rnd - modular/flexible schematics editor - Bill of Materials export
 *  Copyright (C) 2023 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>
#include "bom_conf.h"

#include "conf_internal.c"

#define CONF_FN "export_bom.conf"

conf_bom_t conf_bom;

/* Maximum length of a template name (in the config file, in the enum) */
#define MAX_TEMP_NAME_LEN 128

typedef csch_acomp_t bom_obj_t;
#include "../../src_3rd/rnd_inclib/lib_bom/lib_bom.h"

static const char *bom_name_prefix(bom_subst_ctx_t *ctx)
{
	static char tmp[256]; /* this is safe: caller will make a copy right after we return */
	char *o = tmp;
	const char *t;
	int n = 0;

	TODO("this breaks in hierarchic case: S1/S2/U2 returns S instead of U, see example 32_subtree");

	for(t = ctx->name; isalpha(*t) && (n < sizeof(tmp)-1); t++,n++,o++)
		*o = *t;
	*o = '\0';
	return tmp;
}

static const char *subst_user(bom_subst_ctx_t *ctx, const char *key)
{
	if (strncmp(key, "sym.", 4) == 0) {
		key += 4;

		if (strncmp(key, "a.", 2) == 0) return csch_attrib_get_str(&ctx->obj->hdr.attr, key+2);
		else if (strcmp(key, "name") == 0) return ctx->name;
		if (strcmp(key, "prefix") == 0) return bom_name_prefix(ctx);
	}

	return NULL;
}


static void part_rnd_print(bom_subst_ctx_t *ctx, bom_obj_t *obj_, const char *name)
{
	if (name == NULL) {
		return; /* no globals */
	}
	else {
		csch_acomp_t *obj = (csch_acomp_t *)obj_;
		htsp_entry_t *e;

		bom_tdx_fprint_safe_kv(ctx->f, "sym.name", name);
		bom_tdx_fprint_safe_kv(ctx->f, "sym.prefix", bom_name_prefix(ctx));

		/* print all scalar attributes */
		for(e = htsp_first(&obj->hdr.attr); e != NULL; e = htsp_next(&obj->hdr.attr, e)) {
			csch_attrib_t *a = e->value;
			bom_tdx_fprint_safe_kkv(ctx->f, "sym.a.", a->key, a->val);
		}
	}
}

static csch_plug_io_t ebom;

static int bom_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, "bom") == 0)
		return 100;
	return 0;
}

#include "hid_impl.c"


static int print_bom(const char *fn, csch_abstract_t *abst, bom_template_t *templ)
{
	rnd_design_t *hidlib = rnd_multi_get_current();
	FILE *f;
	bom_subst_ctx_t ctx = {0};
	htsp_entry_t *e;

	f = rnd_fopen_askovr(hidlib, fn, "w", NULL);
	if (f == NULL) {
		rnd_message(RND_MSG_ERROR, "Cannot open file %s for writing\n", fn);
		return 1;
	}

	bom_print_begin(&ctx, f, templ);

	for(e = htsp_first(&abst->comps); e != NULL; e = htsp_next(&abst->comps, e)) {
		csch_acomp_t *comp = e->value;
		if (comp->hdr.omit) continue;
		if (comp->hdr.dnp) continue;
		bom_print_add(&ctx, comp, comp->name);
	}

	bom_print_all(&ctx);
	bom_print_end(&ctx);
	fclose(f);

	return 0;
}

static int bom_export_project_bom(const char *fn, const char *fmt, csch_abstract_t *abst, rnd_hid_attr_val_t *options)
{
	bom_template_t templ = {0};
	char **tid;

	tid = vts0_get(&bom_fmt_ids, options[HA_format].lng, 0);
	if ((tid == NULL) || (*tid == NULL)) {
		rnd_message(RND_MSG_ERROR, "export_bom: invalid template selected\n");
		return -1;
	}

	bom_init_template(&templ, &conf_bom.plugins.export_bom.templates, *tid);
	print_bom(fn, abst, &templ);
	return 0;
}

#include "../../src_3rd/rnd_inclib/lib_bom/lib_bom.c"

int pplg_check_ver_export_bom(int ver_needed) { return 0; }

void pplg_uninit_export_bom(void)
{
	csch_plug_io_unregister(&ebom);
	rnd_export_remove_opts_by_cookie(bom_cookie);
	rnd_hid_remove_hid(&bom_hid);

	rnd_conf_unreg_file(CONF_FN, export_bom_conf_internal);
	rnd_conf_unreg_fields("plugins/export_bom/");

	bom_fmt_uninit();
}

int pplg_init_export_bom(void)
{
	RND_API_CHK_VER;

	ebom.name = "export Bill of Materials";
	ebom.export_prio = bom_export_prio;
	ebom.export_project_abst = bom_export_project_bom;
	ebom.ext_export_project = ".txt";
	csch_plug_io_register(&ebom);

	rnd_conf_reg_file(CONF_FN, export_bom_conf_internal);

#define conf_reg(field,isarray,type_name,cpath,cname,desc,flags) \
	rnd_conf_reg_field(conf_bom, field,isarray,type_name,cpath,cname,desc,flags);
#include "bom_conf_fields.h"

	rnd_hid_nogui_init(&bom_hid);

	bom_hid.struct_size = sizeof(rnd_hid_t);
	bom_hid.name = "bom";
	bom_hid.description = "Exports project's Bill of Materials";
	bom_hid.exporter = 1;

	bom_hid.get_export_options = bom_get_export_options;
	bom_hid.do_export = bom_do_export;
	bom_hid.parse_arguments = bom_parse_arguments;
	bom_hid.argument_array = bom_values;

	bom_hid.usage = bom_usage;

	rnd_hid_register_hid(&bom_hid);
	rnd_hid_load_defaults(&bom_hid, bom_options, NUM_OPTIONS);

	bom_fmt_init();

	return 0;
}

