/*  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
*/

/* remove the 'new' */
static void grbs_detach_addr_(grbs_t *grbs, grbs_detached_addr_t dst[3], grbs_addr_t *addr, int call_cnt)
{
	dst->type = addr->type;
	dst->user_data = addr->user_data;


	switch(addr->type & 0x0F) {
		case ADDR_ARC_VCONCAVE:
			assert(call_cnt == 0);
			dst->pt = addr->obj.arc->parent_pt;
			grbs_detach_addr_(grbs, dst+1, addr->last_real, call_cnt+1); /* pack from_addr */
			break;

		case ADDR_ARC_CONVEX:
			assert(addr->obj.arc->new_in_use);

			dst->pt = addr->obj.arc->parent_pt;
			dst->new_sa = addr->obj.arc->new_sa;
			dst->new_da = addr->obj.arc->new_da;
			dst->new_r = addr->obj.arc->new_r;
			dst->new_adir = addr->obj.arc->new_adir;

			if (!addr->obj.arc->in_use) {
				assert(addr->obj.arc->link_point.prev == NULL); /* this should be a sentinel */
				dst->arc = NULL;
			}
			else
				dst->arc = addr->obj.arc;

			addr->obj.arc->new_in_use = 0;
			if (call_cnt < 2)
				grbs_detach_addr_(grbs, dst+1, addr->last_real, call_cnt+1); /* pack from_addr */

			if (grbs_clean_unused_sentinel_seg(grbs, addr->obj.arc->parent_pt, addr->obj.arc->segi, 1))
				dst->arc = NULL; /* sentinel got removed */
			break;
		case ADDR_POINT:
			dst->arc = NULL;
			dst->pt = addr->obj.pt;
			break;
	}
}

void grbs_detach_addr(grbs_t *grbs, grbs_detached_addr_t dst[3], grbs_addr_t *addr)
{
	memset(dst, 0, sizeof(grbs_detached_addr_t)*3);
	grbs_detach_addr_(grbs, dst, addr, 0);
}

static grbs_addr_t *grbs_reattach_addr_(grbs_t *grbs, grbs_detached_addr_t src[3], int call_cnt)
{
	grbs_addr_t *addr = grbs_addr_new(grbs, src->type, NULL);

	addr->user_data = src->user_data;
	addr->last_real = NULL;

	switch(src->type & 0x0F) {
		case ADDR_ARC_VCONCAVE:
			assert(call_cnt == 0);
			addr->obj.arc = grbs_arc_new(grbs, src->pt, 0, 0, 0, 0);
			addr->obj.arc->new_in_use = 1;
			addr->obj.arc->vconcave = 1;
			addr->last_real = grbs_reattach_addr_(grbs, src+1, call_cnt+1);
			break;

		case ADDR_ARC_CONVEX:
			if (src->arc == NULL) {
				int segi;
				/* need to allocate a new sentinel */
				addr->obj.arc = grbs_new_sentinel(grbs, src->pt, src->new_sa, src->new_da, &segi);
				addr->obj.arc->segi = segi;
			}
			else {
				addr->obj.arc = src->arc;
				assert(!addr->obj.arc->new_in_use);
			}

			addr->obj.arc->new_r = src->new_r;
			addr->obj.arc->new_sa = src->new_sa;
			addr->obj.arc->new_da = src->new_da;
			addr->obj.arc->new_adir = src->new_adir;
			addr->obj.arc->new_in_use = 1;
			if (call_cnt < 2)
				addr->last_real = grbs_reattach_addr_(grbs, src+1, call_cnt+1);
			break;

		case ADDR_POINT:
			addr->obj.pt = src->pt;
			addr->last_real = addr;
			break;
	}

	return addr;
}

grbs_addr_t *grbs_reattach_addr(grbs_t *grbs, grbs_detached_addr_t src[3])
{
	return grbs_reattach_addr_(grbs, src, 0);
}
