/*
 *                            COPYRIGHT
 *
 *  sch-rnd - modular/flexible schematics editor - object access for scripts
 *  Copyright (C) 2023 Tibor 'Igor2' Palinkas
 *
 *  (Supported by NLnet NGI0 Entrust 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/pcb-rnd
 *    lead developer: http://repo.hu/projects/pcb-rnd/contact.html
 *    mailing list: pcb-rnd (at) list.repo.hu (send "subscribe")
 */

/* includeed from act_read.c */

#include <librnd/core/compat_misc.h>
#include <sch-rnd/search.h>
#include <sch-rnd/draw.h>
#include <sch-rnd/crosshair.h>

static const char csch_acts_SearchObjAt[] =
	"SearchObjAt[UnSel|GuiInspect](cursor|crosshair, msg, [r])\n"
	"SearchObjAt[UnSel|GuiInspect](x, y, [r])\n";
static const char csch_acth_SearchObjAt[] = "Return the most preferred object at mouse cursor (or crosshair) or x;y coord; search in a raduis of r coords. The unsel variant ignores selected objects. The GuiInspect variant uses the priorities right-click does. Msg is a string displayed when cursor coord is requested but cursor is not active (see GetXY()). Returns nil or an idpath.";
static fgw_error_t csch_act_SearchObjAt(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	csch_sheet_t *sheet = CSCH_ACT_SHEET;
	const char *actname = argv[0].val.func->name;
	csch_oidpath_t *idp;
	csch_chdr_t *obj;
	rnd_coord_t x, y, r = sch_rnd_slop;

	if ((argv[1].type & FGW_STR) == FGW_STR) {
		const char *where, *msg;
		rnd_coord_t rx, ry;
		int curs, ch = 0;

		RND_ACT_CONVARG(1, FGW_STR, SearchObjAt, where = argv[1].val.str);

		curs = (rnd_strcasecmp(where, "cursor") == 0);
		if (!curs)
			ch = (rnd_strcasecmp(where, "crosshair") == 0);

		if (!curs && !ch)
			goto coords;

		RND_ACT_CONVARG(2, FGW_STR, SearchObjAt, msg = argv[2].val.str);
		rnd_hid_get_coords(msg, &rx, &ry, 0);
		if (curs) {
			x = P2C(rx);
			y = P2C(ry);
		}
		else {
			x = P2C(sch_rnd_crosshair_x);
			y = P2C(sch_rnd_crosshair_y);
		}
	}
	else {
		coords:;
		RND_ACT_CONVARG(1, FGW_COORD, SearchObjAt, x = fgw_coord(&argv[1]));
		RND_ACT_CONVARG(2, FGW_COORD, SearchObjAt, y = fgw_coord(&argv[2]));
	}
	RND_ACT_MAY_CONVARG(3, FGW_COORD, SearchObjAt, r = fgw_coord(&argv[3]));

	switch(actname[11]) {
		case '\0': obj = sch_rnd_search_obj_at(sheet, x, y, r); break;
		case 'u':
		case 'U': obj = sch_rnd_search_obj_at_unsel(sheet, x, y, r); break;
		case 'g':
		case 'G': obj = sch_rnd_search_first_gui_inspect(sheet, C2P(x), C2P(y)); break;
		default:
			rnd_message(RND_MSG_ERROR, "Internal error: SearchObjAt() called with the wrong action name\n");
			return FGW_ERR_ARG_CONV;
	}

	if (obj == NULL)
		return 0;

	idp = calloc(sizeof(csch_oidpath_t), 1);
	csch_oidpath_from_obj(idp, obj);
	res->type = FGW_IDPATH;
	fgw_ptr_reg(&rnd_fgw, res, RND_PTR_DOMAIN_IDPATH, FGW_PTR | FGW_STRUCT, idp);
	return 0;
}

static const char csch_acts_SchGetXY[] = "SchGetXY(cursor|crosshair, msg, X|Y)\n";
static const char csch_acth_SchGetXY[] = "Return the cursor (or crosshair) x or y coord. Msg is a string displayed when cursor coord is requested but cursor is not active (see GetXY()).";
static fgw_error_t csch_act_SchGetXY(fgw_arg_t *res, int argc, fgw_arg_t *argv)
{
	const char *where, *msg, *what;
	rnd_coord_t rx, ry;
	csch_coord_t x, y;

	RND_ACT_CONVARG(1, FGW_STR, SchGetXY, where = argv[1].val.str);
	RND_ACT_CONVARG(2, FGW_STR, SchGetXY, msg = argv[2].val.str);
	RND_ACT_CONVARG(3, FGW_STR, SchGetXY, what = argv[3].val.str);

	rnd_hid_get_coords(msg, &rx, &ry, 0);

	if (rnd_strcasecmp(where, "cursor") == 0) {
		x = P2C(rx);
		y = P2C(ry);
	}
	else if (rnd_strcasecmp(where, "crosshair") == 0) {
		x = P2C(sch_rnd_crosshair_x);
		y = P2C(sch_rnd_crosshair_y);
	}
	else {
		rnd_message(RND_MSG_ERROR, "SchGetXY(): invalid first argument\n");
		return FGW_ERR_ARG_CONV;
	}

	res->type = FGW_LONG;
	switch(*what) {
		case 'x': case 'X': res->val.nat_long = x; break;
		case 'y': case 'Y': res->val.nat_long = y; break;
		default:
			rnd_message(RND_MSG_ERROR, "SchGetXY(): invalid third argument\n");
			return FGW_ERR_ARG_CONV;
	}

	return 0;
}

