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

local thMain = g_thPlaceableDesign
local thI18n = thMain.i18n
THPlaceableDesignSpec = {}
THPlaceableDesignSpec.MOD_NAME = thMain.modName
THPlaceableDesignSpec.MOD_PATH = thMain.modPath
THPlaceableDesignSpec.DATA_KEY = "thPlaceableDesign"
THPlaceableDesignSpec.CONFIG_XML_PATH = "placeable." .. THPlaceableDesignSpec.DATA_KEY
THPlaceableDesignSpec.SAVEGAME_XML_PATH = "placeables.placeable(?)." .. THPlaceableDesignSpec.MOD_NAME .. "." .. THPlaceableDesignSpec.DATA_KEY
THPlaceableDesignSpec.DESIGN_KEY = THPlaceableDesignSpec.DATA_KEY
THPlaceableDesignSpec.COLOR_KEY = "thPlaceableColor"
THPlaceableDesignSpec.NUM_DESIGN_SLOTS = 8
THPlaceableDesignSpec.NUM_COLOR_SLOTS = 8
local function getSpecTable(self)
    return THUtils.getSpecTable(self, THPlaceableDesignSpec.DATA_KEY, THPlaceableDesignSpec.MOD_NAME)
end
function THPlaceableDesignSpec.initSpecialization()
    if THGameVersion == 25 then
        local configManager = g_placeableConfigurationManager
        for i = 1, THPlaceableDesignSpec.NUM_DESIGN_SLOTS do
            local configName = string.format("%s%d", THPlaceableDesignSpec.DESIGN_KEY, i)
            local configXMLKey = THPlaceableDesignSpec.DATA_KEY
            local configTitle = string.format("Design %d (PDK)", i)
            configManager:addConfigurationType(configName, configTitle, configXMLKey, PlaceableConfigurationItem)
        end
        for i = 1, THPlaceableDesignSpec.NUM_COLOR_SLOTS do
            local configName = string.format("%s%d", THPlaceableDesignSpec.COLOR_KEY, i)
            local configXMLKey = THPlaceableDesignSpec.DATA_KEY
            local configTitle = string.format("Color %d (PDK)", i)
            configManager:addConfigurationType(configName, configTitle, configXMLKey, PlaceableConfigurationItemColor)
        end
    end
end
function THPlaceableDesignSpec.prerequisitesPresent(specializations)
    return true
end
function THPlaceableDesignSpec.registerXMLPaths(xmlSchema, xmlPath)
    if THGameVersion == 22 then
        xmlSchema:setXMLSpecializationType("THPlaceableDesign")
        local function registerColorPaths(pBasePath)
            xmlSchema:register(XMLValueType.COLOR, pBasePath .. "#value", "Color name or rgb value")
            xmlSchema:register(XMLValueType.STRING, pBasePath .. "#title", "In-game color name")
        end
        local sharedColorsPath = xmlPath .. ".sharedColors.color(?)"
        registerColorPaths(sharedColorsPath)
        local colorGroupsPath = xmlPath .. ".colorGroups.group(?)"
        xmlSchema:register(XMLValueType.STRING, colorGroupsPath .. "#title", "Color group in-game name")
        xmlSchema:register(XMLValueType.BOOL, colorGroupsPath .. "#useSharedColors", "Use shared colors for this group")
        local groupColorsPath = colorGroupsPath .. ".colors.color(?)"
        registerColorPaths(groupColorsPath)
        local groupNodesPath = colorGroupsPath .. ".nodes.node(?)"
        xmlSchema:register(XMLValueType.NODE_INDEX, groupNodesPath .. "#id", "Colorable node id")
        xmlSchema:register(XMLValueType.STRING, groupNodesPath .. "#shaderParamName", "Name of shader parameter to adjust")
        xmlSchema:setXMLSpecializationType()
    end
end
function THPlaceableDesignSpec.registerEventListeners(vehicleType)
    SpecializationUtil.registerEventListener(vehicleType, "onLoad", THPlaceableDesignSpec)
end
function THPlaceableDesignSpec.registerFunctions(vehicleType)
    SpecializationUtil.registerFunction(vehicleType, "th_loadPlaceableDesignData", THPlaceableDesignSpec.th_loadPlaceableDesignData)
