/*
 *                            COPYRIGHT
 *
 *  cschem - modular/flexible schematics editor - core library
 *  Copyright (C) 2022 Tibor 'Igor2' Palinkas
 *
 *  (Supported by NLnet NGI0 PET Fund in 2022)
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.*
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; 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 "config.h"

#include <genvector/gds_char.h>
#include <librnd/core/compat_misc.h>
#include "concrete.h"
#include "compile.h"
#include "plug_io.h"

#include "util_export.h"

char *cschem_export_filename(rnd_design_t *hl, const char *explicit, const char *base_prefix, const char *base_suffix, const char *ext)
{
	csch_sheet_t *sheet = (csch_sheet_t *)hl;
	gds_t tmp;

	if (explicit != NULL) {
		if ((base_prefix == NULL) && (base_suffix == NULL))
			return rnd_strdup(explicit);

		gds_init(&tmp);

		if (base_prefix != NULL) {
			char *sep = strrchr(explicit, '/');
			if (sep != NULL) {
				gds_append_len(&tmp, sheet->hidlib.loadname, sep - explicit + 1);
				gds_append_str(&tmp, base_prefix);
				gds_append_str(&tmp, sep + 1);
			}
			else {
				gds_append_str(&tmp, base_prefix);
				gds_append_str(&tmp, explicit);
			}
		}
		else
			gds_append_str(&tmp, explicit);

		if (base_suffix != NULL) {
			char *sep = strrchr(tmp.array, '.');
			if (sep != NULL)
				gds_insert_len(&tmp, sep - tmp.array, (char *)base_suffix, strlen(base_suffix));
			else
				gds_append_str(&tmp, base_suffix);
		}
		return tmp.array; /* tmp is not uninited because ownership is passed back to the caller */
	}


	gds_init(&tmp);

	if (sheet->hidlib.loadname != NULL) {
		int n;

		if (base_prefix != NULL) {
			char *sep = strrchr(sheet->hidlib.loadname, '/');
			if (sep != NULL) {
				gds_append_len(&tmp, sheet->hidlib.loadname, sep - sheet->hidlib.loadname + 1);
				gds_append_str(&tmp, base_prefix);
				gds_append_str(&tmp, sep + 1);
			}
			else {
				gds_append_str(&tmp, base_prefix);
				gds_append_str(&tmp, sheet->hidlib.loadname);
			}
		}
		else
			gds_append_str(&tmp, sheet->hidlib.loadname);

		/* truncate "extension" */
		for(n = tmp.used-1; n > 0; n--) {
			if (tmp.array[n] == '.') {
				tmp.used = n;
				break;
			}
		}
	}
	else {
		if (base_prefix != NULL)
			gds_append_str(&tmp, base_prefix);
		gds_append_str(&tmp, "unknown");
	}

	if (base_suffix != NULL)
		gds_append_str(&tmp, base_suffix);

	gds_append_str(&tmp, ext);

	return tmp.array; /* tmp is not uninited because ownership is passed back to the caller */
}

static char nope[] = "no abstract";

int cschem_export_compile_pre(csch_project_t *prj, const char *view_name, void **cookie)
{
	int view_id = CSCH_VIEW_DEFAULT;

	*cookie = prj->abst;

	if ((view_name == NULL) || (*view_name == '\0')) {
		if (prj->abst != NULL) {
			*cookie = nope; /* do not attempt to free prj->abst on _post */
			return 0; /* already compiled and no different view requested */
		}
	}
	else { /* view requested */
		view_id = csch_view_get_id(prj, view_name);
		if (view_id < 0) {
			rnd_message(RND_MSG_ERROR, "Invalid view name: '%s'\n", view_name);
			goto error;
		}
	}

	/* old one saved in cookie */
	prj->abst = calloc(sizeof(csch_abstract_t), 1);
	csch_abstract_init(prj->abst);
	if (csch_compile_project(prj, view_id, prj->abst, 0) != 0) {
		csch_abstract_uninit(prj->abst);
		prj->abst = *cookie;
		rnd_message(RND_MSG_ERROR, "Failed to compile view: '%s'\n", view_name);
		goto error;
	}

	return 0;

	error:;
	*cookie = nope; /* do not attempt to free prj->abst on _post */
	return -1;
}

void cschem_export_compile_post(csch_project_t *prj, void **cookie)
{
	if (*cookie != nope) {
		/* remove abstract model compiled for the export, restore original */
		csch_abstract_uninit(prj->abst);
		prj->abst = *cookie;
	}

	*cookie = NULL;
}



