local ____lualib = require("lualib_bundle")
local __TS__Class = ____lualib.__TS__Class
local Map = ____lualib.Map
local __TS__New = ____lualib.__TS__New
local ____exports = {}
local initDecoratedCallbacks, addCallback, removeCallback, initSaveDataManager, WRAPPED_CALLBACK_METHODS_KEY, WRAPPED_CUSTOM_CALLBACK_METHODS_KEY
local ____array = require("functions.array")
local isArray = ____array.isArray
local ____tstlClass = require("functions.tstlClass")
local getTSTLClassConstructor = ____tstlClass.getTSTLClassConstructor
local getTSTLClassName = ____tstlClass.getTSTLClassName
local ____types = require("functions.types")
local isFunction = ____types.isFunction
local isInteger = ____types.isInteger
local isTable = ____types.isTable
local ____utils = require("functions.utils")
local assertDefined = ____utils.assertDefined
function initDecoratedCallbacks(self, modFeature, constructor, tstlClassName, vanilla, init)
    local modFeatureConstructor = constructor
    local callbackTuplesKey = vanilla and ____exports.MOD_FEATURE_CALLBACKS_KEY or ____exports.MOD_FEATURE_CUSTOM_CALLBACKS_KEY
    local callbackTuples = modFeatureConstructor[callbackTuplesKey]
    if callbackTuples == nil then
        return
    end
    if not isArray(nil, callbackTuples) then
        error((("Failed to initialize/uninitialize the decorated callbacks on a mod feature since the callback arguments on the key of \"" .. callbackTuplesKey) .. "\" was not an array and was instead of type: ") .. type(callbackTuples))
    end
    for ____, callbackTuple in ipairs(callbackTuples) do
        if not isArray(nil, callbackTuple) then
            error((("Failed to initialize/uninitialize the decorated callbacks on a mod feature since one of the callback arguments on the key of \"" .. callbackTuplesKey) .. "\" was not an array and was instead of type: ") .. type(callbackTuple))
        end
        local modCallback = callbackTuple[1]
        if not isInteger(nil, modCallback) then
            error("Failed to get the callback number from the callback tuple for class: " .. tstlClassName)
        end
        local priority = callbackTuple[2]
        if not isInteger(nil, priority) then
            error("Failed to get the callback priority from the callback tuple for class: " .. tstlClassName)
        end
        local callback = callbackTuple[3]
        if not isFunction(nil, callback) then
            error("Failed to get the callback function from the callback tuple for class: " .. tstlClassName)
        end
        local parameters = callbackTuple[4]
        if not isArray(nil, parameters, false) then
            error("Failed to get the callback parameters from the callback tuple for class: " .. tstlClassName)
        end
        local mod = modFeature.mod
        if init then
            addCallback(
                nil,
                modFeature,
                modFeatureConstructor,
                mod,
                modCallback,
                priority,
                callback,
                parameters,
                vanilla
            )
        else
            removeCallback(
                nil,
                modFeatureConstructor,
                mod,
                modCallback,
                vanilla
            )
        end
    end
end
function addCallback(self, modFeature, modFeatureConstructor, mod, modCallback, priority, callback, parameters, vanilla)
    local function wrappedCallback(____, ...)
        local conditionalFunc = modFeature.shouldCallbackMethodsFire
        if conditionalFunc ~= nil then
            local shouldRun = conditionalFunc(nil, vanilla, modCallback, ...)
            if not shouldRun then
                return nil
            end
        end
        local castedCallback = callback
        return castedCallback(modFeature, ...)
    end
    if vanilla then
        local modCallbackVanilla = modCallback
        local wrappedMethodsMap = modFeatureConstructor[WRAPPED_CALLBACK_METHODS_KEY]
        if wrappedMethodsMap == nil then
            wrappedMethodsMap = __TS__New(Map)
            modFeatureConstructor[WRAPPED_CALLBACK_METHODS_KEY] = wrappedMethodsMap
        end
        wrappedMethodsMap:set(modCallbackVanilla, wrappedCallback)
    else
        local modCallbackCustom = modCallback
        local wrappedMethodsMap = modFeatureConstructor[WRAPPED_CUSTOM_CALLBACK_METHODS_KEY]
        if wrappedMethodsMap == nil then
            wrappedMethodsMap = __TS__New(Map)
            modFeatureConstructor[WRAPPED_CUSTOM_CALLBACK_METHODS_KEY] = wrappedMethodsMap
        end
        wrappedMethodsMap:set(modCallbackCustom, wrappedCallback)
    end
    if vanilla then
        mod:AddPriorityCallback(
            modCallback,
            priority,
            wrappedCallback,
            table.unpack(parameters)
        )
    else
        mod:AddPriorityCallbackCustom(
            modCallback,
            priority,
            wrappedCallback,
            table.unpack(parameters)
        )
    end
