import { MARK_DEGENERATE } from "./constants/MARK_DEGENERATE.js";
import { QUAD_ONE_DEGEN_TRI } from "./constants/QUAD_ONE_DEGEN_TRI.js";
import { assert } from "../../../../core/assert.js";

/**
 *
 * @param {STriInfo[]} pTriInfos
 * @param {number[]|Int32Array} piTriList_out
 * @param {number} iNrTrianglesIn
 * @param {number} iTotTris
 * @returns {void}
 */
export function DegenPrologue(
    pTriInfos,
    piTriList_out,
    iNrTrianglesIn,
    iTotTris
) {
    // locate quads with only one good triangle
    let t = 0;

    while (t < (iTotTris - 1)) {

        const tri_0 = pTriInfos[t];
        const tri_1 = pTriInfos[t + 1];

        const iFO_a = tri_0.iOrgFaceNumber;
        const iFO_b = tri_1.iOrgFaceNumber;

        if (iFO_a === iFO_b) {

            // this is a quad
            const bIsDeg_a = (tri_0.iFlag & MARK_DEGENERATE) !== 0;
            const bIsDeg_b = (tri_1.iFlag & MARK_DEGENERATE) !== 0;

            if (bIsDeg_a !== bIsDeg_b) {
                tri_0.iFlag |= QUAD_ONE_DEGEN_TRI;
                tri_1.iFlag |= QUAD_ONE_DEGEN_TRI;
            }

            t += 2;

        } else {
            ++t;
        }
    }

    // reorder list so all degen triangles are moved to the back
    // without reordering the good triangles
    let iNextGoodTriangleSearchIndex = 1;
    let bStillFindingGoodOnes = true;

    t = 0;

    while (t < iNrTrianglesIn && bStillFindingGoodOnes) {

        const bIsGood = (pTriInfos[t].iFlag & MARK_DEGENERATE) === 0;

        if (bIsGood) {
            if (iNextGoodTriangleSearchIndex < (t + 2)) {
                iNextGoodTriangleSearchIndex = t + 2;
            }
        } else {
            // search for the first good triangle.
            let bJustADegenerate = true;

            while (bJustADegenerate && iNextGoodTriangleSearchIndex < iTotTris) {

                const bIsGood = (pTriInfos[iNextGoodTriangleSearchIndex].iFlag & MARK_DEGENERATE) === 0;

                if (bIsGood) {
                    bJustADegenerate = false;
                } else {
                    ++iNextGoodTriangleSearchIndex;
                }

            }

            const t0 = t;
            const t1 = iNextGoodTriangleSearchIndex;

            ++iNextGoodTriangleSearchIndex;
            assert.greaterThan(iNextGoodTriangleSearchIndex, (t + 1));

            // swap triangle t0 and t1
            if (!bJustADegenerate) {

                for (let i = 0; i < 3; i++) {
                    const i0 = t0 * 3 + i;
                    const i1 = t1 * 3 + i;

                    const index = piTriList_out[i0];

                    piTriList_out[i0] = piTriList_out[i1];
                    piTriList_out[i1] = index;
                }

                const tri_info = pTriInfos[t0];
                pTriInfos[t0] = pTriInfos[t1];
                pTriInfos[t1] = tri_info;

            } else {
                // this is not supposed to happen
                bStillFindingGoodOnes = false;
            }
        }

        if (bStillFindingGoodOnes) {
            ++t;
        }
    }

    assert(bStillFindingGoodOnes);	// code will still work.
    assert.equal(iNrTrianglesIn, t);
}
