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


/* Common export code (helpers) */

#include <libcschem/config.h>
#include <libcschem/concrete.h>
#include <libcschem/abstract.h>
#include <libcschem/plug_io.h>
#include <libcschem/util_export.h>
#include <libcschem/compile.h>

#include <ctype.h>
#include <string.h>
#include <genvector/gds_char.h>

#include <librnd/core/error.h>
#include <librnd/core/safe_fs.h>

#include "sheet.h"

#include "export.h"

sch_rnd_export_appspec_t sch_rnd_no_appspec = {0};


RND_INLINE void vis_invert(rnd_xform_t *xform)
{
	int n;
	for(n = 0; n < CSCH_DSPLY_max; n++)
		xform->local_vis[n] = !xform->local_vis[n];
}

RND_INLINE void vis_set_all(rnd_xform_t *xform, int val)
{
	int n;
	for(n = 0; n < CSCH_DSPLY_max; n++)
		xform->local_vis[n] = val;
}

RND_INLINE void vis_set_by_name(rnd_xform_t *xform, const char *name, int len, int val)
{
	int n, set = 0;

	for(n = 0; n < CSCH_DSPLY_max; n++) {
		const char *dly = csch_dsply_name(n);
		if (strncmp(name, dly, len) == 0) {
			xform->local_vis[n] = val;
			set = 1;
		}
	}

	if (set == 0) {
		gds_t tmp = {0};
		gds_append_len(&tmp, name, len);
		rnd_message(RND_MSG_ERROR, "Layer visibility: unknown layer name (prefix did not match any layer): '%s'\n", tmp.array);
		gds_uninit(&tmp);
	}
}


void sch_rnd_set_export_layers(rnd_xform_t *xform, const char *layers)
{
	const char *start, *next, *end;

	assert(sizeof(xform->local_vis) == sizeof(csch_export_layer_vis));

	/* empty string should result in the default export layer visibility setup */
	memcpy(xform->local_vis, csch_export_layer_vis, sizeof(xform->local_vis));
	xform->use_local_vis = 1;

	for(start = layers; start != NULL; start = next) {
		int len, inv = 0;

		/* get next word */
		while(isspace(*start) || (*start == ',')) start++;
		if (*start == '\0')
			break;

		end = next = strpbrk(start, ", \t\r\n");
		if (next != NULL)
			next++;
		else
			end = start + strlen(start);

		/* read pefix */
		while(*start == '!') {
			start++;
			inv = !inv;
		}

		/* decode instruction */
		len = end - start;
		if ((len == 3) && ((strncmp(start, "gui", 3) == 0) || (strncmp(start, "GUI", 3) == 0))) {
			memcpy(xform->local_vis, csch_layer_vis, sizeof(xform->local_vis));
			if (inv) vis_invert(xform);
		}
		else if ((len == 4) && (strncmp(start, "none", 4) == 0))
			vis_set_all(xform, inv ? 1 : 0);
		else if ((len == 3) && (strncmp(start, "all", 3) == 0))
			vis_set_all(xform, inv ? 0 : 1);
		else
			vis_set_by_name(xform, start, len, inv ? 0 : 1);
	}
}

int sch_rnd_export_prj_abst(csch_project_t *prj, csch_sheet_t *sheet, int viewid, const char *exp_fmt, const char *explicit_name, rnd_hid_attr_val_t *options)
{
	int res = 0;
	csch_abstract_t abs;

	csch_abstract_init(&abs);
	res |= csch_compile_project(prj, viewid, &abs, 0);

	if (exp_fmt != NULL) {
		char epath[CSCH_PATH_MAX];
		const char *final_path;

		if (explicit_name == NULL) {
			csch_project_export_name(prj, sheet, epath, exp_fmt, NULL);
			final_path = epath;
		}
		else
			final_path = explicit_name;
		csch_export_project_abst(&abs, final_path, exp_fmt, options);
	}

	csch_abstract_uninit(&abs);
	return res;
}

static int sch_rnd_export_prj_sheets_multifile(rnd_hid_t *hid, rnd_design_t *design, rnd_hid_attr_val_t *options, sch_rnd_export_appspec_t *appspec, int (*exp_sheet)(rnd_hid_t *, rnd_design_t *, rnd_hid_attr_val_t *, sch_rnd_export_appspec_t *, int *ovr))
{
	int res = 0, ovr = 0;
	long page;
	char fn_page_suffix[128];

	appspec->fn_page_suffix = fn_page_suffix;
	for(page = 0; page < design->project->designs.used; page++) {
		sch_rnd_sheet_recalc_bbox((csch_sheet_t *)design->project->designs.array[page]);
		sprintf(fn_page_suffix, "-p%ld", page+1);
		res |= exp_sheet(hid, design->project->designs.array[page], options, appspec, &ovr);
	}
	appspec->fn_page_suffix = NULL;

	return res;
}

int sch_rnd_export_project_or_sheet(rnd_hid_t *hid, rnd_design_t *design, rnd_hid_attr_val_t *options, sch_rnd_export_appspec_t *appspec, int (*exp_sheet)(rnd_hid_t *, rnd_design_t *, rnd_hid_attr_val_t *, sch_rnd_export_appspec_t *, int *ovr))
{
	if (appspec->exp_prj)
		return sch_rnd_export_prj_sheets_multifile(hid, design, options, appspec, exp_sheet);

	sch_rnd_sheet_recalc_bbox((csch_sheet_t *)design);
	return exp_sheet(hid, design, options, appspec, NULL);
}
