/*
 *                            COPYRIGHT
 *
 *  cschem - modular/flexible schematics editor - sch-rnd (executable)
 *  Copyright (C) 2023 Tibor 'Igor2' Palinkas
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.*
 *
 *  This library 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
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; 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 "config.h"

#include "cnc_line.h"
#include "intersect.h"
#include <gengeo2d/cline.h>

#include "util_endpoint.h"

typedef struct find_wire_s {
	csch_sheet_t *sheet;
	csch_chdr_t *obj;
	htepu_t *dst;
	int (*incl)(void *udata, csch_chdr_t *obj);
	void *udata;
} find_wire_t;

static csch_rtree_dir_t find_wire_cb(void *ctx_, void *obj_, const csch_rtree_box_t *box)
{
	find_wire_t *ctx = (find_wire_t *)ctx_;
	csch_line_t *line = obj_;

	if (obj_ == ctx->obj)
		return csch_RTREE_DIR_NOT_FOUND_CONT;

	if ((line->hdr.type == CSCH_CTYPE_LINE) && (line->hdr.parent != NULL) && (line->hdr.parent->role == CSCH_ROLE_WIRE_NET)) {
		g2d_vect_t iscp[2];
		long len, n;
		int zerolen = 0;

		if (line->hdr.parent != ctx->obj->parent)
			return csch_RTREE_DIR_NOT_FOUND_CONT;

		if ((ctx->incl != NULL) && (!ctx->incl(ctx->udata, &line->hdr)))
			return csch_RTREE_DIR_NOT_FOUND_CONT;

		if ((line->inst.c.p1.x == line->inst.c.p2.x) && (line->inst.c.p1.y == line->inst.c.p2.y))
			zerolen = 1;

		len = csch_obj_intersect_obj(ctx->sheet, ctx->obj, &line->hdr, iscp, 2);
		for(n = 0; n < len; n++) {
			htepu_key_t key;
			htepu_value_t val = {0};
			key.obj = &line->hdr;
			key.x = iscp[n].x;
			key.y = iscp[n].y;
			val.newx = iscp[n].x;
			val.newy = iscp[n].y;
			if ((key.x == line->inst.c.p1.x) && (key.y == line->inst.c.p1.y)) {
				if (zerolen)
					key.epi = CSCH_EPI_ALL;
				else
					key.epi = CSCH_EPI_START;
			}
			else if ((key.x == line->inst.c.p2.x) && (key.y == line->inst.c.p2.y))
				key.epi = CSCH_EPI_END;
			else
				key.epi = CSCH_EPI_MID;
			htepu_insert(ctx->dst, key, val);
		}
		return csch_RTREE_DIR_FOUND_CONT;
	}
	return csch_RTREE_DIR_NOT_FOUND_CONT;
}


void csch_endpoint_list_connected(csch_sheet_t *sheet, htepu_t *dst, csch_chdr_t *obj, int (*incl)(void *udata, csch_chdr_t *obj), void *udata)
{
	find_wire_t ctx = {0};
	csch_rtree_box_t query;

	if (obj->type != CSCH_CTYPE_LINE)
		return; /* only line is supported now */

	ctx.sheet = sheet;
	ctx.obj = obj;
	ctx.dst = dst;
	ctx.incl = incl;
	ctx.udata = udata;

	query.x1 = obj->bbox.x1-1; query.y1 = obj->bbox.y1-1;
	query.x2 = obj->bbox.x2+1; query.y2 = obj->bbox.y2+1;
	csch_rtree_search_obj(&sheet->dsply[CSCH_DSPLY_WIRE], &query, find_wire_cb, &ctx);
}
