/*
 *                            COPYRIGHT
 *
 *  sch-rnd - modular/flexible schematics editor - GUI
 *  Copyright (C) 2022,2023,2024 Tibor 'Igor2' Palinkas
 *
 *  (Supported by NLnet NGI0 PET Fund in 2022, Entrust in 2023,2024)
 *
 *  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
 */

#include <libcschem/config.h>

#include <librnd/config.h>

#include <genvector/vti0.h>
#include <genvector/vtp0.h>

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

#include <librnd/core/actions.h>
#include <librnd/core/event.h>
#include <librnd/core/rnd_conf.h>
#include <librnd/core/compat_fs.h>

#include <libcschem/concrete.h>
#include <libcschem/project.h>
#include <libcschem/util_project.h>

#include <sch-rnd/multi.h>

#include "sheetsel.h"

const char sheetsel_tooltip[] =
	"A list of all projects/sheets currently open\n"
	"\nProject marks:\n"
	" [e] explicit (project.lht lists sheet files)\n"
	" [i] implicit (no sheet list in project.lht)\n"
	" P!  partial (not all root sheets are loaded)\n"
	"\nSheet marks:\n"
	" *   unsaved changes\n"
	" [R] root sheet (directly compiled)\n"
	" [a] aux sheet (referenced from hierarchy)\n"
	" [u] unlisted sheet (in the same dir)\n"
	" [E] external (unlisted, loaded for hierarchy)\n"
	" [?] unknown/undecided sheet state\n";

typedef struct sheetsel_ctx_s sheetsel_ctx_t;
struct sheetsel_ctx_s {
	rnd_hid_dad_subdialog_t sub;
	int sub_inited, lock;
	int wtree;
};

static sheetsel_ctx_t sheetsel;

static const char *sheet_marks(csch_project_t *prj, csch_sheet_t *sheet)
{
	switch(sheet->stype) {
		case CSCH_SHTY_unknown:  return " [?]";
		case CSCH_SHTY_AUX:      return " [a]";
		case CSCH_SHTY_ROOT:     return " [R]";
		case CSCH_SHTY_UNLISTED: return " [u]";
		case CSCH_SHTY_EXTERNAL: return " [E]";
	}
	return " [??]";
}

static void sheetsel_prj2dlg(sheetsel_ctx_t *ss)
{
	rnd_hid_attribute_t *attr = &ss->sub.dlg[ss->wtree];
	rnd_hid_tree_t *tree = attr->wdata;
	rnd_hid_row_t *r, *rprj;
	htsp_entry_t *e;
	char *cell[2], *changed;

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

	/* add all items */
	cell[1] = NULL;
	for(e = htsp_first(&rnd_projects); e != NULL; e = htsp_next(&rnd_projects, e)) {
		long n;
		csch_project_t *prj = e->value;
		char *end;
		gds_t tmp = {0};
		const char *bn = rnd_parent_dir_name(e->key);

		gds_append_str(&tmp, bn);
		if (tmp.array != NULL) {
			end = strchr(tmp.array, '/');
			if (end != NULL)
				tmp.used = end - tmp.array;
		}
		else
			rnd_message(RND_MSG_ERROR, "Internal error: empty project name (please report this bug)\n");

		if ((prj->hdr.fullpath == NULL) || ((prj->num_root_sheets == 0) && (prj->num_aux_sheets == 0)))
			gds_append_str(&tmp, " [i]");
		else
			gds_append_str(&tmp, " [e]");

		if (csch_project_is_partial(prj))
			gds_append_str(&tmp, " P!");

		cell[0] = tmp.array;
		rprj = rnd_dad_tree_append(attr, NULL, cell);
		rprj->user_data = NULL;

		for(n = 0; n < prj->hdr.designs.used; n++) {
			csch_sheet_t *sheet = prj->hdr.designs.array[n];
			const char *marks;

			if (sheet->hidlib.loadname != NULL) {
				bn = strrchr(sheet->hidlib.loadname, '/');
				if (bn != NULL)
					bn++;
				else
					bn = sheet->hidlib.loadname;
			}
			else
				bn = "<none>";

			changed = (sheet->changed ? "*" : NULL);
			if (prj->hdr.fullpath == NULL)
				marks = " [u]";
			else
				marks = sheet_marks(prj, sheet);

			cell[0] = rnd_concat(bn, marks, changed, NULL);
			r = rnd_dad_tree_append_under(attr, rprj, cell);
			r->user_data = sheet;
		}
	}

	rnd_dad_tree_expcoll(attr, NULL, 1, 1);

}

