/*
 *                            COPYRIGHT
 *
 *  sch-rnd - modular/flexible schematics editor - sch-rnd (executable)
 *  Copyright (C) 2022,2023 Tibor 'Igor2' Palinkas
 *
 *  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/core/actions.h>
#include <librnd/core/conf.h>
#include <librnd/core/compat_misc.h>
#include <librnd/core/project.h>

#include <libcschem/concrete.h>
#include <libcschem/search.h>
#include <libcschem/operation.h>
#include <libcschem/util_wirenet.h>

#include "funchash_core.h"
#include "conf_core.h"
#include "select.h"

static const char csch_acts_RemoveSelected[] = "RemoveSelected()";
static const char csch_acth_RemoveSelected[] = "Remove all selected objects";
static fgw_error_t csch_act_RemoveSelected(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	csch_sheet_t *sheet = CSCH_ACT_SHEET;
	vtp0_t sel = {0};
	long n;

	uundo_freeze_serial(&sheet->undo);

	csch_wirenet_recalc_freeze(sheet);

	/* First remove top level (groups); this will remove some selected
	   group-part-objects as well */
	csch_search_all_selected(sheet, NULL, &sel, 0);
	for(n = 0; n < sel.used; n++) {
		csch_chdr_t *obj = sel.array[n];
		if (obj->parent != NULL) /* group removal may have removed it already; e.g. wirenet group's name floater */
			csch_op_remove(sheet, obj);
	}
	sel.used = 0;

	csch_wirenet_recalc_unfreeze(sheet);

	/* Search again recursively; this will catch group-part objects that
	   were selected without parent group selection; remove only floaters */
	csch_search_all_selected(sheet, NULL, &sel, 1);
	for(n = 0; n < sel.used; n++) {
		csch_chdr_t *obj = sel.array[n];
		if (obj->floater)
			csch_op_remove(sheet, obj);
	}
	vtp0_uninit(&sel);

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

	RND_ACT_IRES(0);
	return 0;
}

static const char csch_acts_Select[] = "Select([All|Invert])";
static const char csch_acth_Select[] = "Select objects; all=all visible; invert=invert selection; default is all.";
static fgw_error_t csch_act_Select(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	int op = F_All;

	RND_ACT_MAY_CONVARG(1, FGW_KEYWORD, Select, op = fgw_keyword(&argv[1]));

	switch(op) {
		case F_All:
			sch_rnd_select_box(CSCH_ACT_SHEET, -CSCH_COORD_MAX, -CSCH_COORD_MAX, CSCH_COORD_MAX, CSCH_COORD_MAX);
			break;
		case F_Invert:
			sch_rnd_select_invert(CSCH_ACT_SHEET);
			break;
		default:
			rnd_message(RND_MSG_ERROR, "Invalid first arg for Select(); Syntax: %s\n", csch_acts_Select);
			RND_ACT_IRES(-1);
			return 0;
	}
	RND_ACT_IRES(0);
	return 0;
}

static const char csch_acts_UnSelect[] = "UnSelect([All|AllProject])";
static const char csch_acth_UnSelect[] = "Unselect all objects. When first argument is omitted or is All, the action operates on the current sheet. When the first argument is AllProject, it operates on all sheets of the current project.";
static fgw_error_t csch_act_UnSelect(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	csch_sheet_t *sheet = CSCH_ACT_SHEET;
	const char *op = "All";
	RND_ACT_MAY_CONVARG(1, FGW_STR, UnSelect, op = argv[1].val.str);

	if (rnd_strcasecmp(op, "allproject") == 0) {
		rnd_project_t *prj = sheet->hidlib.project;
		long n;

		for(n = 0; n < prj->designs.used; n++)
			sch_rnd_unselect_all(prj->designs.array[n]);
	}
	else
		sch_rnd_unselect_all(sheet);
	RND_ACT_IRES(0);
	return 0;
}

static const char csch_acts_ToggleFloaters[] = "ToggleFloaters(only|lock)";
static const char csch_acth_ToggleFloaters[] = "Toggle the setting for only-floaters ot lock-floaters";
static fgw_error_t csch_act_ToggleFloaters(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	int op = F_All;

	RND_ACT_MAY_CONVARG(1, FGW_KEYWORD, Select, op = fgw_keyword(&argv[1]));

	switch(op) {
		case F_Only:
			rnd_conf_toggle_editor(only_floaters);
			rnd_conf_set_editor(lock_floaters, 0);
			break;
		case F_Lock:
			rnd_conf_toggle_editor(lock_floaters);
			rnd_conf_set_editor(only_floaters, 0);
			break;
		default:
			rnd_message(RND_MSG_ERROR, "Invalid first arg for ToggleFloaters(); Syntax: %s\n", csch_acts_Select);
			RND_ACT_IRES(-1);
			return 0;
	}

	RND_ACT_IRES(0);
	return 0;
}

static rnd_action_t file_action_list[] = {
	{"RemoveSelected", csch_act_RemoveSelected, csch_acth_RemoveSelected, csch_acts_RemoveSelected},
	{"Select", csch_act_Select, csch_acth_Select, csch_acts_Select},
	{"UnSelect", csch_act_UnSelect, csch_acth_UnSelect, csch_acts_UnSelect},
	{"ToggleFloaters", csch_act_ToggleFloaters, csch_acth_ToggleFloaters, csch_acts_ToggleFloaters}
};

void sch_rnd_select_act_init2(void)
{
	RND_REGISTER_ACTIONS(file_action_list, NULL);
}