end
function THPlaceableDesignSpec.onLoad(self, savegame)
    local specTable = getSpecTable(self)
    specTable.hasColors = false
    specTable.sharedColors = {}
    specTable.colorGroups = {}
    specTable.currentColorGroup = 0
    local xmlFile = self.xmlFile
    local xmlBaseKey = THPlaceableDesignSpec.CONFIG_XML_PATH
    local components = self.components
    local i3dMappings = self.i3dMappings
    if xmlFile ~= nil then
        THUtils.call(function()
            self:th_loadPlaceableDesignData(xmlFile, xmlBaseKey, components, i3dMappings)
        end)
    end
end
function THPlaceableDesignSpec.th_loadPlaceableDesignData(self, xmlFile, xmlKey, components, i3dMappings, customEnv, basePath)
    customEnv = customEnv or THPlaceableDesignSpec.MOD_NAME
    basePath = basePath or THPlaceableDesignSpec.MOD_PATH
    local specTable = getSpecTable(self)
    local success = false
    if THUtils.argIsValid(type(xmlFile) == "table", "xmlFile", xmlFile)
        and THUtils.argIsValid(type(xmlKey) == "string", "xmlKey", xmlKey)
    then
        if THGameVersion ~= 22 then
            return true
        end
        specTable.currentColorGroup = 0
        specTable.hasColors = false
        local function loadColorData(pBaseKey, pColorIndex)
            local colorValue = xmlFile:getValue(pBaseKey .. "#value")
            local colorTitle = xmlFile:getValue(pBaseKey .. "#title")
            if colorValue == nil then
                THUtils.xmlErrorMsg(pBaseKey, nil, "Invalid color value")
            else
                local colorData = {
                    value = colorValue
                }
                if colorTitle == nil or colorTitle == "" then
                    colorTitle = thI18n:getText("thUI_genColorTitle")
                    colorData.title = string.format(colorTitle, pColorIndex)
                else
                    colorData.title = thI18n:convertText(colorTitle, customEnv)
                end
                return colorData
            end
        end
        local sharedColorsKey = xmlKey .. ".sharedColors"
        if xmlFile:hasProperty(sharedColorsKey) then
            THUtils.clearTable(specTable.sharedColors)
            xmlFile:iterate(sharedColorsKey .. ".color", function(_, pColorKey)
                local colorData = loadColorData(pColorKey, #specTable.sharedColors + 1)
                if colorData ~= nil then
                    table.insert(specTable.sharedColors, colorData)
                end
            end)
        end
        local colorGroupsKey = xmlKey .. ".colorGroups"
        if xmlFile:hasProperty(colorGroupsKey) then
            THUtils.clearTable(specTable.colorGroups)
            xmlFile:iterate(colorGroupsKey .. ".group", function(_, pGroupKey)
                local groupTitle = xmlFile:getValue(pGroupKey .. "#title")
                local useSharedColors = xmlFile:getValue(pGroupKey .. "#useSharedColors", true)
                local colorGroupData = {
                    index = #specTable.colorGroups + 1,
                    nodes = {},
                    colors = {},
                    currentColor = 0
                }
                if groupTitle ~= nil and groupTitle ~= "" then
                    colorGroupData.title = thI18n:convertText(groupTitle, customEnv)
                else
                    groupTitle = thI18n:getText("thUI_genColorGroupTitle")
                    colorGroupData.title = string.format(groupTitle, colorGroupData.index)
                end
                if useSharedColors then
                    for _, colorData in ipairs(specTable.sharedColors) do
                        table.insert(colorGroupData.colors, colorData)
                    end
                end
                local colorsKey = pGroupKey .. ".colors"
                if xmlFile:hasProperty(colorsKey) then
                    xmlFile:iterate(colorsKey .. ".color", function(_, pColorKey)
                        local colorData = loadColorData(pColorKey, #colorGroupData.colors + 1)
                        if colorData ~= nil then
                            table.insert(colorGroupData.colors, colorData)
                        end
                    end)
                end
                local nodesKey = pGroupKey .. ".nodes"
                if xmlFile:hasProperty(nodesKey) then
                    xmlFile:iterate(nodesKey .. ".node", function(_, pNodeKey)
                        local nodeId = xmlFile:getValue(pNodeKey .. "#id", nil, components, i3dMappings)
                        local shaderParamName = xmlFile:getValue(pNodeKey .. "#shaderParamName", "colorScale0")
                        if THUtils.getNoNil(nodeId, 0) <= 0 then
                            THUtils.xmlErrorMsg(pNodeKey, nil, "Invalid node id")
                        else
                            local nodeName = getName(nodeId) or tostring(nodeId)
                            if not getHasShaderParameter(nodeId, shaderParamName) then
                                THUtils.xmlErrorMsg(pNodeKey, nil, "Node %q does not have shader parameter %q", nodeName, shaderParamName)
                            else
                                local isNodeFound = false
                                for _, otherNodeData in pairs(colorGroupData.nodes) do
                                    if otherNodeData.id == nodeId then
                                        isNodeFound = true
                                        break
                                    end
                                end
                                if isNodeFound then
                                    THUtils.xmlErrorMsg(pNodeKey, false, "Node %q already added to color group", nodeName)
                                else
                                    local nodeData = {
                                        id = nodeId,
                                        name = nodeName,
                                        shaderParamName = shaderParamName,
                                    }
                                    table.insert(colorGroupData.nodes, nodeData)
                                end
                            end
                        end
                    end)
                end
                if next(colorGroupData.colors) == nil then
                    THUtils.xmlErrorMsg(pGroupKey, nil, "No available colors")
                elseif next(colorGroupData.nodes) == nil then
                    THUtils.xmlErrorMsg(pGroupKey, nil, "No available nodes")
                else
                    colorGroupData.currentColor = 1
                    specTable.colorGroups[colorGroupData.index] = colorGroupData
                    if specTable.currentColorGroup <= 0 then
                        specTable.currentColorGroup = 1
                    end
                    specTable.hasColors = true
                end
            end)
        end
        success = true
    end
    return success
end
function THPlaceableDesignSpec.inj_getConfigurationsFromXML(superFunc, manager, xmlFile, ...)
    if manager ~= nil and xmlFile ~= nil
        and THGameVersion == 25
    then
        THUtils.call(function()
            for i = 1, THPlaceableDesignSpec.NUM_COLOR_SLOTS do
                local configName = string.format("%s%d", THPlaceableDesignSpec.COLOR_KEY, i)
                local configInfo = manager:getConfigurationDescByName(configName)
                if configInfo ~= nil
                    and configInfo.configurationsKey ~= nil
                    and configInfo.configurationKey ~= nil
                    and xmlFile:hasProperty(configInfo.configurationsKey)
                then
                    local configData = thMain:createDataTable(configInfo)
                    if configData ~= nil then
                        local numXMLItems = 0
                        xmlFile:iterate(configInfo.configurationKey, function()
                            numXMLItems = numXMLItems + 1
                        end)
                        if not configData.isInitialized then
                            configData.numXMLItems = numXMLItems
                            configData.isInitialized = true
                        end
                        local useSharedColors = xmlFile:getBool(configInfo.configurationsKey .. "#useSharedColors")
                        local sharedColorsKey = THPlaceableDesignSpec.CONFIG_XML_PATH .. ".sharedColors"
                        if useSharedColors and xmlFile:hasProperty(sharedColorsKey) then
                            local configXMLIndex = configData.numXMLItems
                            local configXMLKey = string.format("%s(%d)", configInfo.configurationKey, configXMLIndex)
                            if not xmlFile:hasProperty(configXMLKey) then
                                xmlFile:iterate(sharedColorsKey .. ".color", function(_, pColorKey)
                                    local colorValue = xmlFile:getString(pColorKey .. "#value")
                                    if colorValue ~= nil and colorValue ~= "" then
                                        xmlFile:setString(configXMLKey .. "#color", colorValue)
                                        configXMLIndex = configXMLIndex + 1
                                        configXMLKey = string.format("%s(%d)", configInfo.configurationKey, configXMLIndex)
                                    end
                                end)
                            end
                        end
                    end
                end
            end
        end)
    end
    return superFunc(manager, xmlFile, ...)
end
THUtils.call(function()
    if THGameVersion == 25 then
        THUtils.setFunctionHook("ConfigurationUtil", "getConfigurationsFromXML", false, false, nil, THPlaceableDesignSpec.inj_getConfigurationsFromXML)
    end
end)