static void sheetsel_select_current(sheetsel_ctx_t *ss)
{
	rnd_hid_attribute_t *attr = &ss->sub.dlg[ss->wtree];
	rnd_hid_tree_t *tree = attr->wdata;
	rnd_design_t *curr = rnd_multi_get_current();
	rnd_hid_row_t *r, *actr = NULL;
	htsp_entry_t *e;

	for(e = htsp_first(&tree->paths); e != NULL; e = htsp_next(&tree->paths, e)) {
		r = e->value;
		if (r->user_data == curr)
			actr = e->value;
	}

	/* set cursor to currently active sheet */
	if (actr != NULL) {
		rnd_hid_attr_val_t hv;
		hv.str = actr->path;
		rnd_gui->attr_dlg_set_value(ss->sub.dlg_hid_ctx, ss->wtree, &hv);
	}
}


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

	if ((row == NULL) || (row->user_data == NULL))
		return;

	ctx->lock++;
	sch_rnd_multi_switch_to(row->user_data);
	ctx->lock--;
}

static void sheetsel_docked_create(sheetsel_ctx_t *ss)
{
	RND_DAD_BEGIN_VBOX(ss->sub.dlg);
		RND_DAD_COMPFLAG(ss->sub.dlg, RND_HATF_EXPFILL);

		RND_DAD_TREE(ss->sub.dlg, 1, 1, NULL);
			RND_DAD_COMPFLAG(ss->sub.dlg, RND_HATF_EXPFILL | RND_HATF_SCROLL | RND_HATF_TREE_NO_AUTOEXP);
			RND_DAD_TREE_SET_CB(ss->sub.dlg, selected_cb, sheetsel_select_cb);
			RND_DAD_TREE_SET_CB(ss->sub.dlg, ctx, ss);
			ss->wtree = RND_DAD_CURRENT(ss->sub.dlg);
			RND_DAD_HELP(ss->sub.dlg, sheetsel_tooltip);

	RND_DAD_END(ss->sub.dlg);
	RND_DAD_DEFSIZE(ss->sub.dlg, 210, 200);
	RND_DAD_MINSIZE(ss->sub.dlg, 100, 100);
}


static void sheetsel_build(void)
{
	sheetsel_docked_create(&sheetsel);
	if (rnd_hid_dock_enter(&sheetsel.sub, RND_HID_DOCK_LEFT, "sheetsel") == 0) {
		sheetsel.sub_inited = 1;
		sheetsel_prj2dlg(&sheetsel);
		sheetsel_select_current(&sheetsel);
	}
}

void sch_rnd_sheetsel_gui_init_ev(rnd_design_t *hidlib, void *user_data, int argc, rnd_event_arg_t argv[])
{
	if ((RND_HAVE_GUI_ATTR_DLG) && (rnd_gui->get_menu_cfg != NULL))
		sheetsel_build();
}

void sch_sheetsel_board_changed_ev(rnd_design_t *hidlib, void *user_data, int argc, rnd_event_arg_t argv[])
{
	if (sheetsel.sub_inited && !sheetsel.lock)
		sheetsel_select_current(&sheetsel);
}

void sch_sheetsel_load_post_ev(rnd_design_t *hidlib, void *user_data, int argc, rnd_event_arg_t argv[])
{
	if (sheetsel.sub_inited && !sheetsel.lock) {
		sheetsel_prj2dlg(&sheetsel);
		sheetsel_select_current(&sheetsel);
	}
}

void sch_sheetsel_unload_post_ev(rnd_design_t *hidlib, void *user_data, int argc, rnd_event_arg_t argv[])
{
	sch_sheetsel_load_post_ev(hidlib, user_data, argc, argv);
}

void sch_sheetsel_meta_changed_ev(rnd_design_t *hidlib, void *user_data, int argc, rnd_event_arg_t argv[])
{
	sch_sheetsel_load_post_ev(hidlib, user_data, argc, argv);
}

void sch_sheetsel_fn_changed_ev(rnd_design_t *hidlib, void *user_data, int argc, rnd_event_arg_t argv[])
{
	if (sheetsel.sub_inited && !sheetsel.lock) {
		sheetsel_prj2dlg(&sheetsel);
		sheetsel_select_current(&sheetsel);
	}
}

