import { GROUP_WITH_ANY } from "./constants/GROUP_WITH_ANY.js";
import { assert } from "../../../../core/assert.js";
import { ORIENT_PRESERVING } from "./constants/ORIENT_PRESERVING.js";
import { AddTriToGroup } from "./AddTriToGroup.js";
import { AssignRecur } from "./AssignRecur.js";

/**
 *
 * @param {STriInfo[]} pTriInfos
 * @param {SGroup[]} pGroups
 * @param {number[]|Int32Array} piGroupTrianglesBuffer
 * @param {number[]|Int32Array} piTriListIn
 * @param {number} iNrTrianglesIn
 * @return {number}
 */
export function Build4RuleGroups(
    pTriInfos,
    pGroups,
    piGroupTrianglesBuffer,
    piTriListIn,
    iNrTrianglesIn
) {

    const iNrMaxGroups = iNrTrianglesIn * 3;
    let iNrActiveGroups = 0;
    let iOffset = 0;

    for (let f=0; f < iNrTrianglesIn; f++) {
        const tri_info_f = pTriInfos[f];

        for (let i = 0; i < 3; i++) {

            // if not assigned to a group
            if ((tri_info_f.iFlag & GROUP_WITH_ANY) === 0 && tri_info_f.AssignedGroup[i] === null) {

                const vert_index = piTriListIn[f * 3 + i];

                assert.lessThan(iNrActiveGroups, iNrMaxGroups);

                const assigned_group = pGroups[iNrActiveGroups];
                tri_info_f.AssignedGroup[i] = assigned_group;

                assigned_group.iVertexRepresentitive = vert_index;

                const bOrPre = (tri_info_f.iFlag & ORIENT_PRESERVING) !== 0;

                assigned_group.bOrientPreservering = bOrPre;
                assigned_group.iNrFaces = 0;
                assigned_group.pFaceIndices = new Int32Array(piGroupTrianglesBuffer.buffer, iOffset * 4);
                ++iNrActiveGroups;

                AddTriToGroup(assigned_group, f);

                const neigh_indexL = tri_info_f.FaceNeighbors[i];
                const neigh_indexR = tri_info_f.FaceNeighbors[i > 0 ? (i - 1) : 2];

                if (neigh_indexL >= 0) {

                    // neighbor
                    const bAnswer = AssignRecur(
                        piTriListIn,
                        pTriInfos,
                        neigh_indexL,
                        assigned_group
                    );

                    assert(bAnswer || (bOrPre !== ((pTriInfos[neigh_indexL].iFlag & ORIENT_PRESERVING) !== 0)) );

                }
                if (neigh_indexR >= 0) {

                    // neighbor
                    const bAnswer = AssignRecur(
                        piTriListIn,
                        pTriInfos,
                        neigh_indexR,
                        assigned_group
                    );

                    assert(bAnswer || bOrPre !== ((pTriInfos[neigh_indexR].iFlag & ORIENT_PRESERVING) !== 0));

                }

                // update offset
                iOffset += assigned_group.iNrFaces;

                // since the groups are disjoint a triangle can never
                // belong to more than 3 groups. Subsequently, something
                // is completely screwed if this assertion ever hits.
                assert.lessThanOrEqual(iOffset, iNrMaxGroups);
            }
        }
    }

    return iNrActiveGroups;
}
