/*
 *                            COPYRIGHT
 *
 *  pcb-rnd, interactive printed circuit board design - Rubber Band Stretch Router
 *  Copyright (C) 2024,2025 Tibor 'Igor2' Palinkas
 *  (Supported by NLnet NGI0 Entrust in 2024 and 2025)
 *
 *  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")
 */

#include <librnd/core/error.h>
#include <librnd/hid/hid.h>

#include "map.h"
#include "route_helper.h"

/* Iterate through all grbs arcs within a 2*delta sized box around cx;cy and
   find the closest parent_t to cx;cy */
RND_INLINE grbs_point_t *rbsr_find_point_by_arc_thick(rbsr_map_t *rbs, rnd_coord_t cx_, rnd_coord_t cy_, double bestd2, double delta)
{
	double cx = RBSR_R2G(cx_), cy = RBSR_R2G(cy_);
	grbs_arc_t *arc;
	grbs_point_t *best = NULL;
	grbs_rtree_it_t it;
	grbs_rtree_box_t bbox;

	bbox.x1 = cx - delta;
	bbox.y1 = cy - delta;
	bbox.x2 = cx + delta;
	bbox.y2 = cy + delta;

	for(arc = grbs_rtree_first(&it, &rbs->grbs.arc_tree, &bbox); arc != NULL; arc = grbs_rtree_next(&it)) {
		grbs_point_t *pt = arc->parent_pt;
		double dx = cx - pt->x, dy = cy - pt->y, d2 = dx*dx + dy*dy;
		if (d2 < bestd2) {
			bestd2 = d2;
			best = pt;
		}
	}

	return best;
}

grbs_point_t *rbsr_crosshair_get_pt(rbsr_map_t *rbs, rnd_coord_t tx, rnd_coord_t ty, int allow_incident, int *refuse_incident)
{
	grbs_point_t *end;
	double gslop;

	gslop = (double)rnd_pixel_slop * 100;
	if (gslop < RND_MM_TO_COORD(1))
		gslop = RND_MM_TO_COORD(1);
	else if (gslop > RND_MM_TO_COORD(3))
		gslop = RND_MM_TO_COORD(3);

	gslop = RBSR_R2G(gslop);
	end = rbsr_find_point_thick(rbs, tx, ty, gslop);
	if (allow_incident && (end == NULL)) {
		if (refuse_incident != 0)
			*refuse_incident = 0;
		end = rbsr_find_point_by_arc_thick(rbs, tx, ty, RND_COORD_MAX, gslop);
	}

	return end;
}

grbs_arc_dir_t rbsr_crosshair_get_pt_dir(rbsr_map_t *rbs, rnd_coord_t fromx, rnd_coord_t fromy, rnd_coord_t tx, rnd_coord_t ty, grbs_point_t *end)
{
	rnd_coord_t ptcx, ptcy;
	double l1x, l1y, l2x, l2y, px, py, side, dist2, dx, dy, cop2;

	if (end->RBSR_INCIDENT_ONLY)
		return GRBS_ADIR_INC;

	ptcx = RBSR_G2R(end->x);
	ptcy = RBSR_G2R(end->y);

	cop2 = RBSR_G2R(end->copper);
	cop2 = cop2 * cop2;

	dx = tx - ptcx; dy = ty - ptcy;
	dist2 = dx*dx + dy*dy;

	if (dist2 > cop2) {
		/* project target point onto the line between last end and center of the
		   point; if it is to the right, go ccw, if to the left go cw, if in the
		   center go incident */
		/* decide direction from cross product; line is from* -> ptc* */
		l1x = fromx; l1y = fromy;
		l2x = ptcx, l2y = ptcy;
		px = tx; py = ty;

		side = (l2x - l1x) * (py - l1y) - (l2y - l1y) * (px - l1x);
		rnd_trace(" side: %f %s\n", side, (side < 0) ? "cw" : "ccw");
		return (side < 0) ? GRBS_ADIR_CONVEX_CW : GRBS_ADIR_CONVEX_CCW;
	}

	return GRBS_ADIR_INC;
}
