import { array_copy } from "../../../collection/array/array_copy.js";
import { array_set_diff_sorting } from "../../../collection/array/array_set_diff_sorting.js";
import { compareFaces } from "./compareFaces.js";
import { computeTopoMeshVertexDuplicates } from "./computeTopoMeshVertexDuplicates.js";
import { query_edge_other_vertex } from "./query/query_edge_other_vertex.js";

/**
 *
 * @param {TopoEdge[]} result
 * @param {TopoVertex[]} source_a
 * @param {TopoVertex[]} source_b
 * @returns {number} number of elements placed into the result array
 */
function findCommonDuplicateEdges(result, source_a, source_b) {
    let i, j;
    let result_count = 0;

    const na = source_a.length;

    for (i = 0; i < na; i++) {
        const v_a = source_a[i];

        const edges_a = v_a.edges;

        const edge_count_a = edges_a.length;
        for (j = 0; j < edge_count_a; j++) {
            const topoEdge = edges_a[j];

            const other_vertex_a = query_edge_other_vertex(topoEdge, v_a);

            if (source_b.includes(other_vertex_a)) {
                const existing_result_place = result.indexOf(topoEdge);

                if (existing_result_place > result_count || existing_result_place === -1) {
                    // not included in result set yet
                    result[result_count] = topoEdge;
                    result_count++;
                }

            }
        }
    }

    return result_count;
}

/**
 *
 * @param {TopoEdge} a
 * @param {TopoEdge} b
 */
function connectEdges(a, b) {
    const faces_a = a.faces;
    const faces_b = b.faces;

    const diff = array_set_diff_sorting(faces_a, faces_b, compareFaces);

    const unique_a = diff.uniqueA;
    const unique_b = diff.uniqueB;

    array_copy(unique_a, 0, faces_b, faces_b.length, unique_a.length);
    array_copy(unique_b, 0, faces_a, faces_a.length, unique_b.length);
}

/**
 * Connect together vertices that are spatially on top of one another
 * @param {TopoMesh} mesh
 * @param {AABB3} aabb
 */
export function expandConnectivityByLocality(mesh, aabb) {
    const duplicate_edges = [];

    const vertex_duplicates = computeTopoMeshVertexDuplicates(mesh, aabb);

    // find duplicate edges from vertices
    const edges = mesh.getEdges();

    let j;

    for (let edge of edges) {

        const duplicate_v0s = vertex_duplicates.get(edge.v0);

        if (duplicate_v0s === undefined) {
            // no duplicate vertices, edge is unique
            continue;
        }

        const duplicate_v1s = vertex_duplicates.get(edge.v1);

        if (duplicate_v1s === undefined) {
            // no duplicate vertices, edge is unique
            continue;
        }

        const n = findCommonDuplicateEdges(duplicate_edges, duplicate_v0s, duplicate_v1s);

        for (j = 0; j < n; j++) {
            const duplicate_edge = duplicate_edges[j];
            connectEdges(edge, duplicate_edge);
        }
    }

}
