/*
 *                            COPYRIGHT
 *
 *  sch-rnd - modular/flexible schematics editor - back annotation
 *  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., 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 <libcschem/config.h>

#include <assert.h>

#include <libcschem/event.h>
#include <libcschem/search.h>
#include <libcschem/util_grp.h>
#include <librnd/core/actions.h>
#include <librnd/core/plugins.h>

static const char sch_backann_cookie[] = "backann plugin";

#define GVT_DONT_UNDEF
#include "backann.h"

#define GVT_REALLOC(vect, ptr, size)  realloc(ptr, size)
#define GVT_FREE(vect, ptr)           free(ptr)
#include <genvector/genvector_impl.c>


#include "check_ba.h"
#include "auto_ba.h"

#include "dlg_ba.c"
#include "parse_backann.c"

htpp_t sch_rnd_prj2backann;
int sch_rnd_prj2backann_inited;

void sch_rnd_backann_uninit(sch_rnd_backann_t *ctx)
{
	assert(sch_rnd_prj2backann_inited);
	htpp_pop(&sch_rnd_prj2backann, (csch_project_t *)ctx->sheet->hidlib.project);
	backann_free_list(ctx);
	free(ctx);
}

static void sch_rnd_backann_close(sch_rnd_backann_t *ctx)
{
	rnd_dad_retovr_t retovr = {0};
	rnd_hid_dad_close(ctx->dlg_hid_ctx, &retovr, 0);
}

void sch_rnd_backann_update(sch_rnd_backann_t *ctx)
{
	sch_rnd_backann_check(ctx);
	backann_data2dlg(ctx);
}

static void backann_init_dlgs(void)
{
	if (!sch_rnd_prj2backann_inited) {
		htpp_init(&sch_rnd_prj2backann, ptrhash, ptrkeyeq);
		sch_rnd_prj2backann_inited = 1;
	}
}

void sch_rnd_backann_present(sch_rnd_backann_t *pctx)
{
	backann_init_dlgs();
	sch_rnd_backann_check(pctx);
	backann_dlg(pctx);
	htpp_set(&sch_rnd_prj2backann, (csch_project_t *)pctx->sheet->hidlib.project, pctx);
}

static const char csch_acts_Backann[] = "Backann([filename])\n";
static const char csch_acth_Backann[] = "Load a back annotation file for interactive back annotation";
static fgw_error_t csch_act_Backann(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	rnd_design_t *hidlib = RND_ACT_DESIGN;
	sch_rnd_backann_t ctx = {0}, *pctx;

	backann_init_dlgs();

	ctx.sheet = (csch_sheet_t *)hidlib;
	RND_ACT_MAY_CONVARG(1, FGW_STR, Backann, ctx.fn = argv[1].val.str);

	if (ctx.fn == NULL) {
		static char *default_file = NULL;
		static const char *flt_bap[] = {"*.bap", NULL};
		static const char *flt_any[] = {"*", "*.*", NULL};
		const rnd_hid_fsd_filter_t flt[] = {
			{"pcb-rnd back annotation",            NULL, flt_bap},
			{"all",                                NULL, flt_any},
			{NULL, NULL,NULL}
		};

		ctx.fn = rnd_hid_fileselect(rnd_gui,
			"Load back annotation file...", "Picks a back annotation file\n",
			default_file, ".bap", flt, "backann", RND_HID_FSD_READ, NULL);

		free(default_file);
		default_file = NULL;

		if (ctx.fn == NULL) {
			RND_ACT_IRES(1);
			return 0; /* cancel */
		}
	}

	pctx = htpp_get(&sch_rnd_prj2backann, (csch_project_t *)ctx.sheet->hidlib.project);
	if (pctx != NULL) {
		RND_ACT_IRES(1);
		rnd_message(RND_MSG_ERROR, "A back annotation session is already active for this project\n");
		return 0;
	}


	if (backann_parse(&ctx) != 0) {
		RND_ACT_IRES(1);
		return 0;
	}

	/* make ctx permament */
	pctx = malloc(sizeof(sch_rnd_backann_t));
	memcpy(pctx, &ctx, sizeof(sch_rnd_backann_t));

	sch_rnd_backann_present(pctx);

	RND_ACT_IRES(0);
	return 0;
}

static rnd_action_t sch_backann_action_list[] = {
	{"Backann", csch_act_Backann, csch_acth_Backann, csch_acts_Backann},
};

static void backann_ev_compiled(rnd_design_t *hidlib, void *user_data, int argc, rnd_event_arg_t argv[])
{
	htpp_entry_t *e;

	if (!sch_rnd_prj2backann_inited) return;

	for(e = htpp_first(&sch_rnd_prj2backann); e != NULL; e = htpp_next(&sch_rnd_prj2backann, e)) {
		sch_rnd_backann_t *ctx = e->value;
		if (&ctx->sheet->hidlib == hidlib)
			sch_rnd_backann_update(e->value);
	}
}

static void backann_ev_preunload(rnd_design_t *hidlib, void *user_data, int argc, rnd_event_arg_t argv[])
{
	htpp_entry_t *e;

	if (!sch_rnd_prj2backann_inited) return;

	for(e = htpp_first(&sch_rnd_prj2backann); e != NULL; e = htpp_next(&sch_rnd_prj2backann, e)) {
		sch_rnd_backann_t *ctx = e->value;
		if (&ctx->sheet->hidlib == hidlib)
			sch_rnd_backann_close(ctx);
	}
}



int pplg_check_ver_backann(int ver_needed) { return 0; }

void pplg_uninit_backann(void)
{
	if (sch_rnd_prj2backann_inited) {
		htpp_entry_t *e;

		for(e = htpp_first(&sch_rnd_prj2backann); e != NULL; e = htpp_next(&sch_rnd_prj2backann, e))
			sch_rnd_backann_close(e->value);
	}

	rnd_remove_actions_by_cookie(sch_backann_cookie);
	rnd_event_unbind_allcookie(sch_backann_cookie);
	if (sch_rnd_prj2backann_inited) {
		htpp_uninit(&sch_rnd_prj2backann);
		sch_rnd_prj2backann_inited = 0;
	}
}

int pplg_init_backann(void)
{
	RND_API_CHK_VER;

	RND_REGISTER_ACTIONS(sch_backann_action_list, sch_backann_cookie);

	rnd_event_bind(CSCH_EVENT_PRJ_COMPILED, backann_ev_compiled, NULL, sch_backann_cookie);
	rnd_event_bind(CSCH_EVENT_SHEET_PREUNLOAD, backann_ev_preunload, NULL, sch_backann_cookie);

	return 0;
}

