-- BGA_FilltypeExtension.lua
-- Version 1.1.0.0
-- Autor: Tidde23


BGA_FilltypeExtension = {}

BGA_FilltypeExtension.attachBaseFillType = "SILAGE"

-- Conversion Table: New Filltypes can be added here
BGA_FilltypeExtension.extraFillTypesConfig = {
    { name = "CHOPPEDMAIZE_FERMENTED", ratio = 1.10 },
    { name = "GRASS_FERMENTED",        ratio = 0.95 },
    { name = "ALFALFA_FERMENTED",      ratio = 0.83 },
    { name = "CLOVER_FERMENTED",       ratio = 0.90 },

    { name = "GRASS_WINDROW",          ratio = 0.49 },
    { name = "ALFALFA_WINDROW",        ratio = 0.42 },
    { name = "CLOVER_WINDROW",         ratio = 0.41 },
}

BGA_FilltypeExtension.filteredExtras = nil

local function getFillTypeIndex(name)
    if not name or name == "" then return nil end
    return g_fillTypeManager:getFillTypeIndexByName(string.upper(name))
end

local function splitStringToArray(str)
    if not str or str == "" then return {} end
    return string.split(str, " ")
end

local function hasFillTypeToken(str, token)
    if not str or str == "" then return false end
    token = token:upper()
    local tokens = splitStringToArray(str)
    for i=1, #tokens do
        if tokens[i]:upper() == token then
            return true
        end
    end
    return false
end

local function appendUniqueFillTypeTokens(str, names)
    local existingTokens = {}
    local tokens = splitStringToArray(str)
    for i=1, #tokens do
        existingTokens[tokens[i]:upper()] = true
    end
    
    local newString = str or ""
    for i=1, #names do
        local upperName = names[i]:upper()
        if not existingTokens[upperName] then
            newString = (newString == "") and upperName or (newString .. " " .. upperName)
            existingTokens[upperName] = true
        end
    end
    return newString
end

function BGA_FilltypeExtension:loadMap(_)
    local baseIndex = getFillTypeIndex(self.attachBaseFillType)
    if baseIndex == nil then
        self.filteredExtras = {}
        return
    end

    local filteredConfigurations = {}
    for i=1, #self.extraFillTypesConfig do
        local config = self.extraFillTypesConfig[i]
        local fillTypeIndex = getFillTypeIndex(config.name)
        if fillTypeIndex ~= nil then
            table.insert(filteredConfigurations, {
                name  = config.name:upper(),
                ratio = config.ratio or 1.0
            })
        else
            Logging.warning("[BGA_FilltypeExtension] Warning: Filltype '%s' is not registered in the game. It will be ignored.", config.name)
        end
    end
    self.filteredExtras = filteredConfigurations
end
addModEventListener(BGA_FilltypeExtension)

local function isBiogasProduction(xmlFile, key)
    local isBiogas = false
    xmlFile:iterate(key .. ".productions.production", function(_, productionKey)
        xmlFile:iterate(productionKey .. ".outputs.output", function(_, outputKey)
            local fillTypeName = (xmlFile:getValue(outputKey .. "#fillType", "") or ""):upper()
            if fillTypeName == "METHANE" or fillTypeName == "DIGESTATE" or fillTypeName == "SILAGE_IN" or fillTypeName == "MANURE_IN" or fillTypeName == "SUGARBEETCUT_IN" then
                isBiogas = true
            end
        end)
    end)
    return isBiogas
end

local function hasFillTypeConversion(xmlFile, unloadTriggerKey, incomingName, outgoingName)
    local conversionExists = false
    xmlFile:iterate(unloadTriggerKey .. ".fillTypeConversion", function(_, conversionKey)
        local incomingFillTypeName  = (xmlFile:getValue(conversionKey .. "#incomingFillType") or ""):upper()
        local outgoingFillTypeName = (xmlFile:getValue(conversionKey .. "#outgoingFillType") or ""):upper()
        if incomingFillTypeName == incomingName:upper() and outgoingFillTypeName == outgoingName:upper() then
            conversionExists = true
        end
    end)
    return conversionExists
