/*
 *                            COPYRIGHT
 *
 *  cschem - modular/flexible schematics editor - libcschem (core library)
 *  Copyright (C) 2022 Tibor 'Igor2' Palinkas
 *
 *  (Supported by NLnet NGI0 PET Fund in 2022)
 *
 *  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 "concrete.h"
#include "cnc_line.h"
#include "cnc_arc.h"
#include "cnc_poly.h"
#include "cnc_grp.h"

#include <gengeo2d/cline.h>
#include <gengeo2d/carc.h>
#include <gengeo2d/intersect.h>

#include "intersect.h"

static long csch_obj_intersect_obj_(csch_chdr_t *o1, csch_chdr_t *o2, g2d_vect_t **iscp, long *iscp_len);

RND_INLINE void isc_append(g2d_vect_t **dst, long *dst_len, g2d_vect_t *src, long src_len)
{
	long n;

	for(n = 0; n < src_len; n++) {
		if (*dst_len == 0)
			return;
		**dst = *src;
		(*dst)++;
		(*dst_len)--;
		src++;
	}
}

RND_INLINE long isc_ll(csch_line_t *l1, csch_line_t *l2, g2d_vect_t **iscp, long *iscp_len)
{
	if (*iscp != NULL) {
		g2d_vect_t ip[2];
		int res = g2d_iscp_cline_cline(&l1->inst.c, &l2->inst.c, ip, NULL);
		isc_append(iscp, iscp_len, ip, res);
		return res;
	}
	else
		return g2d_isc_sline_sline(&l1->inst, &l2->inst);
}

RND_INLINE long isc_la(csch_line_t *l, csch_arc_t *a, g2d_vect_t **iscp, long *iscp_len)
{
	if (*iscp != NULL) {
		g2d_vect_t ip[2];
		int res = g2d_iscp_cline_carc(&l->inst.c, &a->inst.c, ip, NULL, 0);
		isc_append(iscp, iscp_len, ip, res);
		return 0;
	}
	else
		return g2d_isc_sline_sarc(&l->inst, &a->inst);
}

RND_INLINE long isc_aa(csch_arc_t *a1, csch_arc_t *a2, g2d_vect_t **iscp, long *iscp_len)
{
	TODO("g2d needs arc-arc intersection calculations");
	return 0;
}

RND_INLINE long isc_po(csch_cpoly_t *p, csch_chdr_t *o, g2d_vect_t **iscp, long *iscp_len)
{
	long n, res = 0;
	for(n = 0; n < p->outline.used; n++) {
		csch_chdr_t *po = &p->outline.array[n].hdr;
		res += csch_obj_intersect_obj_(po, o, iscp, iscp_len);
	}
	return res;
}

RND_INLINE long isc_pp(csch_cpoly_t *p1, csch_cpoly_t *p2, g2d_vect_t **iscp, long *iscp_len)
{
	long n, res = 0;
	for(n = 0; n < p1->outline.used; n++) {
		csch_chdr_t *po = &p1->outline.array[n].hdr;
		res += isc_po(p2, po, iscp, iscp_len);
	}
	return res;
}

RND_INLINE long isc_go(csch_cgrp_t *g, csch_chdr_t *o, g2d_vect_t **iscp, long *iscp_len)
{
	long res = 0;
	htip_entry_t *e;
	for(e = htip_first(&g->id2obj); e != NULL; e = htip_next(&g->id2obj, e)) {
		csch_chdr_t *go = e->value;
		res += csch_obj_intersect_obj_(go, o, iscp, iscp_len);
	}
	return res;
}

RND_INLINE long isc_gg(csch_cgrp_t *g1, csch_cgrp_t *g2, g2d_vect_t **iscp, long *iscp_len)
{
	long res = 0;
	htip_entry_t *e;
	for(e = htip_first(&g1->id2obj); e != NULL; e = htip_next(&g1->id2obj, e)) {
		csch_chdr_t *go = e->value;
		res += isc_go(g2, go, iscp, iscp_len);
	}
	return res;
}



static long csch_obj_intersect_obj_(csch_chdr_t *o1, csch_chdr_t *o2, g2d_vect_t **iscp, long *iscp_len)
{
	switch(o1->type) {
		case CSCH_CTYPE_LINE:
			switch(o2->type) {
				case CSCH_CTYPE_LINE:     return isc_ll((csch_line_t *)o1, (csch_line_t *)o2, iscp, iscp_len);
				case CSCH_CTYPE_ARC:      return isc_la((csch_line_t *)o1, (csch_arc_t *)o2, iscp, iscp_len);
				case CSCH_CTYPE_POLY:     return isc_po((csch_cpoly_t *)o2, o1, iscp, iscp_len);
				case CSCH_CTYPE_GRP:      /* intentional fall-through */
				case CSCH_CTYPE_GRP_REF:  return isc_go((csch_cgrp_t *)o2, o1, iscp, iscp_len);
				case CSCH_CTYPE_TEXT:     return 0;
				case CSCH_CTYPE_BITMAP:   return 0;
				case CSCH_CTYPE_CONN:     return 0;
				case CSCH_CTYPE_PEN:      return 0;
				case CSCH_CTYPE_invalid:  return 0;
				case CSCH_CTYPE_max:      return 0;
			}
			return 0;
		case CSCH_CTYPE_ARC:
			switch(o2->type) {
				case CSCH_CTYPE_LINE:     return isc_la((csch_line_t *)o2, (csch_arc_t *)o1, iscp, iscp_len);
				case CSCH_CTYPE_ARC:      return isc_aa((csch_arc_t *)o2, (csch_arc_t *)o1, iscp, iscp_len);
				case CSCH_CTYPE_POLY:     return isc_po((csch_cpoly_t *)o2, o1, iscp, iscp_len);
				case CSCH_CTYPE_GRP:      /* intentional fall-through */
				case CSCH_CTYPE_GRP_REF:  return isc_go((csch_cgrp_t *)o2, o1, iscp, iscp_len);
				case CSCH_CTYPE_TEXT:     return 0;
				case CSCH_CTYPE_BITMAP:   return 0;
				case CSCH_CTYPE_CONN:     return 0;
				case CSCH_CTYPE_PEN:      return 0;
				case CSCH_CTYPE_invalid:  return 0;
				case CSCH_CTYPE_max:      return 0;
			}
			return 0;
		case CSCH_CTYPE_POLY:
			switch(o2->type) {
				case CSCH_CTYPE_LINE:     /* intentional fall-through */
				case CSCH_CTYPE_ARC:      return isc_po((csch_cpoly_t *)o1, o2, iscp, iscp_len);
				case CSCH_CTYPE_POLY:     return isc_pp((csch_cpoly_t *)o1, (csch_cpoly_t *)o2, iscp, iscp_len);
				case CSCH_CTYPE_GRP:      /* intentional fall-through */
				case CSCH_CTYPE_GRP_REF:  return isc_go((csch_cgrp_t *)o2, o1, iscp, iscp_len);
				case CSCH_CTYPE_TEXT:     return 0;
				case CSCH_CTYPE_BITMAP:   return 0;
				case CSCH_CTYPE_CONN:     return 0;
				case CSCH_CTYPE_PEN:      return 0;
				case CSCH_CTYPE_invalid:  return 0;
				case CSCH_CTYPE_max:      return 0;
			}
			return 0;
		case CSCH_CTYPE_GRP:
		case CSCH_CTYPE_GRP_REF:
			switch(o2->type) {
				case CSCH_CTYPE_LINE:     /* intentional fall-through */
				case CSCH_CTYPE_ARC:      /* intentional fall-through */
				case CSCH_CTYPE_POLY:     return isc_go((csch_cgrp_t *)o1, o2, iscp, iscp_len);
				case CSCH_CTYPE_GRP:      /* intentional fall-through */
				case CSCH_CTYPE_GRP_REF:  return isc_gg((csch_cgrp_t *)o1, (csch_cgrp_t *)o2, iscp, iscp_len);
				case CSCH_CTYPE_TEXT:     return 0;
				case CSCH_CTYPE_BITMAP:   return 0;
				case CSCH_CTYPE_CONN:     return 0;
				case CSCH_CTYPE_PEN:      return 0;
				case CSCH_CTYPE_invalid:  return 0;
				case CSCH_CTYPE_max:      return 0;
			}
			return 0;

		case CSCH_CTYPE_TEXT:
		case CSCH_CTYPE_BITMAP:
		case CSCH_CTYPE_CONN:
		case CSCH_CTYPE_PEN:
		case CSCH_CTYPE_invalid:
		case CSCH_CTYPE_max:
			return 0;
	}
	return 0;
}

long csch_obj_intersect_obj(csch_sheet_t *sheet, csch_chdr_t *o1, csch_chdr_t *o2, g2d_vect_t *iscp, long iscp_len)
{
	return csch_obj_intersect_obj_(o1, o2, &iscp, &iscp_len);

}
