import { assert } from "../../../assert.js";
import AABB2 from "../../2d/aabb/AABB2.js";

/**
 * @template D
 * @extends {AABB2}
 */
export class QuadTreeDatum extends AABB2 {

    /**
     *
     * @type {D|null}
     */
    data = null;

    /**
     *
     * @type {QuadTreeNode|null}
     */
    parentNode = null;

    disconnect() {
        const parentNode = this.parentNode;

        if (parentNode === null) {
            //not connected
            return;
        }

        const parentData = parentNode.data;

        const i = parentData.indexOf(this);

        assert.notEqual(i, -1, 'Datum is not present in parentNode.data');

        parentData.splice(i, 1);

        let node = parentNode;

        while (node !== null) {
            node.treeDataCount--;

            node = node.parentNode;
        }

        this.parentNode.balanceBubbleUp();

        this.parentNode = null;
    }

    /**
     *
     * @param {number} x0
     * @param {number} y0
     * @param {number} x1
     * @param {number} y1
     */
    resize(x0, y0, x1, y1) {
        this.x0 = x0;
        this.y0 = y0;
        this.x1 = x1;
        this.y1 = y1;

        const parentNode = this.parentNode;

        if (parentNode === null) {
            //orphaned datum
            return;
        }


        let node = parentNode;

        if (
            this.x0 < node.x0
            || this.x1 >= node.x1
            || this.y0 < node.y0
            || this.y1 >= node.y1
        ) {
            //new size violates bounds of the containing node

            this.disconnect();

            node.insertDatum(this);
        }
    }

    /**
     *
     * @param {number} dX
     * @param {number} dY
     */
    move(dX, dY) {
        const x0 = this.x0 + dX;
        const y0 = this.y0 + dY;

        const x1 = this.x1 + dX;
        const y1 = this.y1 + dY;

        this.resize(x0, y0, x1, y1);
    }
}

QuadTreeDatum.prototype.isQuadTreeDatum = true;
