--[[
    AttachImplementsManuallyManager

    Manages the loading and application of config values for Attach Implements Manually

	@author: 		BayernGamers
	@date: 			06.05.2026
	@version:		1.0

	History:		v1.0 @06.05.2026 - initial implementation in FS25
                    ------------------------------------------------------------------------------------------------------

	
	License:        Terms:
                        Usage:
                            Feel free to use this work as-is as long as you adhere to the following terms:
						Attribution:
							You must give appropriate credit to the original author when using this work.
						No Derivatives:
							You may not alter, transform, or build upon this work in any way.
						Usage:
							The work may be used for personal and commercial purposes, provided it is not modified or adapted.
                        Non-Compete:
                            This script may not be used in any scripts or mods that can be considered to be a direct competitor to the mod this script is part of.
						Additional Clause:
							This script may not be converted, adapted, or incorporated into any other game versions or platforms except by GIANTS Software.
]]
source(Utils.getFilename("scripts/utils/Logger.lua", g_currentModDirectory))

local log = Logger.new(true, Logger.DEBUG_LEVELS.HIGH, "AttachImplementsManuallyManager.lua")

AttachImplementsManuallyManager = {}
AttachImplementsManuallyManager.MOD_DIRECTORY = g_currentModDirectory

local AttachImplementsManuallyManager_mt = Class(AttachImplementsManuallyManager, AbstractManager)

function AttachImplementsManuallyManager.new(customMt)
	local self = AbstractManager.new(customMt or AttachImplementsManuallyManager_mt)

    --addConsoleCommand("gsLoggerSetDebugLevel", "Set the debug level for a script", "consoleCommandSetDebugLevel", Logger, "[modName]; [scriptName]; [debugLevel]")
    addConsoleCommand("gsAimManagerListCustomFrontloaderJointTypes", "List all custom frontloader joint types across all active mods", "consoleCommandListCustomFrontloaderJointTypes", self, "[modName (optional)]")
    addConsoleCommand("gsAimManagerReloadCustomFrontloaderJointTypes", "Reload custom frontloader joint types from config files of all active mods", "consoleCommandReloadCustomFrontloaderJointTypes", self)

	return self
end

function AttachImplementsManuallyManager.createModDescSchema()
    local schema = g_modDescSchema

    schema:register(XMLValueType.FILENAME, "modDesc.attachImplementsManually#configFilename", "path to Attach Implements manually global config filename", nil, false)
end

function AttachImplementsManuallyManager.createConfigFileSchema()
    local schema = XMLSchema.new("AttachImplementsManuallyConfig")

    schema:register(XMLValueType.STRING, "attachImplementsManuallyConfig.customFrontloaderJointTypes.customFrontloaderJointType(?)#name", "Name of the custom frontloader joint type")
    schema:register(XMLValueType.STRING, "attachImplementsManuallyConfig.disabledVehicles.disabledVehicle(?)#xmlFilename", "XML filename of a vehicle for which Attach Implements Manually should be disabled")
    schema:register(XMLValueType.STRING, "attachImplementsManuallyConfig.disabledVehicles.disabledVehicle(?)#modName", "Name of the mod the disabled vehicle belongs to")

    return schema
end

function AttachImplementsManuallyManager:initDataStructures()
    AttachImplementsManuallyManager.createModDescSchema()
    self.configFileSchema = AttachImplementsManuallyManager.createConfigFileSchema()

    self.customFrontloaderJointTypes = {}
    self.customFrontloaderJointTypeIndices = {}
    self.customFrontloaderJointTypesByMod = {}
    self.activeConfigFiles = {}

    self.disabledVehicles = {}
end

function AttachImplementsManuallyManager:loadMapData()
    self.activeConfigFiles = self:loadConfigFilesFromActiveMods()
    self:loadConfigFiles()

    return true
end

function AttachImplementsManuallyManager:consoleCommandListCustomFrontloaderJointTypes(modName)
    if modName ~= nil and modName ~= "" then
        if not string.startsWith(modName, "FS25_") then
            modName = "FS25_" .. modName
        end

        if not g_modIsLoaded[modName] then
            Logging.error("Mod not found: " .. tostring(modName))
            return
        end

        if self.customFrontloaderJointTypesByMod[modName] ~= nil then
            print("Custom frontloader joint types for mod " .. modName .. ":")
            for jointType in pairs(self.customFrontloaderJointTypesByMod[modName]) do
                print("  - " .. jointType)
            end
        else
            print("No custom frontloader joint types found for mod " .. modName)
        end
    else
        print("Custom frontloader joint types across all active mods:")
        for modName, jointTypes in pairs(self.customFrontloaderJointTypesByMod) do
            print("  " .. modName .. ":")
            for jointType in pairs(jointTypes) do
                print("    - " .. jointType)
            end
        end
    end
end

