import { BitSet } from "../../../../../../binary/BitSet.js";
import { bt_face_get_neighbour_faces } from "./bt_face_get_neighbour_faces.js";

/**
 * Find groups of connected faces in the mesh. Faces are considered connected if they share an edge.
 * If the entire mesh is connected - there will be a single island.
 *
 * @param {BinaryTopology} mesh
 * @returns {number[][]} each island is a sequence of face IDs
 */
export function bt_mesh_compute_face_islands(mesh) {
    /**
     *
     * @type {number[][]}
     */
    const result = [];

    // traverse over all faced in the mesh, flood-filling to build islands
    const closed_set = new BitSet();

    const faces = mesh.faces;

    /**
     * @type {number}
     */
    const face_count = faces.size;

    /**
     *
     * @type {number[]}
     */
    const scratch_neighbours = [];

    for (let seed_face_id = 0; seed_face_id < face_count; seed_face_id++) {
        if (closed_set.getAndSet(seed_face_id)) {
            // already processed
            continue;
        }

        if (!faces.is_allocated(seed_face_id)) {
            // a hole
            continue;
        }

        // start a new island

        /**
         *
         * @type {number[]}
         */
        const island = [];

        result.push(island);

        const open = [seed_face_id];

        while (open.length > 0) {
            const face_id = open.pop();

            island.push(face_id);

            const neighbour_count = bt_face_get_neighbour_faces(scratch_neighbours, 0, mesh, face_id);

            for (let i = 0; i < neighbour_count; i++) {
                const neighbour_id = scratch_neighbours[i];

                if (closed_set.getAndSet(neighbour_id)) {
                    continue;
                }

                open.push(neighbour_id);
            }
        }

    }

    return result;
}