import { ValidationError } from "../../core/index.js";
import {} from "../Component.js";
import { entityKey, sameEntity } from "../Entity.js";
export class HierarchyComponent {
    parent;
    previousSibling = null;
    nextSibling = null;
    depth = 0;
    childEntities = [];
    constructor(parent = null) {
        this.parent = parent;
    }
    get children() {
        return this.childEntities;
    }
    get childCount() {
        return this.childEntities.length;
    }
    get firstChild() {
        return this.childEntities[0] ?? null;
    }
    get lastChild() {
        return this.childEntities[this.childEntities.length - 1] ?? null;
    }
    hasParent() {
        return this.parent !== null;
    }
    hasChildren() {
        return this.childEntities.length > 0;
    }
    includesChild(entity) {
        return this.childEntities.some((child) => sameEntity(child, entity));
    }
    forEachChild(callback) {
        for (const child of this.childEntities)
            callback(child);
    }
    getSiblingIndex(entity) {
        if (!entity)
            return this.parent ? 0 : -1;
        return this.childEntities.findIndex((child) => sameEntity(child, entity));
    }
    _setParent(parent) {
        this.parent = parent;
    }
    _addChild(child) {
        if (!this.includesChild(child))
            this.childEntities.push(child);
    }
    _removeChild(child) {
        const index = this.childEntities.findIndex((entry) => sameEntity(entry, child));
        if (index < 0)
            return false;
        this.childEntities.splice(index, 1);
        return true;
    }
    _clearChildren() {
        this.childEntities.length = 0;
    }
    _moveChild(child, index) {
        const current = this.childEntities.findIndex((entry) => sameEntity(entry, child));
        if (current < 0)
            throw new ValidationError("ECS_HIERARCHY_CHILD", `Entity is not a child: ${entityKey(child)}`);
        const [entry] = this.childEntities.splice(current, 1);
        this.childEntities.splice(Math.max(0, Math.min(index, this.childEntities.length)), 0, entry);
    }
    toJSON() {
        return {
            parent: this.parent ? { ...this.parent } : null,
            children: this.childEntities.map((child) => ({ ...child })),
            previousSibling: this.previousSibling ? { ...this.previousSibling } : null,
            nextSibling: this.nextSibling ? { ...this.nextSibling } : null,
            depth: this.depth
        };
    }
    static schema = {
        version: 1,
        serialize(component) {
            return component.toJSON();
        },
        deserialize(data) {
            if (!isRecord(data) || !Array.isArray(data.children)) {
                throw new ValidationError("HIERARCHY_COMPONENT_DESERIALIZE", "HierarchyComponent data requires children array.");
            }
            const hierarchy = new HierarchyComponent(isEntity(data.parent) ? data.parent : null);
            for (const child of data.children) {
                if (isEntity(child))
                    hierarchy._addChild(child);
            }
            hierarchy.previousSibling = isEntity(data.previousSibling) ? data.previousSibling : null;
            hierarchy.nextSibling = isEntity(data.nextSibling) ? data.nextSibling : null;
            hierarchy.depth = typeof data.depth === "number" && Number.isFinite(data.depth) ? Math.max(0, Math.floor(data.depth)) : 0;
            return hierarchy;
        }
    };
}
function isRecord(value) {
    return typeof value === "object" && value !== null;
}
function isEntity(value) {
    return isRecord(value) && Number.isSafeInteger(value.id) && Number.isSafeInteger(value.generation);
}
//# sourceMappingURL=HierarchyComponent.js.map