/*
 *                            COPYRIGHT
 *
 *  sch-rnd - modular/flexible schematics editor - high level sim, GUI
 *  Copyright (C) 2023 Tibor 'Igor2' Palinkas
 *
 *  (Supported by NLnet NGI0 Entrust in 2023)
 *
 *  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 <genht/htpp.h>
#include <genht/hash.h>
#include <genht/ht_utils.h>

#include <librnd/core/conf_hid.h>
#include <librnd/hid/hid_dad.h>
#include <librnd/hid/hid_dad_tree.h>
#include <liblihata/dom.h>
#include <liblihata/tree.h>

#include <libcschem/project.h>
#include <plugins/sim/sim_conf.h>

#include "sim_setup_dlg.h"

static const char sim_dlg_cookie[] = "sim_gui/sim_dlg";

typedef struct sim_dlg_ctx_s {
	RND_DAD_DECL_NOINIT(dlg)
	csch_project_t *prj;
	int wlist;
} sim_dlg_ctx_t;

static htpp_t prj2dlg;

static void sim_dlg_close_cb(void *caller_data, rnd_hid_attr_ev_t ev)
{
	sim_dlg_ctx_t *ctx = caller_data;

	htpp_pop(&prj2dlg, ctx->prj);
	free(ctx);
}

static void sch_sim_sch2dlg(sim_dlg_ctx_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;
	gdl_iterator_t it;
	rnd_conf_listitem_t *i;
	char *cell[2];

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

	/* remove existing items and fill up with the new */
	rnd_dad_tree_clear(tree);

	/* fill in the table */
	cell[1] = NULL;
	rnd_conflist_foreach(&SCH_SIM_CONF_SETUPS_CONLIST, &it, i) {
		lht_node_t *nsetup = i->prop.src;
		if (nsetup == NULL) continue;
		cell[0] = rnd_strdup(nsetup->name);
		rnd_dad_tree_append(attr, NULL, cell);
	}

	/* restore cursor (will work only in non-modal upon project update from elsewhere) */
	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 dlg_sim_open_cb(void *hid_ctx, void *caller_data, rnd_hid_attribute_t *attr_btn)
{
	sim_dlg_ctx_t *ctx = caller_data;
	rnd_hid_attribute_t *attr = &ctx->dlg[ctx->wlist];
	rnd_hid_row_t *r = rnd_dad_tree_get_selected(attr);

	if (r == NULL) {
		rnd_message(RND_MSG_ERROR, "Select a simulation setup first!\n");
		return;
	}

	sim_setup_dlg(ctx->prj, r->cell[0]);
}

static void dlg_sim_select_cb(void *hid_ctx, void *caller_data, rnd_hid_attribute_t *attr_btn)
{
	/* Double click or enter on an item: just open the sim */
	dlg_sim_open_cb(hid_ctx, caller_data, attr_btn);
}

static void dlg_sim_new_cb(void *hid_ctx, void *caller_data, rnd_hid_attribute_t *attr_btn)
{
	sim_dlg_ctx_t *ctx = caller_data;
	rnd_design_t *dsg = ctx->prj->hdr.designs.array[0];
	char *name;
	lht_node_t *nold, *nnew;

	name = rnd_hid_prompt_for(dsg, "Name for the new simulation setup", NULL, "Simulation setup naming");
	if ((name == NULL) || (*name == '\0')) {
		free(name);
		return; /* cancel */
	}
	nold = sch_sim_get_setup(ctx->prj, name, 0);
	if (nold != NULL) {
		rnd_message(RND_MSG_ERROR, "Setup of that name already exists\nPlease choose a different name\n");
		free(name);
		return;
	}

	nnew = sch_sim_get_setup(ctx->prj, name, 1);
	if (nnew == NULL) {
		rnd_message(RND_MSG_ERROR, "Failed to create new simulation setup\n");
		free(name);
		return;
	}

	sch_sim_flush_prj_file(ctx->prj);
	sim_setup_dlg(ctx->prj, name);
	free(name);
}

static void dlg_sim_del_cb(void *hid_ctx, void *caller_data, rnd_hid_attribute_t *attr_btn)
{
	sim_dlg_ctx_t *ctx = caller_data;
/*	rnd_design_t *dsg = ctx->prj->hdr.designs.array[0];*/
	rnd_hid_attribute_t *attr = &ctx->dlg[ctx->wlist];
	rnd_hid_row_t *r = rnd_dad_tree_get_selected(attr);
	lht_node_t *nd;

	if (r == NULL) {
		rnd_message(RND_MSG_ERROR, "Select a simulation setup first!\n");
		return;
	}

	nd = sch_sim_get_setup(ctx->prj, r->cell[0], 0);
	if (nd == NULL) {
		rnd_message(RND_MSG_ERROR, "Failed to find simulation setup\n");
		return;
	}

	sim_setup_dlg_setup_removed(nd->name);

	lht_tree_del(nd);

	sch_sim_flush_prj_file(ctx->prj);
}


