/*
 *                            COPYRIGHT
 *
 *  cschem - modular/flexible schematics editor - GUI
 *  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., 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
 */

/* quick-edit attribute: symbol portmap list, in sym->fp format */

#include <librnd/hid/hid_dad.h>
#include <librnd/hid/hid_dad_tree.h>

#include <ctype.h>

typedef struct {
	RND_DAD_DECL_NOINIT(dlg)
	csch_sheet_t *sheet;
	csch_cgrp_t *grp;
	int changed;
	int wlist, wadd, wsym, wkey, wval;
} qa_portmap_t;

static void qa_portmap_close_cb(void *caller_data, rnd_hid_attr_ev_t ev)
{
	
}

static void qa_portmap_sheet2dlg(qa_portmap_t *ctx)
{
	rnd_hid_attribute_t *attr = &ctx->dlg[ctx->wlist];
	rnd_hid_tree_t *tree = attr->wdata;
	rnd_hid_row_t *r;
	char *cursor_path = NULL;
	const vts0_t *arr;

	/* remember cursor */
	r = rnd_dad_tree_get_selected(attr);
	if (r != NULL)
		cursor_path = rnd_strdup(r->cell[0]);

	/* remove existing items */
	rnd_dad_tree_clear(tree);

	/* add all items */
	arr = csch_attrib_get_arr(&ctx->grp->attr, "portmap");
	if (arr != NULL) {
		long n;
		char *cell[4];

		cell[3] = NULL;
		for(n = 0; n < arr->used; n++) {
			char *c, *sep, *s, *key, *val;
			int found = 0;

			c = arr->array[n];
			for(sep = c; *sep != '\0'; sep++) {
				if ((sep[0] == '-') && (sep[1] == '>')) {
					found = 1;
					break;
				}
			}
			if (found) {
				s = sep-1;
				while((s >= c) && isspace(*s))
					s--;
				cell[0] = rnd_strndup(c, s-c+1);
				s = sep+2;
				while(isspace(*s)) s++;

				key = rnd_strdup(s);
				val = strchr(key, '=');
				if (val != NULL) {
					*val = '\0';
					val++;
				}
				cell[1] = key;
				cell[2] = rnd_strdup(val);
			}
			else {
				cell[0] = rnd_strdup(c);
				cell[1] = NULL;
			}
			rnd_dad_tree_append(attr, NULL, cell);
		}
	}

	/* restore cursor */
	if (cursor_path != NULL) {
		rnd_hid_attr_val_t hv;
		hv.str = cursor_path;
		rnd_gui->attr_dlg_set_value(ctx->dlg_hid_ctx, ctx->wlist, &hv);
		free(cursor_path);
	}
}

static void qa_portmap_select_cb(rnd_hid_attribute_t *attrib, void *hid_ctx, rnd_hid_row_t *row)
{
	rnd_hid_tree_t *tree = attrib->wdata;
	qa_portmap_t *ctx = tree->user_ctx;

	if (row != NULL) {
		rnd_hid_attr_val_t hv;

		hv.str = row->cell[0];
		rnd_gui->attr_dlg_set_value(ctx->dlg_hid_ctx, ctx->wsym, &hv);
		hv.str = row->cell[1];
		rnd_gui->attr_dlg_set_value(ctx->dlg_hid_ctx, ctx->wkey, &hv);
		hv.str = row->cell[2];
		rnd_gui->attr_dlg_set_value(ctx->dlg_hid_ctx, ctx->wval, &hv);
	}
}

static long sym2idx(qa_portmap_t *ctx, long *totlen, int err)
{
	const vts0_t *arr = csch_attrib_get_arr(&ctx->grp->attr, "portmap");
	long n, len, cmplen;
	const char *sym = ctx->dlg[ctx->wsym].val.str, *end;
	const char *key = ctx->dlg[ctx->wkey].val.str, *attrkey;

	if (totlen != NULL) {
		if (arr == NULL)
			*totlen = 0;
		else
			*totlen = arr->used;
	}

	if (sym != NULL)
		while(isspace(*sym)) sym++;

	if (((sym == NULL) || (*sym == '\0')) && err) {
		rnd_message(RND_MSG_ERROR, "Please fill in the symbol side name\n");
		return -1;
	}

	if ((arr == NULL) || (sym == NULL) || (*sym == '\0'))
		return -1;

	if ((key == NULL) || (*key == '\0')) {
		key = NULL;
		cmplen = 0;
	}
	else
		cmplen = strlen(key);


	end = strpbrk(sym, " \t\r\n");
	if (end != NULL)
		len = end - sym;
	else
		len = strlen(sym);

	for(n = 0; n < arr->used; n++) {
		char *a = arr->array[n];
		if ((strncmp(a, sym, len) == 0) && ((a[len] == '-') || isspace(a[len]))) {
			end = a+len;
			while(isspace(*end)) end++;
			if ((end[0] == '-') && (end[1] == '>')) {
				end += 2;
				while(isspace(*end)) end++;
				attrkey = end;
			}
			else {
				/* no -> means no attr key */
				attrkey = NULL;
			}

			if ((key == NULL) && (attrkey == NULL))
				return n;
			if ((strncmp(key, attrkey, cmplen) == 0) && (attrkey[cmplen] == '='))
				return n;
		}
	}

	if (err)
		rnd_message(RND_MSG_ERROR, "No entry found for symbol side name '%s'\n", sym);

	return -1;
}

