/*
 *                            COPYRIGHT
 *
 *  pcb-rnd, interactive printed circuit board design - map junftions and 2nets
 *  Copyright (C) 2025 Tibor 'Igor2' Palinkas
 *  (Supported by NLnet NGI0 Entrust in 2025)
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 31 Milk Street, # 960789 Boston, MA 02196 USA.
 *
 *  Contact:
 *    Project page: http://repo.hu/projects/pcb-rnd
 *    lead developer: http://repo.hu/projects/pcb-rnd/contact.html
 *    mailing list: pcb-rnd (at) list.repo.hu (send "subscribe")
 */

#include "board.h"
#include <genht/htpp.h>

typedef struct pcb_j2n_junc_s pcb_j2n_junc_t;
typedef struct pcb_j2n_jkey_s pcb_j2n_jkey_t;
typedef struct pcb_j2n_seg_s pcb_j2n_seg_t;

struct pcb_j2n_seg_s {
	gdl_elem_t jslink, jelink;  /* in start and end junction's ->segs list; also serves to get to the start and end junction pointer */

	/* the object the segment represents; NULL for implicit connections (e.g. via) */
	pcb_any_obj_t *obj;

	unsigned crawled:1;

	gdl_elem_t link_allsegs;
};

struct pcb_j2n_jkey_s {
	rnd_coord_t x, y;
	rnd_layergrp_id_t gid;   /* multi-level padstacks need to be added multiple times */
};

struct pcb_j2n_junc_s {
	pcb_j2n_jkey_t key;
	rnd_coord_t copdia;  /* maximum diameter (copper only) */
	rnd_coord_t clrdia;  /* maximum clearance diameter */

	pcb_any_obj_t *obj; /* a padstack or polygon or NULL; NULL is for trace-trace endpoint junctions */
	gdl_list_t ssegs;   /* segments starting here */
	gdl_list_t esegs;   /* segments ending here */

	pcb_j2n_junc_t *split_next; /* cyclic list if the same ->obj has multiple junctions, e.g. multiple layers of a via, multiple points of a poly */

	gdl_elem_t link_alljuncs;

	void *user_data;
};

/* hash instance */
typedef pcb_j2n_jkey_t htjunc_key_t;
typedef pcb_j2n_junc_t * htjunc_value_t;
#define HT(x) htjunc_ ## x
#include <genht/ht.h>
#undef HT



typedef struct pcb_j2netmap_s {
	/* configuration */
	unsigned find_rats:1;      /* set to 1 if rats shall be included */
	unsigned grbs_law:1;       /* emit grbs-compatible twonets of point-line-arc-line-arc...-line-point */

	void *user_data;           /* opaque, not touched by the lib */

	/* state */
	htjunc_t juncs;            /* find junction by level:x:y */

	/* internal */
	pcb_board_t *pcb;
	gdl_list_t all_segs;       /* list of all pcb_j2n_seg_t segments allocated (so they can be freed on uninit) */
	gdl_list_t all_juncs;      /* list of all pcb_j2n_junc_t junctions allocated (so they can be freed on uninit) */
	unsigned error:1;          /* encountered an error while mapping */
	htpp_t o2j;                /* object to junction, in case the object is a junction; points to one of the cyclic linked junctions  */
	htpp_t o2s;                /* object to segment, in case the object is a segment  */
	pcb_dynf_t mapped;         /* mark objects that are already in the map - tracked across multiple finds */
} pcb_j2netmap_t;


int pcb_map_j2nets_init(pcb_j2netmap_t *map, pcb_board_t *pcb);
int pcb_map_j2nets_uninit(pcb_j2netmap_t *map);


typedef struct pcb_j2nets_crawl_s {
	void (*twonet_begin)(pcb_j2netmap_t *map, pcb_j2n_junc_t *junc);
	void (*twonet_obj)(pcb_j2netmap_t *map, pcb_any_obj_t *obj, int reversed, pcb_j2n_junc_t *incident_junc); /* reversed==-1 for junction */
	void (*twonet_vjunct)(pcb_j2netmap_t *map, pcb_any_obj_t *obj, pcb_j2n_junc_t *junc); /* a virtual junction is when a two-net ends at a line or arc end (floating net or line-line split); obj is the current two-net object whose endpoint it is on */
	void (*twonet_end)(pcb_j2netmap_t *map, pcb_j2n_junc_t *junc);
} pcb_j2nets_crawl_t;

int pcb_map_j2nets_crawl(pcb_j2netmap_t *map, const pcb_j2nets_crawl_t *cr);

