/*
 *                            COPYRIGHT
 *
 *  sch-rnd - modular/flexible schematics editor - GUI - project dialog
 *  Copyright (C) 2023 Tibor 'Igor2' Palinkas
 *
 *  (Supported by NLnet NGI0 Entrist 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., 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
 */

/* project properties dialog */

#include <libcschem/config.h>


#include <string.h>
#include <genht/htsp.h>
#include <genht/hash.h>
#include <genlist/gendlist.h>

#include <librnd/core/event.h>
#include <librnd/core/actions.h>
#include <librnd/core/hidlib.h>
#include <librnd/core/rnd_conf.h>
#include <librnd/hid/hid_dad.h>
#include <librnd/hid/hid_dad_tree.h>

#include <libcschem/project.h>

typedef struct prjdlg_ctx_s prjdlg_ctx_t;

struct prjdlg_ctx_s {
	RND_DAD_DECL_NOINIT(dlg)
	int wlist, wscope;
	unsigned active:1;
	csch_project_t *prj;
	int wtab;
};

static prjdlg_ctx_t prjdlg; /* only one instance can be active */


#define SCOPE (ctx->dlg[ctx->wscope].val.lng)
#define PRJDSG ((ctx->prj->hdr.designs.used > 0) ? ctx->prj->hdr.designs.array[0] : NULL)

static void prjdlg_close_cb(void *caller_data, rnd_hid_attr_ev_t ev)
{
	prjdlg_ctx_t *ctx = caller_data;

	RND_DAD_FREE(ctx->dlg);
	ctx->active = 0;
}

static void prj2dlg_load_tree(prjdlg_ctx_t *ctx)
{
	rnd_hid_attribute_t *attr = &ctx->dlg[ctx->wlist];
	char *cell[2];
	long n;
	csch_sheet_type_t ty;

	switch(SCOPE) {
		case 0: ty = CSCH_SHTY_ROOT; break;
		case 1: ty = CSCH_SHTY_AUX; break;
		case 2: ty = CSCH_SHTY_UNLISTED; break;
		case 3: ty = CSCH_SHTY_EXTERNAL; break;
		default:
			rnd_message(RND_MSG_ERROR, "prj2dlg_load_tree(): internal error: invalid SCOPE %d\n", SCOPE);
			return;
	}

	/* add sheets that match SCOPE's type to table */
	cell[1] = NULL;
	for(n = 0; n < ctx->prj->hdr.designs.used; n++) {
		csch_sheet_t *sheet = ctx->prj->hdr.designs.array[n];
		if (sheet->stype == ty) {
			cell[0] = rnd_strdup(sheet->hidlib.fullpath);
			rnd_dad_tree_append(attr, NULL, cell);
		}
	}
}

static void prj2dlg(prjdlg_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;

	/* 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);
	prj2dlg_load_tree(ctx);

	/* 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 prj_set_scope_cb(void *hid_ctx, void *caller_data, rnd_hid_attribute_t *attr)
{
	prjdlg_ctx_t *ctx = caller_data;
	prj2dlg(ctx);
}


static void prj_sheet_select_cb(rnd_hid_attribute_t *attrib, void *hid_ctx, rnd_hid_row_t *row)
{
/*	rnd_hid_tree_t *tree = attrib->wdata;*/
/*	prjdlg_ctx_t *ctx = tree->user_ctx;*/
/* Nothing to do here yet */
}

static void prj_sheet_toggle_cb(void *hid_ctx, void *caller_data, rnd_hid_attribute_t *attr)
{
	prjdlg_ctx_t *ctx = caller_data;
	rnd_hid_attribute_t *tattr = &ctx->dlg[ctx->wlist];
	rnd_hid_row_t *row = rnd_dad_tree_get_selected(tattr);
	const char *target;

	if (row == NULL)
		return;

	switch(SCOPE) {
		case 0: target="aux"; break;
		case 1:
		case 2: target="root"; break;
		case 3: target="aux"; break;
		default:
			return;
	}

	rnd_actionva(PRJDSG, "ProjectSheetType", "@", row->cell[0], target, NULL);
	prj2dlg(ctx);
}

static void prj_sheet_new_cb(void *hid_ctx, void *caller_data, rnd_hid_attribute_t *attr)
{
	prjdlg_ctx_t *ctx = caller_data;
	rnd_actionva(PRJDSG, "New", "@", "root", NULL);
	prj2dlg(ctx);
}