static void sim_dlg(csch_project_t *prj)
{
	sim_dlg_ctx_t *ctx;
	rnd_hid_dad_buttons_t clbtn[] = {{"Close", 0}, {NULL, 0}};

	if (htpp_has(&prj2dlg, prj))
		return;

	ctx = calloc(sizeof(sim_dlg_ctx_t), 1);
	ctx->prj = prj;
	htpp_set(&prj2dlg, prj, ctx);

	RND_DAD_BEGIN_VBOX(ctx->dlg);
		RND_DAD_COMPFLAG(ctx->dlg, RND_HATF_EXPFILL);

		RND_DAD_TREE(ctx->dlg, 1, 0, NULL);
			RND_DAD_COMPFLAG(ctx->dlg, RND_HATF_EXPFILL | RND_HATF_SCROLL);
			ctx->wlist = RND_DAD_CURRENT(ctx->dlg);
			RND_DAD_CHANGE_CB(ctx->dlg, dlg_sim_select_cb);

		RND_DAD_BEGIN_HBOX(ctx->dlg);
			RND_DAD_BUTTON(ctx->dlg, "Open...");
				RND_DAD_HELP(ctx->dlg, "Open the simulation setup dialog to edit or run the simulation");
				RND_DAD_CHANGE_CB(ctx->dlg, dlg_sim_open_cb);
			RND_DAD_BUTTON(ctx->dlg, "New...");
				RND_DAD_HELP(ctx->dlg, "Create a new simulation setup and append to the list");
				RND_DAD_CHANGE_CB(ctx->dlg, dlg_sim_new_cb);
			RND_DAD_BUTTON(ctx->dlg, "Remove");
				RND_DAD_HELP(ctx->dlg, "Remove selected simulation setup from the project config");
				RND_DAD_CHANGE_CB(ctx->dlg, dlg_sim_del_cb);

			RND_DAD_BEGIN_VBOX(ctx->dlg); /* spring */
				RND_DAD_COMPFLAG(ctx->dlg, RND_HATF_EXPFILL);
			RND_DAD_END(ctx->dlg);

			RND_DAD_BUTTON_CLOSES(ctx->dlg, clbtn);
		RND_DAD_END(ctx->dlg);

	RND_DAD_END(ctx->dlg);

	RND_DAD_DEFSIZE(ctx->dlg, 300, 200);
	RND_DAD_NEW("SimulationDialog", ctx->dlg, "Simulation selector", ctx, 0, sim_dlg_close_cb); /* type=local */

	sch_sim_sch2dlg(ctx);
}

const char csch_acts_SimDlg[] = "SimDlg()";
const char csch_acth_SimDlg[] = "Open the sim(ulation) dialog\n";
fgw_error_t csch_act_SimDlg(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	rnd_design_t *dsg = RND_ACT_DESIGN;
	sim_dlg((csch_project_t *)dsg->project);
	return 0;
}

static void sim_dlg_cfgchg(rnd_conf_native_t *cfg, int v, void *user_data)
{
	rnd_design_t *dsg = rnd_multi_get_current();
	sim_dlg_ctx_t *ctx;

	if (dsg == NULL)
		return;
	ctx = htpp_get(&prj2dlg, dsg->project);
	if (ctx != NULL)
		sch_sim_sch2dlg(ctx);
}

static void sim_dlg_prj_unload(rnd_project_t *prj)
{
	rnd_dad_retovr_t retovr = {0};
	sim_dlg_ctx_t *ctx = htpp_get(&prj2dlg, prj);

	/* close dialog referring to this project */
	if (ctx != NULL)
		rnd_hid_dad_close(ctx->dlg_hid_ctx, &retovr, 0);
}

static void sim_dlg_uninit(void)
{
	genht_uninit_deep(htpp, &prj2dlg, {
		rnd_dad_retovr_t retovr = {0};
		sim_dlg_ctx_t *ctx = htent->value;
		rnd_hid_dad_close(ctx->dlg_hid_ctx, &retovr, 0);
	});

	rnd_conf_hid_unreg(sim_dlg_cookie);
}


static void sim_dlg_init(void)
{
	static rnd_conf_hid_callbacks_t cbs;
	static rnd_conf_hid_callbacks_t cbs2;
	static rnd_conf_hid_id_t cfgid;

	htpp_init(&prj2dlg, ptrhash, ptrkeyeq);

	cfgid = rnd_conf_hid_reg(sim_dlg_cookie, &cbs);
	cbs2.val_change_post = sim_dlg_cfgchg;
	rnd_conf_hid_set_cb(rnd_conf_get_field("plugins/sim/setups"), cfgid, &cbs2);
}