end

local function addConversionsForAditionalFillTypes(xmlFile, triggerKey, baseFillTypeName, extraFillTypes)
    local lastConversionIndex = -1
    xmlFile:iterate(triggerKey .. ".fillTypeConversion", function(index, _)
        if index > lastConversionIndex then lastConversionIndex = index end
    end)

    for _, config in ipairs(extraFillTypes or {}) do
        local incomingFillTypeName = config.name
        if not hasFillTypeConversion(xmlFile, triggerKey, incomingFillTypeName, baseFillTypeName) then
            lastConversionIndex = lastConversionIndex + 1
            local conversionKey = string.format("%s.fillTypeConversion(%d)", triggerKey, lastConversionIndex)
            xmlFile:setValue(conversionKey .. "#incomingFillType", incomingFillTypeName)
            xmlFile:setValue(conversionKey .. "#outgoingFillType", baseFillTypeName:upper())
            xmlFile:setValue(conversionKey .. "#ratio", config.ratio or 1.0)
        end
    end
end

local function extendBaleTriggers(xmlFile, baseProductionKey, baseFillType, extraFillTypes)
    xmlFile:iterate(baseProductionKey .. ".sellingStation.baleTrigger", function(_, baleTriggerKey)
        local fillTypesString = xmlFile:getString(baleTriggerKey .. "#fillTypes")
        if fillTypesString ~= nil and hasFillTypeToken(fillTypesString, baseFillType) then
            local fillTypesToAdd = {}
            for i=1, #extraFillTypes do
                table.insert(fillTypesToAdd, extraFillTypes[i].name)
            end
            local newFillTypesString = appendUniqueFillTypeTokens(fillTypesString, fillTypesToAdd)
            xmlFile:setString(baleTriggerKey .. "#fillTypes", newFillTypesString)
            
            addConversionsForAditionalFillTypes(xmlFile, baleTriggerKey, baseFillType, extraFillTypes)
        end
    end)
end

local function onLoadProductionPoint(self, superFunc, components, xmlFile, key, customEnv, i3dMappings)
    if BGA_FilltypeExtension.filteredExtras == nil or #BGA_FilltypeExtension.filteredExtras == 0 then
        return superFunc(self, components, xmlFile, key, customEnv, i3dMappings)
    end

    if not isBiogasProduction(xmlFile, key) then
        return superFunc(self, components, xmlFile, key, customEnv, i3dMappings)
    end

    local baseFillTypeName = BGA_FilltypeExtension.attachBaseFillType

    xmlFile:iterate(key .. ".sellingStation.unloadTrigger", function(_, unloadTriggerKey)
        local fillTypesString = xmlFile:getString(unloadTriggerKey .. "#fillTypes")
        if fillTypesString == nil or fillTypesString == "" then
            return
        end

        if not hasFillTypeToken(fillTypesString, baseFillTypeName) then
            return
        end

        local fillTypesToAdd = {}
        for i=1, #BGA_FilltypeExtension.filteredExtras do
            table.insert(fillTypesToAdd, BGA_FilltypeExtension.filteredExtras[i].name)
        end
        local newFillTypesString = appendUniqueFillTypeTokens(fillTypesString, fillTypesToAdd)
        xmlFile:setString(unloadTriggerKey .. "#fillTypes", newFillTypesString)

        addConversionsForAditionalFillTypes(xmlFile, unloadTriggerKey, baseFillTypeName, BGA_FilltypeExtension.filteredExtras)
    end)

    extendBaleTriggers(xmlFile, key, baseFillTypeName, BGA_FilltypeExtension.filteredExtras)

    return superFunc(self, components, xmlFile, key, customEnv, i3dMappings)
end

ProductionPoint.load = Utils.overwrittenFunction(ProductionPoint.load, onLoadProductionPoint)