static void prj_sheet_load_cb(void *hid_ctx, void *caller_data, rnd_hid_attribute_t *attr)
{
	prjdlg_ctx_t *ctx = caller_data;
	csch_sheet_t *ns, *curr = (csch_sheet_t *)rnd_multi_get_current();

	rnd_actionva(PRJDSG, "Load", NULL);
	ns = (csch_sheet_t *)rnd_multi_get_current();
	if (ns != curr) {
		rnd_actionva(PRJDSG, "ProjectSheetType", "@", ns->hidlib.fullpath, "root", NULL);
		prj2dlg(ctx);
	}
}

static void prj_sheet_del_cb(void *hid_ctx, void *caller_data, rnd_hid_attribute_t *attr)
{
	prjdlg_ctx_t *ctx = caller_data;
	rnd_hid_attribute_t *tattr = &ctx->dlg[ctx->wlist];
	rnd_hid_row_t *row = rnd_dad_tree_get_selected(tattr);

	if (row == NULL)
		return;

	rnd_actionva(PRJDSG, "ProjectSheetType", "@", row->cell[0], "unload", NULL);
	prj2dlg(ctx);
}

static void prj_dlg(csch_project_t *prj)
{
	prjdlg_ctx_t *ctx = &prjdlg;
	rnd_hid_dad_buttons_t clbtn[] = {{"Close", 0}, {NULL, 0}};
	char *lists[] = {"root sheets (directly compiled)", "aux sheets (referenced by hierarchy)", "unlisted sheets", "external sheets", NULL};

	ctx->prj = prj;

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

		RND_DAD_ENUM(ctx->dlg, lists);
			ctx->wscope = RND_DAD_CURRENT(ctx->dlg);
			RND_DAD_CHANGE_CB(ctx->dlg, prj_set_scope_cb);

		RND_DAD_TREE(ctx->dlg, 1, 0, NULL); /* middle: tree */
			RND_DAD_COMPFLAG(ctx->dlg, RND_HATF_EXPFILL);
			RND_DAD_TREE_SET_CB(ctx->dlg, selected_cb, prj_sheet_select_cb);
			RND_DAD_TREE_SET_CB(ctx->dlg, ctx, ctx);
			ctx->wlist = RND_DAD_CURRENT(ctx->dlg);

		RND_DAD_BEGIN_HBOX(ctx->dlg); /* bottom buttons */
			RND_DAD_BUTTON(ctx->dlg, "toggle root");
				RND_DAD_CHANGE_CB(ctx->dlg, prj_sheet_toggle_cb);
				RND_DAD_HELP(ctx->dlg, "If the selected sheet is a root sheet, make it an aux sheet;\nif it is an aux sheet, make it a root sheet;\nif it is an unlisted sheet, make it a root sheet;\nif it is an external sheet, make it an aux sheet.");
			RND_DAD_BUTTON(ctx->dlg, "new");
				RND_DAD_CHANGE_CB(ctx->dlg, prj_sheet_new_cb);
				RND_DAD_HELP(ctx->dlg, "Create a new root sheet");
			RND_DAD_BUTTON(ctx->dlg, "load");
				RND_DAD_CHANGE_CB(ctx->dlg, prj_sheet_load_cb);
				RND_DAD_HELP(ctx->dlg, "Load a new root sheet");
			RND_DAD_BUTTON(ctx->dlg, "del");
				RND_DAD_CHANGE_CB(ctx->dlg, prj_sheet_del_cb);
				RND_DAD_HELP(ctx->dlg, "Remove selected sheet from the project file and unload the sheet file");
			RND_DAD_BEGIN_VBOX(ctx->dlg);
				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);

	ctx->active = 1;
	RND_DAD_DEFSIZE(ctx->dlg, 200, 300);
	RND_DAD_NEW("PrjPropDialog", ctx->dlg, "Project properties", ctx, 1, prjdlg_close_cb); /* type=local/modal */

	prj2dlg(ctx);

	RND_DAD_RUN(ctx->dlg);
	RND_DAD_FREE(ctx->dlg);
}


const char csch_acts_ProjectDialog[] = "ProjectDialog()";
const char csch_acth_ProjectDialog[] = "Bring up a modal project edit dialog for editing file listings of a project.\n";
fgw_error_t csch_act_ProjectDialog(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	rnd_design_t *hidlib = RND_ACT_DESIGN;
	csch_sheet_t *sheet = (csch_sheet_t *)hidlib;

	prj_dlg((csch_project_t *)sheet->hidlib.project);

	RND_ACT_IRES(0);
	return 0;
}

