/*
 *                            COPYRIGHT
 *
 *  sch-rnd - modular/flexible schematics editor - sheet-local symbol library
 *  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
 */

/* symbol local-lib specific actions */

extern csch_chdr_t *csch_obj_clicked;

static int sym_loc_lib_to_grp(csch_chdr_t *obj)
{
	csch_cgrp_t *grp = (csch_cgrp_t *)obj;

	if (obj->type == CSCH_CTYPE_GRP) {
		rnd_message(RND_MSG_ERROR, "SymLocLib: togrp: target object is already a group\n");
		return -1;
	}
	if (obj->type != CSCH_CTYPE_GRP_REF) {
		rnd_message(RND_MSG_ERROR, "SymLocLib: togrp: target object must be a group reference\n");
		return -1;
	}
	if (grp->role != CSCH_ROLE_SYMBOL) {
		rnd_message(RND_MSG_ERROR, "SymLocLib: togrp: target object is not a symbol\n");
		return -1;
	}

	csch_grp_ref_embed(grp);

	return 0;
}

static int sym_loc_lib_to_ref(csch_chdr_t *obj)
{
	csch_cgrp_t *grp = (csch_cgrp_t *)obj;
	csch_sheet_t *sheet = obj->sheet;

	if (obj->type == CSCH_CTYPE_GRP_REF) {
		rnd_message(RND_MSG_ERROR, "SymLocLib: toref: target object is already a group ref\n");
		return -1;
	}
	if (obj->type != CSCH_CTYPE_GRP) {
		rnd_message(RND_MSG_ERROR, "SymLocLib: toref: target object must be a group\n");
		return -1;
	}

	uundo_freeze_serial(&sheet->undo);

	/* replace grp with a grpref */
	local_paste_place(sheet, &grp);
	csch_op_inserted(sheet, grp->hdr.parent, &grp->hdr);
	csch_op_remove(sheet, obj);

	uundo_unfreeze_serial(&sheet->undo);
	uundo_inc_serial(&sheet->undo);


	return -1;
}

static int doit_selected(csch_cgrp_t *root, int (*doit)(csch_chdr_t *obj))
{
	int res = 0;
	htip_entry_t *e;

	if ((root->role == CSCH_ROLE_SYMBOL) && root->hdr.selected)
		res |= doit(&root->hdr);

	for(e = htip_first(&root->id2obj); e != NULL; e = htip_next(&root->id2obj, e)) {
		csch_cgrp_t *g = e->value;
		if (csch_obj_is_grp(&g->hdr))
			res |= doit_selected(g, doit);
	}

	return res;
}

const char csch_acts_SymLocLib[] = "SymLocLib(object[:idpath]|selected, [toref|togrp])\n";
const char csch_acth_SymLocLib[] = "Convert between \"embedded\" symbols (full copy) and local lib symbol references";
fgw_error_t csch_act_SymLocLib(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	rnd_design_t *hl = RND_ACT_DESIGN;
	csch_sheet_t *sheet = (csch_sheet_t *)hl;
	csch_chdr_t *obj;
	const char *scope, *cmd;
	int selected = 0, quiet = 0;
	int (*doit)(csch_chdr_t *obj);
	int r = 0;

	RND_ACT_MAY_CONVARG(1, FGW_STR, SymLocLib, scope = argv[1].val.str);
	RND_ACT_MAY_CONVARG(2, FGW_STR, SymLocLib, cmd = argv[2].val.str);

	if (strcmp(cmd, "togrp") == 0)
		doit = sym_loc_lib_to_grp;
	else if (strcmp(cmd, "toref") == 0)
		doit = sym_loc_lib_to_ref;
	else {
		rnd_message(RND_MSG_ERROR, "SymLocLib: invalid command '%s'\n", cmd);
		return FGW_ERR_ARG_CONV;
	}

	if (strncmp(scope, "object", 6) == 0) {
		csch_oidpath_t idp = {0};

		if (scope[6] == ':') {
			if (csch_oidpath_parse(&idp, scope+7) != 0) {
				if (!quiet)
					rnd_message(RND_MSG_ERROR, "Failed to convert object ID path: '%s'\n", scope+7);
				return FGW_ERR_ARG_CONV;
			}
			obj = csch_oidpath_resolve(sheet, &idp);
			csch_oidpath_free(&idp);
			if (obj == NULL) {
				if (!quiet)
					rnd_message(RND_MSG_ERROR, "No object by idpath %s\n", scope+7);
				return FGW_ERR_ARG_CONV;
			}
		}
		else {
			obj = csch_obj_clicked;
			if (obj == NULL) {
				if (!quiet)
					rnd_message(RND_MSG_ERROR, "No object under the cursor\n");
				return FGW_ERR_ARG_CONV;
			}
		}
	}
	else if (strcmp(scope, "selected") == 0) {
		selected = 1;
	}

	if (obj != NULL)
		r |= doit(obj);

	if (selected)
		r |= doit_selected(&sheet->direct, doit);

	RND_ACT_IRES(0);
	return 0;
}

static rnd_action_t symlib_local_action_list[] = {
	{"SymLocLib", csch_act_SymLocLib, csch_acth_SymLocLib, csch_acts_SymLocLib}
};

