#ifndef CSCH_UTIL_WIRENET_H
#define CSCH_UTIL_WIRENET_H

#include <libcschem/cnc_line.h>

/* Create a line object to be part of a wire-net. Undoable. There are three
   cases on which wirenet:
   - if either end is connected to a wirenet, or both ends connected to the
     same wirenet, the line is created within that wirenet group
   - if one end is connected to one wirenet and the other end is connected
     to another wirenet, the wirenet at x2;y2 is merged into the wirenet at
     x1;y1 and the new line is added in the remaining wirenet group
   - if neither endpoint lands on an existing wirenet, a new wirenet group
     is created.

   Returns the new line object.
*/
csch_chdr_t *csch_wirenet_draw(csch_sheet_t *sheet, csch_comm_str_t stroke_name, csch_coord_t x1, csch_coord_t y1, csch_coord_t x2, csch_coord_t y2);

/* Recalculate all junction marks on a wirenet, removing stale ones and
   adding new ines where multiple lines are crossing */
void csch_wirenet_recalc_junctions(csch_sheet_t *sheet, csch_cgrp_t *wirenet);

/* Recalculate wirenets after a line has changed geometry if the line was
   in a wirenet. Potential outcome include:
   - wirenet split in two if the bridge object is (re)moved
   - two or more wirenets merged
   - input line object changes its parent (jumps wirenet)
*/
void csch_wirenet_recalc_line_chg(csch_sheet_t *sheet, csch_line_t *line);

/* Return true if object is a wirenet junction */
RND_INLINE int csch_obj_is_junction(csch_chdr_t *obj);

void csch_recalc_obj_conn(csch_sheet_t *sheet, csch_chdr_t *wobj, csch_displayer_t target, csch_displayer_t target2);

/* Inhibit wirenet recalculations and recalculate everything once at the end;
   useful during multiple wirenet line manipulation operations bundled */
void csch_wirenet_recalc_freeze(csch_sheet_t *sheet);
void csch_wirenet_recalc_unfreeze(csch_sheet_t *sheet);


void csch_wirenet_recalc_obj_conn(csch_sheet_t *sheet, csch_chdr_t *wobj);

/* Count number of junctions on a wire object wno. If mid_cnt_out is not NULL,
   load it with the number of junctions that are not falling at either
   endpoint of wno. */
int csch_wire_count_junctions(csch_chdr_t *wno, int *mid_cnt_out);

/* Returns true if line between x1;y1 and x2;y2 is safe to draw: a random
   other line won't have its endpoint in the middle of the new line */
int csch_is_wireline_safe(csch_sheet_t *sheet, csch_coord_t x1, csch_coord_t y1, csch_coord_t x2, csch_coord_t y2);

/* Called after an object is removed from a wirenet; removes floaters if the
   wirenet is empty */
void csch_wirenet_post_remove_checks(csch_sheet_t *sheet, csch_cgrp_t *wn, int undoable);

/* Return the wire that's at x;y; if ignore_line is not NULL, ignore that
   object (useful if there are multiple lines on the same spot) */
csch_line_t *csch_find_wire_at(csch_sheet_t *sheet, csch_coord_t x, csch_coord_t y, csch_chdr_t *ignore_line);


/*** low level ***/

/* Create a new wire line within a wirenet without updating or recalculating
   the wirenet */
csch_line_t *csch_wirenet_draw_line_in(csch_sheet_t *sheet, csch_cgrp_t *parent, csch_comm_str_t stroke_name, csch_coord_t x1, csch_coord_t y1, csch_coord_t x2, csch_coord_t y2);

/* merges any lines that connect with "line" from within the same wirenet and
   has the same direction; if remove_overlap is 0, line is never removed;
   if remove_overlap is 1, if line fully overlaps with an existing wire from
   one end of that wire, the wire is truncated (and line is removed) */
void csch_wirenet_recalc_merge(csch_sheet_t *sheet, csch_line_t *line, int remove_overlap);


/*** implementation ***/
RND_INLINE int csch_obj_is_junction(csch_chdr_t *obj)
{
	/* simplest case: zero-length line is implied to be a junction */
	if (obj->type == CSCH_CTYPE_LINE) {
		csch_line_t *line = (csch_line_t *)obj;
		if ((line->spec.p1.x == line->spec.p2.x) && (line->spec.p1.y == line->spec.p2.y))
			return 1;
	}

	/* non-line drawing object, or line with non-zero length: check if parent is a junction grp */
	if (!csch_obj_is_grp(obj))
		obj = &obj->parent->hdr;

	if (csch_obj_is_grp(obj)) { /* more complex junction graphics must go in a role=junction grp */
		csch_cgrp_t *grp = (csch_cgrp_t *)obj;
		return (grp->role == CSCH_ROLE_JUNCTION);
	}

	return 0; /* anything else is wire */
}

#endif