function AttachImplementsManuallyManager:consoleCommandReloadCustomFrontloaderJointTypes()
    self.customFrontloaderJointTypes = {}
    self.customFrontloaderJointTypeIndices = {}
    self.customFrontloaderJointTypesByMod = {}

    for modName, configFilename in pairs(self.activeConfigFiles) do
        local fullPath = Utils.getFilename(configFilename, g_modNameToDirectory[modName])
        local configFile = XMLFile.loadIfExists("AttachImplementsManuallyConfig", configFilename, self.configFileSchema)

        if configFile ~= nil then
            self:loadCustomFrontloaderJointTypes(modName, configFile)

            configFile:delete()
        end
    end
end

function AttachImplementsManuallyManager:loadConfigFilesFromActiveMods()
    local activeConfigFiles = {}
    
    for _, mod in ipairs(g_modManager:getActiveMods()) do
        local modDesc = XMLFile.loadIfExists("ModFile", mod.modFile, g_modDescSchema)

        if modDesc ~= nil then
            local configFilename = modDesc:getValue("modDesc.attachImplementsManually#configFilename")

            if configFilename ~= nil and fileExists(Utils.getFilename(configFilename, mod.modDir)) then
                activeConfigFiles[mod.modName] = configFilename
            end
        end
    end

    return activeConfigFiles
end

function AttachImplementsManuallyManager:loadConfigFiles()
    for modName, configFilename in pairs(self.activeConfigFiles) do
        local fullPath = Utils.getFilename(configFilename, g_modNameToDirectory[modName])
        self:loadConfigFile(modName, fullPath)
    end
end

function AttachImplementsManuallyManager:loadConfigFile(modName, configFilename)
    local configFile = XMLFile.loadIfExists("AttachImplementsManuallyConfig", configFilename, self.configFileSchema)

    if configFile ~= nil then
        self:loadCustomFrontloaderJointTypes(modName, configFile)
        self:loadDisabledVehicles(modName, configFile)

        configFile:delete()
    else
        log:printError("Failed to load Attach Implements Manually config file: " .. tostring(configFilename))
    end
end

function AttachImplementsManuallyManager:loadCustomFrontloaderJointTypes(modName, configFile)
    if configFile == nil then
        log:printError("Config file is nil, cannot load custom frontloader joint types")
        return
    end

    configFile:iterate("attachImplementsManuallyConfig.customFrontloaderJointTypes.customFrontloaderJointType", function(_, key)
        local name = configFile:getValue(key .. "#name")



        if name ~= nil and name ~= "" then
            name = "JOINTTYPE_" .. name:upper()

            if AttacherJoints[name] ~= nil then
                self.customFrontloaderJointTypes[name] = true
                self.customFrontloaderJointTypeIndices[AttacherJoints[name]] = name
                
                if self.customFrontloaderJointTypesByMod[modName] == nil then
                    self.customFrontloaderJointTypesByMod[modName] = {}
                end

                self.customFrontloaderJointTypesByMod[modName][name] = true
            end
        else
            log:printXMLError(configFile, "Invalid or missing name for custom frontloader joint type " .. key)
        end
    end)
end

function AttachImplementsManuallyManager:loadDisabledVehicles(modName, configFile)  
    local mod = g_modManager:getModByName(modName)

    if mod ~= nil then
        configFile:iterate("attachImplementsManuallyConfig.disabledVehicles.disabledVehicle", function(_, key)
            local xmlFilename = configFile:getValue(key .. "#xmlFilename")
            
            if configFile.filename:find(AttachImplementsManuallyManager.MOD_DIRECTORY) then
                local customModName = configFile:getValue(key .. "#modName")

                if not string.isNilOrWhitespace(customModName) then
                    local customMod = g_modManager:getModByName(customModName)

                    if customMod ~= nil then
                        mod = customMod
                    else
                        log:printDevInfo("Mod specified for disabled vehicle is not loaded: %s. Defaulting to mod %s for resolving XML filename.", Logger.DEBUG_LEVELS.HIGH, customModName, modName)
                    end
                end
            end

            if not string.isNilOrWhitespace(xmlFilename) then
                local fullPath = Utils.getFilename(xmlFilename, mod.modDir)

                if fileExists(fullPath) then
                    self.disabledVehicles[fullPath] = true
                else
                    if mod.modDir ~= AttachImplementsManuallyManager.MOD_DIRECTORY then
                        log:printXMLError(configFile, "Disabled vehicle XML file not found: " .. fullPath)
                    end
                end
            else
                log:printXMLError(configFile, "Invalid or missing xmlFilename for disabled vehicle " .. key)
            end
        end)
    end
end

function AttachImplementsManuallyManager:getIsDisabledVehicle(vehicle)
    if vehicle == nil or vehicle.configFileName == nil then
        return false
    end

    return self.disabledVehicles[vehicle.configFileName] == true
end

g_attachImplementsManuallyManager = AttachImplementsManuallyManager.new()

Mission00.load = Utils.appendedFunction(Mission00.load, function(...)
    g_asyncTaskManager:addTask(function()
        g_attachImplementsManuallyManager:loadMapData()
    end)
end)

Mission00.delete = Utils.prependedFunction(Mission00.delete, function(...)
    g_attachImplementsManuallyManager:unloadMapData()
end)