import { bt_face_get_attached_faces } from "../query/bt_face_get_attached_faces.js";
import { bt_mesh_face_decouple } from "./bt_mesh_face_decouple.js";

/**
 * Breaks up any shared edges and vertices between faces across given islands.
 * As a result each island shares no vertices or edges with other islands.
 *
 * Note: Islands do not have to be connected, but must be disjoint.
 * Note: Islands do not have to include all faces of the mesh.
 *
 * @param {BinaryTopology} mesh
 * @param {number[][]} islands 2D array of face IDs
 */
export function bt_mesh_face_decouple_islands(mesh, islands) {

    if (islands.length <= 1) {
        // no need to decouple
        return;
    }

    /**
     *
     * @type {number[]}
     */
    const all_island_faces = [];
    /**
     *
     * @type {Map<number, number>}
     */
    const face_to_islands = new Map();

    // build face -> island map
    for (let island_id = 0; island_id < islands.length; island_id++) {
        const island = islands[island_id];

        const island_size = island.length;

        for (let j = 0; j < island_size; j++) {
            const face = island[j];

            face_to_islands.set(face, island_id);
            all_island_faces.push(face);

        }
    }

    // crawl faces
    const relevant_face_count = all_island_faces.length;

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

    /**
     *
     * @type {Map<number, Set<number>>}
     */
    const processed_pairs = new Map();

    /**
     *
     * @param {number} face
     * @returns {Set<number>}
     */
    function get_processed_pair(face) {
        const existing = processed_pairs.get(face);

        if (existing !== undefined) {
            return existing;
        }

        const v = new Set();

        processed_pairs.set(face, v);

        return v;
    }

    for (let i = 0; i < relevant_face_count; i++) {
        const face = all_island_faces[i];

        const island_id = face_to_islands.get(face);

        const attached_count = bt_face_get_attached_faces(other_faces, 0, mesh, face);

        for (let j = 0; j < attached_count; j++) {
            const attached_face = other_faces[j];

            const neighbour_island_id = face_to_islands.get(attached_face);

            if (neighbour_island_id === island_id || neighbour_island_id === undefined) {
                continue;
            }

            const this_pairs = get_processed_pair(face);

            if (this_pairs.has(attached_face)) {
                // already processed
                continue;
            }

            bt_mesh_face_decouple(mesh, face, attached_face);

            // record processed pair
            this_pairs.add(attached_face);
            get_processed_pair(attached_face).add(face);
        }
    }
}