static int use_project_name(csch_sheet_t *sheet, int exp_prj)
{
	csch_project_t *prj = (csch_project_t *)sheet->hidlib.project;

	/* exporting a single sheet: always use sheet name */
	if (!exp_prj)
		return 0;

	/* if there is an explicit project file, always export project by project name */
	if (!prj->dummy)
		return 1;

	/* if we have an implicit project with a single file, use the file name */
	if (sheet->hidlib.project->designs.used < 2)
		return 0;

	/* multiple files with implicit project file: use project name */
	return 1;
}

/* Always leaves room for at least 3 more bytes starting from \0 */
void csch_sheet_export_name(csch_sheet_t *sheet, int exp_prj, char epath[CSCH_PATH_MAX], long exp_idx)
{
	if (use_project_name(sheet, exp_prj)) {
		if ((sheet->hidlib.project != NULL) && (sheet->hidlib.project->prjdir != NULL)) {
			const char *pname = NULL, *sep;

			sep = strrchr(sheet->hidlib.project->prjdir, '/');
			if (sep == NULL)
				pname = sheet->hidlib.project->prjdir;
			else
				pname = sep+1;
			if (strlen(pname) >= CSCH_PATH_MAX-4) {
				sprintf(epath, "long_named_sheet_%ld*", exp_idx);
				return;
			}
			else
				sprintf(epath, "%s*", pname);
		}
		else
			strcpy(epath, "implicit_project*");
	}
	else if (sheet->hidlib.loadname != NULL) {
		char *ext;
		if (strlen(sheet->hidlib.loadname) >= CSCH_PATH_MAX-4) {
			sprintf(epath, "long_named_sheet_%ld*", exp_idx);
			return;
		}
		strcpy(epath, sheet->hidlib.loadname);
		ext = strrchr(epath, '.');
		if ((ext != NULL) && ((strcmp(ext, ".rs") == 0) || (strcmp(ext, ".lht") == 0) || (strcmp(ext, ".csch") == 0)))
			strcpy(ext, "*");
		else
			strcat(epath, "*");
	}
	else
		sprintf(epath, "anon_sheet_%ld*", exp_idx);
}

void csch_project_export_name(csch_project_t *prj, csch_sheet_t *sheet, char epath[CSCH_PATH_MAX], const char *exp_fmt, const char *view_name)
{

	/* automatic view name */
	if (view_name == NULL) {
		void **v = vtp0_get(&prj->views, prj->curr, 0);

		if ((v != NULL) && (*v != NULL)) {
			csch_view_t *view = *v;
			view_name = view->fgw_ctx.name;
		}
		else
			view_name = "no_view";
	}

	if (prj->hdr.loadname != NULL) {
		char *end;
		if (strlen(prj->hdr.loadname) + strlen(view_name) >= CSCH_PATH_MAX)
			goto fallback;
		strcpy(epath, prj->hdr.loadname);
		end = strrchr(epath, '/');
		if (strcmp(end, "/project.lht") == 0)
			sprintf(end, "/netlist.%s*", view_name);
	}
	else {
		fallback:;
		if (sheet != NULL) {
			if (sheet->hidlib.loadname != NULL) {
				long len = strlen(sheet->hidlib.loadname);
				char *s, *end;

				memcpy(epath, sheet->hidlib.loadname, len);
				for(s = end = epath + len; s > sheet->hidlib.loadname+1; s--) {
					if (*s == '.') {
						end = s;
						break;
					}
				}
				*end = '.';
				end++;
				len = strlen(view_name);
				memcpy(end, view_name, len);
				end += len;
				end[0] = '*';
				end[1] = '\0';
			}
			else
				goto fallback2;
		}
		else {
			fallback2:;
			sprintf(epath, "netlist.%s*", view_name);
		}
	}
}

void csch_derive_default_filename(rnd_design_t *dsg, int exp_prj, rnd_hid_attr_val_t *filename_attrib, const char *suffix)
{
	csch_sheet_t *sheet = (csch_sheet_t *)dsg;
	char tmp[CSCH_PATH_MAX];
	char *e;

	csch_sheet_export_name(sheet, exp_prj, tmp, sheet->uid);
	e = strchr(tmp, '*');
	if (e != NULL) {
		if ((CSCH_PATH_MAX - (e - tmp)) > strlen(suffix)+1) {
			strcpy(e, suffix);
		}
		else {
			e[0] = '_';
			e[1] = '\0';
		}
	}

	free((char *)filename_attrib->str);
	filename_attrib->str = rnd_strdup(tmp);
}