end
function removeCallback(self, modFeatureConstructor, mod, modCallback, vanilla)
    if vanilla then
        local modCallbackVanilla = modCallback
        local wrappedMethodsMap = modFeatureConstructor[WRAPPED_CALLBACK_METHODS_KEY]
        if wrappedMethodsMap == nil then
            return
        end
        local wrappedCallback = wrappedMethodsMap:get(modCallbackVanilla)
        mod:RemoveCallback(modCallback, wrappedCallback)
    else
        local modCallbackCustom = modCallback
        local wrappedMethodsMap = modFeatureConstructor[WRAPPED_CUSTOM_CALLBACK_METHODS_KEY]
        if wrappedMethodsMap == nil then
            return
        end
        local wrappedCallback = wrappedMethodsMap:get(modCallbackCustom)
        mod:RemoveCallbackCustom(modCallback, wrappedCallback)
    end
end
function initSaveDataManager(self, modFeature, tstlClassName, init)
    local ____modFeature_0 = modFeature
    local v = ____modFeature_0.v
    if v == nil then
        return
    end
    if not isTable(nil, v) then
        error("Failed to initialize a mod feature class due to having a \"v\" property that is not an object. (The \"v\" property is supposed to be an object that holds the variables for the class, managed by the save data manager.)")
    end
    local mod = modFeature.mod
    local saveDataManagerMethodName = init and "saveDataManager" or "saveDataManagerRemove"
    local saveDataManagerMethod = mod[saveDataManagerMethodName]
    assertDefined(nil, saveDataManagerMethod, "Failed to initialize a mod feature class due to having a \"v\" object and not having the save data manager initialized. You must pass \"ISCFeature.SAVE_DATA_MANAGER\" to the \"upgradeMod\" function.")
    if type(saveDataManagerMethod) ~= "function" then
        error(("The \"" .. saveDataManagerMethodName) .. "\" property of the \"ModUpgraded\" object was not a function.")
    end
    if init then
        saveDataManagerMethod(nil, tstlClassName, v)
    else
        saveDataManagerMethod(nil, tstlClassName)
    end
end
____exports.MOD_FEATURE_CALLBACKS_KEY = "__callbacks"
____exports.MOD_FEATURE_CUSTOM_CALLBACKS_KEY = "__customCallbacks"
WRAPPED_CALLBACK_METHODS_KEY = "__wrappedCallbackMethods"
WRAPPED_CUSTOM_CALLBACK_METHODS_KEY = "__wrappedCustomCallbacksMethods"
--- Helper class for mods that want to represent their individual features as classes. Extend your
-- mod features from this class in order to enable the `@Callback` and `@CustomCallback` decorators
-- that automatically subscribe to callbacks.
-- 
-- It is recommended that you use the `initModFeatures` helper function to instantiate all of your
-- mod classes (instead of instantiating them yourself). This is so that any attached `v` objects
-- are properly registered with the save data manager; see below.
-- 
-- If you are manually instantiating a mod feature yourself, then:
-- 
-- - You must pass your upgraded mod as the first argument to the constructor.
-- - In almost all cases, you will want the callback functions to be immediately subscribed after
--   instantiating the class. However, if this is not the case, you can pass `false` as the optional
--   second argument to the constructor.
-- 
-- If your mod feature has a property called `v`, it will be assumed that these are variables that
-- should be managed by the save data manager. Unfortunately, due to technical limitations with
-- classes, this registration will only occur if you initialize the class with the `initModFeatures`
-- helper function. (This is because the parent class does not have access to the child's properties
-- upon first construction.)
____exports.ModFeature = __TS__Class()
local ModFeature = ____exports.ModFeature
ModFeature.name = "ModFeature"
function ModFeature.prototype.____constructor(self, mod, init)
    if init == nil then
        init = true
    end
    self.shouldCallbackMethodsFire = nil
    self.initialized = false
    self.mod = mod
    if init then
        self:init()
    end
end
function ModFeature.prototype.init(self, init)
    if init == nil then
        init = true
    end
    if self.initialized == init then
        return
    end
    self.initialized = init
    local constructor = getTSTLClassConstructor(nil, self)
    assertDefined(nil, constructor, "Failed to get the TSTL class constructor for a mod feature.")
    local tstlClassName = getTSTLClassName(nil, self)
    assertDefined(nil, tstlClassName, "Failed to get the TSTL class name for a mod feature.")
    initDecoratedCallbacks(
        nil,
        self,
        constructor,
        tstlClassName,
        true,
        init
    )
    initDecoratedCallbacks(
        nil,
        self,
        constructor,
        tstlClassName,
        false,
        init
    )
    initSaveDataManager(nil, self, tstlClassName, init)
end
function ModFeature.prototype.uninit(self)
    self:init(false)
end
return ____exports
