"use strict";
// The save data manager has a feature where certain variables will automatically be rolled back
// when the Glowing Hourglass is used.
Object.defineProperty(exports, "__esModule", { value: true });
exports.restoreGlowingHourGlassBackup = exports.makeGlowingHourGlassBackup = void 0;
const SaveDataKey_1 = require("../../../../enums/SaveDataKey");
const SerializationType_1 = require("../../../../enums/SerializationType");
const deepCopy_1 = require("../../../../functions/deepCopy");
const merge_1 = require("../../../../functions/merge");
const table_1 = require("../../../../functions/table");
const constants_1 = require("./constants");
/**
 * When the Glowing Hourglass is used, certain save data keys will automatically be restored to a
 * backup.
 */
const GLOWING_HOUR_GLASS_BACKUP_KEYS = [
    SaveDataKey_1.SaveDataKey.RUN,
    SaveDataKey_1.SaveDataKey.LEVEL,
];
const IGNORE_GLOWING_HOUR_GLASS_KEY = "__ignoreGlowingHourGlass";
const REWIND_WITH_GLOWING_HOUR_GLASS_KEY = "__rewindWithGlowingHourGlass";
function makeGlowingHourGlassBackup(saveDataMap, saveDataConditionalFuncMap, saveDataGlowingHourGlassMap) {
    (0, table_1.iterateTableInOrder)(saveDataMap, (subscriberName, saveData) => {
        // We make the Glowing Hourglass backup using `SerializationType.SERIALIZE`, which means that
        // we cannot operate on unserializable data, such as functions. Save data that utilizes
        // unserializable data will typically be marked using a conditional function that evaluates to
        // false, so we skip all save data that matches this criteria.
        const conditionalFunc = saveDataConditionalFuncMap.get(subscriberName);
        if (conditionalFunc !== undefined) {
            const shouldSave = conditionalFunc();
            if (!shouldSave) {
                return;
            }
        }
        for (const saveDataKey of getKeysToBackup(saveData)) {
            const childTable = saveData[saveDataKey];
            if (childTable === undefined) {
                // This feature does not happen to store any variables on this particular child table.
                continue;
            }
            // Ignore child tables that the end-user has explicitly annotated.
            const childTableLuaMap = childTable;
            if (childTableLuaMap.has(IGNORE_GLOWING_HOUR_GLASS_KEY)) {
                continue;
            }
            let saveDataGlowingHourGlass = saveDataGlowingHourGlassMap.get(subscriberName);
            if (saveDataGlowingHourGlass === undefined) {
                saveDataGlowingHourGlass = new LuaMap();
                saveDataGlowingHourGlassMap.set(subscriberName, saveDataGlowingHourGlass);
            }
            // We serialize the table so that we can use the `merge` function later on with no other
            // modifications.
            const copiedChildTable = (0, deepCopy_1.deepCopy)(childTable, SerializationType_1.SerializationType.SERIALIZE);
            saveDataGlowingHourGlass[saveDataKey] = copiedChildTable;
        }
    }, constants_1.SAVE_DATA_MANAGER_DEBUG);
}
exports.makeGlowingHourGlassBackup = makeGlowingHourGlassBackup;
function restoreGlowingHourGlassBackup(saveDataMap, saveDataConditionalFuncMap, saveDataGlowingHourGlassMap, classConstructors) {
    (0, table_1.iterateTableInOrder)(saveDataMap, (subscriberName, saveData) => {
        // We make the Glowing Hourglass backup using `SerializationType.SERIALIZE`, which means that
        // we cannot operate on unserializable data, such as functions. Save data that utilizes
        // unserializable data will typically be marked using a conditional function that evaluates to
        // false, so we skip all save data that matches this criteria.
        const conditionalFunc = saveDataConditionalFuncMap.get(subscriberName);
        if (conditionalFunc !== undefined) {
            const shouldSave = conditionalFunc();
            if (!shouldSave) {
                return;
            }
        }
        for (const saveDataKey of getKeysToBackup(saveData)) {
            const childTable = saveData[saveDataKey];
            if (childTable === undefined) {
                // This feature does not happen to store any variables on this particular child table.
                continue;
            }
            // Ignore child tables that the end-user has explicitly annotated.
            const childTableLuaMap = childTable;
            if (childTableLuaMap.has(IGNORE_GLOWING_HOUR_GLASS_KEY)) {
                continue;
            }
            const saveDataGlowingHourGlass = saveDataGlowingHourGlassMap.get(subscriberName);
            if (saveDataGlowingHourGlass === undefined) {
                // This should never happen.
                continue;
            }
            const childTableBackup = saveDataGlowingHourGlass[saveDataKey];
            if (childTableBackup === undefined) {
                // This should never happen.
                continue;
            }
            (0, merge_1.merge)(childTable, childTableBackup, 
            // Append an arbitrary suffix for better error messages.
            `${subscriberName}__glowingHourGlass`, classConstructors);
        }
    }, constants_1.SAVE_DATA_MANAGER_DEBUG);
}
exports.restoreGlowingHourGlassBackup = restoreGlowingHourGlassBackup;
function getKeysToBackup(saveData) {
    const shouldBackupPersistentObject = saveData.persistent !== undefined &&
        saveData.persistent.has(REWIND_WITH_GLOWING_HOUR_GLASS_KEY);
    return shouldBackupPersistentObject
        ? [...GLOWING_HOUR_GLASS_BACKUP_KEYS, SaveDataKey_1.SaveDataKey.PERSISTENT]
        : GLOWING_HOUR_GLASS_BACKUP_KEYS;
}
