import { aabb2_distance_sqr_to_point } from "../aabb/aabb2_distance_sqr_to_point.js";

/**
 *
 * @type {QuadTreeNode[]}
 */
const node_stack = [];

/**
 * @template T
 * @param {QuadTreeDatum<T>[]} result
 * @param {number} result_offset
 * @param {QuadTreeNode<T>} tree
 * @param {number} x
 * @param {number} y
 * @param {number} radius
 * @param {function(data:T):boolean} [predicate]
 * @param {*} [predicateContext]
 * @returns {number}
 */
export function qt_match_data_by_circle(
    result, result_offset,
    tree,
    x, y, radius,
    predicate, predicateContext
) {
    let result_cursor = result_offset;

    let stack_pointer = 0;

    const r2 = radius * radius;

    node_stack[stack_pointer] = tree;
    stack_pointer++;

    while (stack_pointer > 0) {

        --stack_pointer;
        const node = node_stack[stack_pointer];

        const d2 = aabb2_distance_sqr_to_point(node.x0, node.y0, node.x1, node.y1, x, y);

        if (d2 > r2) {
            // not a match
            continue;
        }

        const data = node.data;
        const data_count = data.length;

        for (let i = 0; i < data_count; i++) {
            const datum = data[i];

            const d2_to_datum = aabb2_distance_sqr_to_point(datum.x0, datum.y0, datum.x1, datum.y1, x, y);

            if (d2_to_datum <= r2 && predicate.call(predicateContext, datum.data)) {
                result[result_cursor++] = datum;
            }
        }

        if (node.isSplit()) {
            node_stack[stack_pointer++] = node.topLeft;
            node_stack[stack_pointer++] = node.bottomLeft;
            node_stack[stack_pointer++] = node.topRight;
            node_stack[stack_pointer++] = node.bottomRight;
        }
    }

    return result_cursor - result_offset;
}
