import { Entity } from './Entity';
import { removeItemFromArray } from '../Util/Util';
// Add/Remove entities and components
export class EntityManager {
    constructor(_world) {
        this._world = _world;
        this.entities = [];
        this._entityIndex = {};
        this._entitiesToRemove = [];
    }
    /**
     * Runs the entity lifecycle
     * @param scene
     * @param elapsed
     */
    updateEntities(scene, elapsed) {
        for (const entity of this.entities) {
            entity.update(scene.engine, elapsed);
            if (!entity.active) {
                this.removeEntity(entity);
            }
        }
    }
    findEntitiesForRemoval() {
        for (const entity of this.entities) {
            if (!entity.active) {
                this.removeEntity(entity);
            }
        }
    }
    /**
     * Adds an entity to be tracked by the EntityManager
     * @param entity
     */
    addEntity(entity) {
        entity.active = true;
        entity.scene = this._world.scene;
        if (entity && !this._entityIndex[entity.id]) {
            this._entityIndex[entity.id] = entity;
            this.entities.push(entity);
            this._world.queryManager.addEntity(entity);
            // if entity has children
            entity.children.forEach((c) => {
                c.scene = entity.scene;
                this.addEntity(c);
            });
            entity.childrenAdded$.register({
                notify: (e) => {
                    this.addEntity(e);
                }
            });
            entity.childrenRemoved$.register({
                notify: (e) => {
                    this.removeEntity(e, false);
                }
            });
        }
    }
    removeEntity(idOrEntity, deferred = true) {
        var _a, _b;
        let id = 0;
        if (idOrEntity instanceof Entity) {
            id = idOrEntity.id;
        }
        else {
            id = idOrEntity;
        }
        const entity = this._entityIndex[id];
        if (entity && entity.active) {
            entity.active = false;
        }
        if (entity && deferred) {
            this._entitiesToRemove.push(entity);
            return;
        }
        delete this._entityIndex[id];
        if (entity) {
            entity.scene = null;
            removeItemFromArray(entity, this.entities);
            this._world.queryManager.removeEntity(entity);
            // if entity has children
            entity.children.forEach((c) => {
                c.scene = null;
                this.removeEntity(c, deferred);
            });
            entity.childrenAdded$.clear();
            entity.childrenRemoved$.clear();
            // stats
            if ((_b = (_a = this._world) === null || _a === void 0 ? void 0 : _a.scene) === null || _b === void 0 ? void 0 : _b.engine) {
                this._world.scene.engine.stats.currFrame.actors.killed++;
            }
        }
    }
    processEntityRemovals() {
        for (const entity of this._entitiesToRemove) {
            if (entity.active) {
                continue;
            }
            this.removeEntity(entity, false);
        }
        this._entitiesToRemove.length = 0;
    }
    processComponentRemovals() {
        for (const entity of this.entities) {
            entity.processComponentRemoval();
        }
    }
    getById(id) {
        return this._entityIndex[id];
    }
    getByName(name) {
        return this.entities.filter((e) => e.name === name);
    }
    clear() {
        for (let i = this.entities.length - 1; i >= 0; i--) {
            this.removeEntity(this.entities[i]);
        }
    }
}
//# sourceMappingURL=EntityManager.js.map