static void qa_portmap_del_cb(void *hid_ctx, void *caller_data, rnd_hid_attribute_t *attr)
{
	qa_portmap_t *ctx = caller_data;
	long idx = sym2idx(ctx, NULL, 1);
	if (idx < 0)
		return;
	csch_attr_arr_modify_del(ctx->sheet, ctx->grp, "portmap", idx, 1);
	qa_portmap_sheet2dlg(ctx);
}

static void qa_portmap_add_cb(void *hid_ctx, void *caller_data, rnd_hid_attribute_t *attr)
{
	qa_portmap_t *ctx = caller_data;
	long totlen, idx = sym2idx(ctx, &totlen, 0);
	const char *sym = ctx->dlg[ctx->wsym].val.str;
	const char *key = ctx->dlg[ctx->wkey].val.str;
	const char *val = ctx->dlg[ctx->wval].val.str;
	gds_t tmp = {0};

	if ((sym == NULL) || (*sym == '\0') || (key == NULL) || (*key == '\0')) {
		rnd_message(RND_MSG_ERROR, "Please fill in both symbol and output side first!\n");
		return;
	}

	gds_append_str(&tmp, sym);
	gds_append_str(&tmp, "->");
	gds_append_str(&tmp, key);
	gds_append(&tmp, '=');
	gds_append_str(&tmp, val);

	if (idx >= 0)
		csch_attr_arr_modify_str(ctx->sheet, ctx->grp, "portmap", idx, tmp.array, 1);
	else
		csch_attr_arr_modify_ins_before(ctx->sheet, ctx->grp, "portmap", totlen, tmp.array, 1);

	ctx->changed = 1;

	qa_portmap_sheet2dlg(ctx);
	gds_uninit(&tmp);
}

const char csch_acts_quick_attr_portmap[] = "quick_attr_portmap(objptr)";
const char csch_acth_quick_attr_portmap[] = "Quick Attribute Edit for core data model's symbol portmap attribute (attribute based \"symbol terminal to network\" portmap table)";
fgw_error_t csch_act_quick_attr_portmap(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	qa_portmap_t ctx = {0};
	rnd_design_t *hidlib = RND_ACT_DESIGN;
	rnd_hid_dad_buttons_t clbtn[] = {{"Close", 1}, {NULL, 0}};
	const char *hdr[] = {"Symbol term name", "Attrib key", "Attrib value", NULL};

	ctx.sheet = (csch_sheet_t *)hidlib;
	ctx.changed = 0;
	QUICK_ATTR_GET_GRP(ctx.grp, "quick_attr_portmap");

	RND_DAD_BEGIN_VBOX(ctx.dlg);
		RND_DAD_COMPFLAG(ctx.dlg, RND_HATF_EXPFILL);
		RND_DAD_TREE(ctx.dlg, 3, 0, hdr);
			RND_DAD_COMPFLAG(ctx.dlg, RND_HATF_EXPFILL | RND_HATF_SCROLL);
			ctx.wlist = RND_DAD_CURRENT(ctx.dlg);
			RND_DAD_TREE_SET_CB(ctx.dlg, selected_cb, qa_portmap_select_cb);
			RND_DAD_TREE_SET_CB(ctx.dlg, ctx, &ctx);
		RND_DAD_BEGIN_HBOX(ctx.dlg);
			RND_DAD_LABEL(ctx.dlg, "Symbol term name:");
			RND_DAD_STRING(ctx.dlg);
				ctx.wsym = RND_DAD_CURRENT(ctx.dlg);
			RND_DAD_BUTTON(ctx.dlg, "Del");
				RND_DAD_CHANGE_CB(ctx.dlg, qa_portmap_del_cb);
		RND_DAD_END(ctx.dlg);
		RND_DAD_BEGIN_HBOX(ctx.dlg);
			RND_DAD_BEGIN_VBOX(ctx.dlg);
				RND_DAD_BEGIN_HBOX(ctx.dlg);
					RND_DAD_LABEL(ctx.dlg, "Output attrib key:");
					RND_DAD_STRING(ctx.dlg);
						RND_DAD_DEFAULT_PTR(ctx.dlg, rnd_strdup("pcb/pinnum"));
						ctx.wkey = RND_DAD_CURRENT(ctx.dlg);
				RND_DAD_END(ctx.dlg);
				RND_DAD_BEGIN_HBOX(ctx.dlg);
					RND_DAD_LABEL(ctx.dlg, "Output attrib value:");
					RND_DAD_STRING(ctx.dlg);
						ctx.wval = RND_DAD_CURRENT(ctx.dlg);
				RND_DAD_END(ctx.dlg);
			RND_DAD_END(ctx.dlg);
			RND_DAD_BUTTON(ctx.dlg, "Add/edit");
				ctx.wadd = RND_DAD_CURRENT(ctx.dlg);
				RND_DAD_CHANGE_CB(ctx.dlg, qa_portmap_add_cb);
		RND_DAD_END(ctx.dlg);
		RND_DAD_BUTTON_CLOSES(ctx.dlg, clbtn);
	RND_DAD_END(ctx.dlg);

	RND_DAD_NEW("quick_attr_portmap", ctx.dlg, "Set symbol portmap list", &ctx, 1, qa_portmap_close_cb); /* type=local/modal */
	qa_portmap_sheet2dlg(&ctx);
	RND_DAD_RUN(ctx.dlg);

	RND_ACT_IRES(ctx.changed);

	return 0;
}
