-- Copyright ©2024-2025 by Todd Hundersmarck (ThundR) 
-- All Rights Reserved

--[[

Unauthorized use and/or distribution of this work entitles myself, the author, to unlimited free and unrestricted use, access, and distribution of any works related to the unauthorized user and/or distributor.

--]]

THConstantMapping = {}
local THConstantMapping_mt = Class(THConstantMapping)
THConstantMapping.CLASS_NAME = "THConstantMapping"
local debugFlagId = THUtils.createDebugFlagId(THConstantMapping.CLASS_NAME)
THConstantMapping.debugFlagId = debugFlagId
local function initScript()
    local self = THConstantMapping.new()
    if self ~= nil then
        _G.g_thConstantMapping = self
    end
end
function THConstantMapping.new(customMt)
    customMt = customMt or THConstantMapping_mt
    if THUtils.argIsValid(type(customMt) == THValueType.TABLE, "customMt", customMt) then
        local self = setmetatable({}, customMt)
        self.constantMapping = {}
        self.mappingDebugFlagId = {
            base = debugFlagId,
            current = debugFlagId,
        }
        self.mappingDebugLevel = {
            base = THDebugLevel.ALL,
            current = THDebugLevel.ALL
        }
        return self
    end
end
function THConstantMapping.initConstantMapping(self, dataKey, className, isGlobal, reset)
    if THUtils.argIsValid(type(dataKey) == THValueType.STRING, "dataKey", dataKey)
        and THUtils.argIsValid(type(className) == THValueType.STRING, "className", className)
        and THUtils.argIsValid(not isGlobal or isGlobal == true, "isGlobal", isGlobal)
        and THUtils.argIsValid(not reset or reset == true, "reset", reset)
    then
        local target = (isGlobal == true and g_thGlobalEnv) or _G
        local baseValues = target[className]
        if type(baseValues) ~= THValueType.TABLE then
            THUtils.errorMsg(true, THMessage.ARGUMENT_INVALID, "className", className)
            return
        end
        local constantData = self.constantMapping[dataKey]
        if constantData ~= nil then
            if reset then
                self:resetConstantMapping(dataKey)
            else
                THUtils.errorMsg(false, "Constant mapping for %q already registered", className)
            end
        else
            constantData = {
                dataKey = dataKey,
                className = className,
                defaultValues = baseValues,
                currentValues = {},
                isGlobal = isGlobal,
                hasError = false
            }
            self.constantMapping[dataKey] = constantData
            if THUtils.getIsDebugEnabled() then
                THUtils.displayMsg("Initializing %s constant mapping:", constantData.className)
                THUtils.printTableValues(constantData.defaultValues, nil, true, 10)
            end
        end
        return constantData
    end
end
function THConstantMapping.mapConstant(self, dataKey, constantKey, newValue, altDebugFlagId, altDebugLevel)
    altDebugFlagId = altDebugFlagId or debugFlagId
    altDebugLevel = altDebugLevel or THDebugLevel.ALL
    local constantData = self.constantMapping[dataKey]
    local success = false
    if constantData == nil then
        THUtils.errorMsg(true, THMessage.ARGUMENT_INVALID, "dataKey", dataKey)
    else
        local target = (constantData.isGlobal == true and g_thGlobalEnv) or _G
        local baseValues = target[constantData.className]
        local oldValue = baseValues[constantKey]
        if oldValue == nil then
            THUtils.errorMsg(true, THMessage.ARGUMENT_INVALID, "constantKey", constantKey)
        elseif type(oldValue) ~= type(newValue) then
            THUtils.errorMsg(true, THMessage.ARGUMENT_INVALID, "newValue", newValue)
        elseif constantData.hasError then
            if THUtils.getIsDebugEnabled() then
                THUtils.errorMsg(true, "Could not map %s constant (data error)", constantData.className)
            end
        else
            local isChanged = oldValue ~= newValue or baseValues ~= constantData.currentValues
            if isChanged then
                constantData.currentValues[constantKey] = newValue
                if baseValues ~= constantData.currentValues then
                    for key, value in pairs(baseValues) do
                        if constantData.currentValues[key] == nil then
                            constantData.currentValues[key] = value
                        end
                    end
                    constantData.lastValues = baseValues
                    if constantData.isGlobal then
                        g_thGlobalEnv[constantData.className] = constantData.currentValues
                    else
                        _G[constantData.className] = constantData.currentValues
                    end
                end
                if THUtils.getIsDebugEnabled(altDebugFlagId, altDebugLevel) then
                    THUtils.displayMsg("Mapping %s constant: %s (%s >> %s)", constantData.className, constantKey, oldValue, newValue)
                    THUtils.printTableValues(target[constantData.className], nil, true, 10)
                    printCallstack()
                end
                success = true
            end
        end
    end
    return success
end
function THConstantMapping.resetConstantMapping(self, dataKey, altDebugFlagId, altDebugLevel)
    altDebugFlagId = altDebugFlagId or debugFlagId
    altDebugLevel = altDebugLevel or THDebugLevel.ALL
    local constantData = self.constantMapping[dataKey]
    local success = false
    if THUtils.argIsValid(constantData ~= nil, "dataKey", dataKey) then
        if constantData.hasError then
            if THUtils.getIsDebugEnabled() then
                THUtils.errorMsg(true, "Could not reset %s constants (data error)", constantData.className)
            end
        else
            local target = (constantData.isGlobal == true and g_thGlobalEnv) or _G
            local baseValues = target[constantData.className]
            local isReset = false
            if baseValues == constantData.currentValues then
                if constantData.lastValues ~= nil then
                    target[constantData.className] = constantData.lastValues
                elseif constantData.defaultValues ~= nil then
                    target[constantData.className] = constantData.defaultValues
                else
                    THUtils.errorMsg(true, "Cannot find default %s constants!", constantData.className)
                    constantData.hasError = true
                    return false
                end
                isReset = true
            end
            if next(constantData.currentValues) ~= nil then
                THUtils.clearTable(constantData.currentValues)
                isReset = true
            end
            if isReset then
                constantData.lastValues = nil
                if THUtils.getIsDebugEnabled(altDebugFlagId, altDebugLevel) then
                    THUtils.displayMsg("Resetting %s constants", constantData.className)
                    THUtils.printTableValues(target[constantData.className], nil, true, 10)
                    printCallstack()
                end
                success = true
            end
        end
    end
    return success
end
THUtils.pcall(initScript)