"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.GridEntityUpdateDetection = void 0;
const isaac_typescript_definitions_1 = require("isaac-typescript-definitions");
const ISCFeature_1 = require("../../../enums/ISCFeature");
const ModCallbackCustom_1 = require("../../../enums/ModCallbackCustom");
const gridEntities_1 = require("../../../functions/gridEntities");
const Feature_1 = require("../../private/Feature");
const v = {
    room: {
        /** Indexed by grid index. */
        initializedGridEntities: new Map(),
    },
};
class GridEntityUpdateDetection extends Feature_1.Feature {
    v = v;
    postGridEntityInit;
    postGridEntityCustomInit;
    postGridEntityUpdate;
    postGridEntityCustomUpdate;
    postGridEntityRemove;
    postGridEntityCustomRemove;
    postGridEntityStateChanged;
    postGridEntityCustomStateChanged;
    postGridEntityBroken;
    postGridEntityCustomBroken;
    customGridEntities;
    constructor(postGridEntityInit, postGridEntityCustomInit, postGridEntityUpdate, postGridEntityCustomUpdate, postGridEntityRemove, postGridEntityCustomRemove, postGridEntityStateChanged, postGridEntityCustomStateChanged, postGridEntityBroken, postGridEntityCustomBroken, customGridEntities) {
        super();
        this.featuresUsed = [ISCFeature_1.ISCFeature.RUN_IN_N_FRAMES];
        this.callbacksUsed = [
            // 1
            [isaac_typescript_definitions_1.ModCallback.POST_UPDATE, this.postUpdate],
        ];
        this.customCallbacksUsed = [
            [ModCallbackCustom_1.ModCallbackCustom.POST_NEW_ROOM_REORDERED, this.postNewRoomReordered],
        ];
        this.postGridEntityInit = postGridEntityInit;
        this.postGridEntityCustomInit = postGridEntityCustomInit;
        this.postGridEntityUpdate = postGridEntityUpdate;
        this.postGridEntityCustomUpdate = postGridEntityCustomUpdate;
        this.postGridEntityRemove = postGridEntityRemove;
        this.postGridEntityCustomRemove = postGridEntityCustomRemove;
        this.postGridEntityStateChanged = postGridEntityStateChanged;
        this.postGridEntityCustomStateChanged = postGridEntityCustomStateChanged;
        this.postGridEntityBroken = postGridEntityBroken;
        this.postGridEntityCustomBroken = postGridEntityCustomBroken;
        this.customGridEntities = customGridEntities;
    }
    // ModCallback.POST_UPDATE (1)
    postUpdate = () => {
        const gridEntitiesMap = (0, gridEntities_1.getGridEntitiesMap)();
        // We check for removed grid entities first so that grid entities that change type will count as
        // being removed and fire the PostGridEntityRemoved callback.
        this.checkGridEntitiesRemoved(gridEntitiesMap);
        for (const [gridIndex, gridEntity] of gridEntitiesMap) {
            this.checkGridEntityStateChanged(gridIndex, gridEntity);
            this.checkNewGridEntity(gridIndex, gridEntity);
            const gridEntityTypeCustom = this.customGridEntities.getCustomGridEntityType(gridIndex);
            if (gridEntityTypeCustom === undefined) {
                this.postGridEntityUpdate.fire(gridEntity);
            }
            else {
                this.postGridEntityCustomUpdate.fire(gridEntity, gridEntityTypeCustom);
            }
        }
    };
    checkGridEntitiesRemoved(gridEntitiesMap) {
        for (const [gridIndex, gridEntityTuple] of v.room.initializedGridEntities) {
            const [storedGridEntityType, storedGridEntityVariant] = gridEntityTuple;
            const gridEntity = gridEntitiesMap.get(gridIndex);
            if (gridEntity === undefined ||
                gridEntity.GetType() !== storedGridEntityType) {
                v.room.initializedGridEntities.delete(gridIndex);
                const gridEntityTypeCustom = this.customGridEntities.getCustomGridEntityType(gridIndex);
                if (gridEntityTypeCustom === undefined) {
                    this.postGridEntityRemove.fire(gridIndex, storedGridEntityType, storedGridEntityVariant);
                }
                else {
                    this.postGridEntityCustomRemove.fire(gridIndex, gridEntityTypeCustom);
                }
            }
        }
    }
    checkGridEntityStateChanged(gridIndex, gridEntity) {
        const gridEntityTuple = v.room.initializedGridEntities.get(gridIndex);
        if (gridEntityTuple === undefined) {
            // This grid entity did not exist a frame ago; we don't want to fire the state changed
            // callback on the first frame that it exists.
            return;
        }
        const [_gridEntityType, _gridEntityVariant, oldState] = gridEntityTuple;
        const newState = gridEntity.State;
        if (oldState !== newState) {
            this.updateTupleInMap(gridEntity);
            const gridEntityTypeCustom = this.customGridEntities.getCustomGridEntityType(gridEntity);
            if (gridEntityTypeCustom === undefined) {
                this.postGridEntityStateChanged.fire(gridEntity, oldState, newState);
            }
            else {
                this.postGridEntityCustomStateChanged.fire(gridEntity, gridEntityTypeCustom, oldState, newState);
            }
            if ((0, gridEntities_1.isGridEntityBroken)(gridEntity)) {
                if (gridEntityTypeCustom === undefined) {
                    this.postGridEntityBroken.fire(gridEntity);
                }
                else {
                    this.postGridEntityCustomBroken.fire(gridEntity, gridEntityTypeCustom);
                }
            }
        }
    }
    checkNewGridEntity(gridIndex, gridEntity) {
        const gridEntityType = gridEntity.GetType();
        const gridEntityTuple = v.room.initializedGridEntities.get(gridIndex);
        if (gridEntityTuple === undefined ||
            gridEntityTuple[0] !== gridEntityType) {
            this.updateTupleInMap(gridEntity);
            const gridEntityTypeCustom = this.customGridEntities.getCustomGridEntityType(gridEntity);
            if (gridEntityTypeCustom === undefined) {
                this.postGridEntityInit.fire(gridEntity);
            }
            else {
                this.postGridEntityCustomInit.fire(gridEntity, gridEntityTypeCustom);
            }
        }
    }
    updateTupleInMap(gridEntity) {
        const gridEntityType = gridEntity.GetType();
        const variant = gridEntity.GetVariant();
        const gridIndex = gridEntity.GetGridIndex();
        const newTuple = [
            gridEntityType,
            variant,
            gridEntity.State,
        ];
        v.room.initializedGridEntities.set(gridIndex, newTuple);
    }
    // ModCallbackCustom.POST_NEW_ROOM_REORDERED
    postNewRoomReordered = () => {
        const gridEntitiesMap = (0, gridEntities_1.getGridEntitiesMap)();
        for (const [gridIndex, gridEntity] of gridEntitiesMap) {
            this.checkNewGridEntity(gridIndex, gridEntity);
        }
    };
}
exports.GridEntityUpdateDetection = GridEntityUpdateDetection;
