/*
 *                            COPYRIGHT
 *
 *  cschem - modular/flexible schematics editor - libcschem (core library)
 *  Copyright (C) 2018,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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  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
 */

/* Dynamic text (dyntext) management/render */

#include "config.h"

#include <librnd/core/rnd_printf.h>
#include <librnd/core/conf.h>
#include <librnd/core/compat_misc.h>
#include <librnd/core/compat_fs.h>

#include "abstract.h"
#include "cnc_text.h"
#include "cnc_grp.h"
#include "cnc_text_dyn.h"
#include "project.h"

RND_INLINE const csch_chdr_t *get_attrib_obj(char **path, const csch_text_t *text)
{
	const csch_chdr_t *hdr = &text->hdr;
	for(;;) {
		if (((*path)[0] == '.') && ((*path)[1] == '.') && ((*path)[2] == '/')) {
			if (hdr->parent != NULL)
				hdr = &hdr->parent->hdr;
			*path += 3;
		}
		else break;
	}
	return hdr;
}

static const char *get_filename(csch_sheet_t *sheet)
{
	const char *sep, *fn = sheet->hidlib.fullpath;

	if (fn == NULL)
		return "<not saved yet>";

	sep = strrchr(fn, '/');
	if (sep != NULL)
		return sep+1; /* basename */

	return fn;
}

static const char *prj_name(const char *fullpath)
{
	static char res[1024], *d;
	const char *s;

	for(s = rnd_parent_dir_name(fullpath), d = res; *s != '/'; s++, d++) {
		if ((d - res) > sizeof(res)-2)
			break;
		*d = *s;
	}
	*d = '\0';
	return res;
}

static const char *get_prjname(csch_sheet_t *sheet)
{
	const char *fn = sheet->hidlib.loadname;
	csch_project_t *prj = NULL;
	htsp_entry_t *e;

	if ((fn == NULL) || (fn[0] == '<'))
		return "<none> (save sheet!)";

	prj = (csch_project_t *)sheet->hidlib.project;
	if (prj == NULL)
		return "<none> (no project)";

	if (prj->hdr.fullpath != NULL)
		return prj_name(prj->hdr.fullpath);

	for(e = htsp_first(&rnd_projects); e != NULL; e = htsp_next(&rnd_projects, e))
		if (prj == e->value)
			return prj_name(e->key);

	return "<none> (unnamed prj)";
}

static const char *dyntext_get_attr_val(const csch_attribs_t *attrs, const char *key)
{
	const char *val = csch_attrib_get_str(attrs, key);
	if (val == NULL) {
		const vts0_t *arr = csch_attrib_get_arr(attrs, key);
		if (arr != NULL) {
			if (arr->used == 1)
				val = arr->array[0];
			else
				val = "<array>";
		}
	}
	return val;
}


static int csch_text_render_str_cb(void *ctx, gds_t *s, const char **input)
{
	const csch_text_t *text = ctx;
	const csch_attribs_t *attrs = NULL;
	const csch_chdr_t *agrp;
	char *end, key[128], *path;
	const char *val = NULL;
	size_t len;

	end = strchr(*input, '%');
	len = end - *input;
	if (len > sizeof(key)-1)
		return -1;

	strncpy(key, *input, len);
	key[len] = '\0';
	*input += len+1;

	if (strcmp(key, "filename") == 0) {
		val = get_filename(text->hdr.sheet);
		goto append;
	}
	if (strcmp(key, "project.name") == 0) {
		val = get_prjname(text->hdr.sheet);
		goto append;
	}
	if (strncmp(key, "stance.", 7) == 0) {
		val = csch_stance_get(key+7);
		goto append;
	}
	if (strncmp(key, "view.", 5) == 0) {
		val = csch_view_get_prop((csch_project_t *)text->hdr.sheet->hidlib.project, -1, key+5);
		goto append;
	}


	path = key;
	agrp = get_attrib_obj(&path, text);
	if ((path[0] == 'A') && (path[1] == '.')) {
		if (agrp != NULL) {
			csch_cgrp_t *g = (csch_cgrp_t *)agrp;
			attrs = &g->attr;
		}
		path+=2;
		if (attrs != NULL) {
			val = dyntext_get_attr_val(attrs, path);
			goto append;
		}
	}
	else if ((path[0] == 'a') && (path[1] == '.')) {
		int hier_idx = 0;
		csch_ahdr_t *a = NULL;

		path+=2;
		TODO("hierarchic: provide a spinbox next to the view name for selecting hier_idx here instead of hardwiring 0");
		if (agrp != NULL) {
			assert(csch_obj_is_grp(agrp));
			a = csch_cgrp_get_abstract(text->hdr.sheet, (const csch_cgrp_t *)agrp, hier_idx);
		}
		if (a != NULL)
			attrs = &a->attr;
		if (attrs != NULL) {
			val = dyntext_get_attr_val(attrs, path);
			goto append;
		}
	}
	return 0;

	append:;
	if (val != NULL)
		gds_append_str(s, val);
	return 0;
}


void csch_text_dyntext_inval(csch_text_t *text)
{
	free(text->rtext);
	text->rtext = NULL;
}

void csch_text_dyntext_render(csch_text_t *text)
{
	const char *empty = "\001";
	csch_text_dyntext_inval(text);

	if (text->dyntext) {
		gds_t tmp = {0};
		rnd_subst_append(&tmp, text->text, csch_text_render_str_cb, (void *)text, RND_SUBST_PERCENT | RND_SUBST_CONF, 0);
		if ((tmp.array == NULL) || (*tmp.array == '\0')) {
			text->rtext = rnd_strdup(empty);
			gds_uninit(&tmp);
		}
		else
			text->rtext = tmp.array;
	}
	else {
		if ((text->text == NULL) || (*text->text == '\0'))
			text->rtext = rnd_strdup(empty);
		else
			text->rtext = rnd_strdup(text->text);
	}
}

