import { SCRATCH_UINT32_TRAVERSAL_STACK } from "../../../collection/SCRATCH_UINT32_TRAVERSAL_STACK.js";
import { aabb2_intersects_circle } from "../aabb/aabb2_intersects_circle.js";
import { COLUMN_CHILD_1, COLUMN_CHILD_2, COLUMN_USER_DATA, ELEMENT_WORD_COUNT, NULL_NODE } from "./BVH2D.js";

const stack = SCRATCH_UINT32_TRAVERSAL_STACK;

/**
 *
 * @param {BVH2D} bvh
 * @param {number} root
 * @param {number[]|Uint32Array} result
 * @param {number} result_offset
 * @param {number} center_x
 * @param {number} center_y
 * @param {number} radius
 * @return {number}
 */
export function bvh2d_query_all_data_by_circle(
    bvh, root,
    result, result_offset,
    center_x, center_y, radius
) {

    if (root === NULL_NODE) {
        return 0;
    }

    /**
     *
     * @type {number}
     */
    const stack_top = stack.pointer++;

    stack[stack_top] = root;

    let result_cursor = result_offset;

    /*
     For performance, we bind data directly to avoid extra copies required to read out AABB
     */
    const float32 = bvh.__data_float32;
    const uint32 = bvh.__data_uint32;

    do {
        stack.pointer--;

        /**
         *
         * @type {number}
         */
        const node = stack[stack.pointer];

        const address = node * ELEMENT_WORD_COUNT;

        // test node against the ray
        const intersects = aabb2_intersects_circle(
            float32[address], float32[address + 1],
            float32[address + 2], float32[address + 3],
            center_x, center_y, radius
        );

        if (!intersects) {
            continue;
        }

        // get fist child to check if this is a leaf node or not
        const child_1 = uint32[address + COLUMN_CHILD_1];

        if (child_1 !== NULL_NODE) {

            // this is not a leaf node, push children onto traversal stack
            stack[stack.pointer++] = child_1;
            stack[stack.pointer++] = uint32[address + COLUMN_CHILD_2];

        } else {
            // leaf node

            result[result_cursor++] = uint32[address + COLUMN_USER_DATA];
        }
    } while (stack.pointer > stack_top);

    return result_cursor - result_offset;
}