/*  libgrbs - geometric rubber band sketch model
    Copyright (C) 2021  Tibor 'Igor2' Palinkas
    (Supported by NLnet NGI0 PET Fund in 2021)

    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/libgrbs
      lead developer: http://repo.hu/projects/pcb-rnd/contact.html
*/

/*#define GRBS_ROUTE_REMOVE_TRACE*/

#undef tprinf
#ifdef GRBS_ROUTE_REMOVE_TRACE
#include <stdio.h>
#define tprintf printf
#else
#define tprintf grbs_nullprintf
#endif

/* if there is anything above the new arc, shrink radius pushing the
   above-arcs lower (by exactly as much as twonet tn took) */
static grbs_arc_t *shrink_seg_radii_any(grbs_t *grbs, grbs_arc_t *arc, int *need_narc_post_update, double *narc_oldr_out)
{
	grbs_arc_t *next, *prev;
	double prev_copper, prev_clearance, newr, incr, prevr;
	double narc_oldr = 0, narcr;


	prev = grbs_prev_arc_in_use(arc);

	/* simple case: no convex segments below:
	   previous radius:copper:clearance is the same-segment arc below or the point */
	if ((!arc->in_use) || (prev == NULL)) {
		prev_copper = arc->parent_pt->copper;
		prev_clearance = arc->parent_pt->clearance;
		prevr = 0;
	}
	else {
		prev_copper = prev->copper;
		prev_clearance = prev->clearance;
		prevr = prev->r;
	}

	next = grbs_next_arc_in_use(arc);
	if (next == NULL) {
		*narc_oldr_out = 0;
		return NULL;
	}
	narcr = next->r;

	newr = prevr + prev_copper + next->copper + GRBS_MAX(prev_clearance, next->clearance); /* new arc added on top of the previous */
	tprintf("remove: newr=%f != %f (prev=%f/%f next=%f/%f)\n", newr, narcr, prev_copper, prev_clearance, next->copper, next->clearance);
	if (newr != narcr) {
		narc_oldr = narcr;
		narcr = newr; /* may replace an arc with smaller or larger spacing reqs... */
		tprintf(" new narc r: %f -> %f\n",  narc_oldr, narcr);
		*need_narc_post_update = 1;
	}

	incr = newr - next->r;
	tprintf("decr; narc->r=%f newr=%f oldr=%f incr=%f W: next=%f/%f\n", narcr, newr, next->r, incr, next->copper, next->clearance);

	bump_seg_radii(grbs, next, incr, -1, -1, 1, 0, 1);
	*narc_oldr_out = narc_oldr;
	return next;
}

static void grbs_path_remove_incident(grbs_t *grbs, grbs_arc_t *arc)
{
	grbs_del_arc(grbs, arc);
}

void grbs_path_remove_arc(grbs_t *grbs, grbs_arc_t *arc)
{
	grbs_arc_t *first, *sarc, *sentinel;
	int need_narc_post_update = 0;
	double narc_oldr;
	grbs_point_t *pt;

	if (arc->r == 0) {
		grbs_path_remove_incident(grbs, arc);
		return;
	}

	pt = arc->parent_pt;
	first = sentinel = gdl_first(&pt->arcs[arc->segi]);
	if (!first->new_in_use)
		first = gdl_next(&pt->arcs[arc->segi], first); /* for already realized arcs: first is the first above sentinel */

	/* free room of the arc being removed */
	arc->in_use = 0; /* do not consider this arc in any radii or sentinel calculation */
	sarc = shrink_seg_radii_any(grbs, arc, &need_narc_post_update, &narc_oldr);
	if (arc == first) {
		if (sarc != NULL)
			update_seg_sentinel_angles(sentinel, sarc);
		else
			grbs_del_arc(grbs, sentinel);
	}

	grbs_del_arc(grbs, arc);
}


void grbs_path_remove_addr(grbs_t *grbs, grbs_addr_t *addr)
{
	int type = (addr->type & 0x0F);

	switch(type) {
		case ADDR_ARC_CONVEX:
		case ADDR_ARC_VCONCAVE:
			grbs_path_remove_arc(grbs, addr->obj.arc);
			break;

		case ADDR_POINT:
			/* an address without an actual grbs_arc_t has no further effect - nothing to do here */
			break;

		default: abort();
	}
}


void grbs_path_remove_2net_addrs(grbs_t *grbs, grbs_2net_t *tn)
{
	grbs_arc_t *n, *next;
	for(n = gdl_first(&tn->arcs); n != NULL; n = next) {
		next = gdl_next(&tn->arcs, n);
		grbs_path_remove_arc(grbs, n);
	}
}


void grbs_path_remove_2net(grbs_t *grbs, grbs_2net_t *tn)
{
	grbs_path_remove_2net_addrs(grbs, tn);
	grbs_2net_free(grbs, tn);
}


void grbs_path_remove_line(grbs_t *grbs, grbs_line_t *line)
{
	grbs_line_del(grbs, line);
}

