--[[
Interface: 1.5.1.0 b6732

Copyright (C) GtX (Andy), 2019

Author: GtX | Andy
Date: 15.03.2019
Version: 1.0.0.0

Contact:
https://forum.giants-software.com
https://github.com/GtX-Andy

History:
V 1.0.0.0 @ 15.03.2019 - Release Version
V 1.1.0.0 @ 16.10.2019 - Disable on maps as this should be done correctly as Giants intended using 'maps_fillTypes.xml'
                       - Removed 'densityMapHeightType' feature for the moment due to conflicts. Feature should only be added by map authors only anyway.

About:
1: Allows extra 'fillTypes', 'fillTypeCategories', fillTypeConverters to be added with Placeable mods.
2: Allows extra / new 'fillTypes' to be added to animal food groups.
3: Allows extra / new 'fillTypes' to be added to placeable Selling Stations mods and maps.

Important:
No changes are to be made to this script without permission from GtX | Andy!
An diesem Skript dürfen ohne Genehmigung von GtX | Andy keine Änderungen vorgenommen werden!
]]


RegisterFillTypes = {}

RegisterFillTypes.modName = g_currentModName
RegisterFillTypes.modDirectory = g_currentModDirectory

local function printToLog(showPrint, typ, text, ...)
    if showPrint then
        print("  " .. typ .. ": [" .. RegisterFillTypes.modName .. "] - [RegisterFillTypes] " .. string.format(text, ...))
    end
end

function RegisterFillTypes.init()
    if g_modManager:isModMap(RegisterFillTypes.modName) then
        print(string.format("  Error: [%s] - [RegisterFillTypes] This script should only be used for Placeable Mods! Use correct method provided by Giants to add new fillTypes to maps.", RegisterFillTypes.modName))
        return
    end

    FSBaseMission.loadMapFinished = Utils.prependedFunction(FSBaseMission.loadMapFinished, RegisterFillTypes.loadMapFinished)
end

function RegisterFillTypes:loadMapFinished(node)
    if node ~= 0 then
        local xmlFile = loadXMLFile("TempModDesc", RegisterFillTypes.modDirectory .. "modDesc.xml")
        if xmlFile ~= 0 then
            local showAllPrints = Utils.getNoNil(getXMLBool(xmlFile, "modDesc.registerFillTypes#showDebugPrints"), false)

            if RegisterFillTypes:loadFillTypes(xmlFile, showAllPrints) > 0 then
                g_currentMission.hud.fillLevelsDisplay:refreshFillTypes(g_fillTypeManager)
            end

            RegisterFillTypes:loadCategories(xmlFile, showAllPrints)
            RegisterFillTypes:loadConverters(xmlFile, showAllPrints)

            RegisterFillTypes:addToAnimalFoodGroups(xmlFile, showAllPrints)
            RegisterFillTypes:addToSellingStations(xmlFile, showAllPrints)

            delete(xmlFile)
            xmlFile = nil
        end
    end
end

function RegisterFillTypes:loadFillTypes(xmlFile, showAllPrints)
    local addedFillTypes = 0

    local i = 0
    while true do
        local key = string.format("modDesc.registerFillTypes.fillTypes.fillType(%d)", i)
        if not hasXMLProperty(xmlFile, key) then
            break
        end

        local name = getXMLString(xmlFile, key .. "#name")
        if name ~= nil then
            name = name:upper()

            if g_fillTypeManager:getFillTypeByName(name) == nil then
                local title = getXMLString(xmlFile, key .. "#title")
                local showOnPriceTable = Utils.getNoNil(getXMLBool(xmlFile, key .. "#showOnPriceTable"), false)
                local pricePerLiter = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#pricePerLiter"), 0.2)
                local massPerLiter = Utils.getNoNil(getXMLFloat(xmlFile, key .. ".physics#massPerLiter"),  0.0001)
                local maxPhysicalSurfaceAngle = math.rad(Utils.getNoNil(getXMLInt(xmlFile, key .. ".physics#maxPhysicalSurfaceAngle"), 30))
                local hudOverlayFilename = Utils.getNoNil(getXMLString(xmlFile, key .. ".image#hud"), "$dataS2/menu/hud/fillTypes/hud_fill_unknown.dds")
                local hudOverlayFilenameSmall = Utils.getNoNil(getXMLString(xmlFile, key .. ".image#hudSmall"), hudOverlayFilename)
                local palletFilename = getXMLString(xmlFile, key .. ".pallet#filename")

                local fillType = g_fillTypeManager:addFillType(name, title, showOnPriceTable, pricePerLiter, massPerLiter, maxPhysicalSurfaceAngle, hudOverlayFilename, hudOverlayFilenameSmall, RegisterFillTypes.modDirectory, nil, {1,1,1}, palletFilename, false)
                if fillType ~= nil then
                    addedFillTypes = addedFillTypes + 1

                    -- If true then the 'Liquid' sound will be used instead of grain.
                    if Utils.getNoNil(getXMLBool(xmlFile, key .. "#useLiquidSample"), false) then
                        local sample = g_fillTypeManager.fillTypeSamples[3]
                        if sample ~= nil and sample == g_fillTypeManager.fillTypeToSample[FillType.WATER] then
                            g_fillTypeManager.fillTypeToSample[fillType] = sample
                            printToLog(showAllPrints, "Info", "Fill Type '%s' added to liquid sample successfully.", name)
                        end
                    end

                    if not showAllPrints then
                        print("Register FillType '" .. name .. "'")
                    else
                        printToLog(showAllPrints, "Info", "Fill Type '%s' added successfully by %s.", name, RegisterFillTypes.modName)
                    end
                end
            else
                printToLog(showAllPrints, "Warning", "A Fill Type using the name '%s' already exists and can not be added!", name)
            end
        end

        i = i + 1
    end

    return addedFillTypes
end

function RegisterFillTypes:loadCategories(xmlFile, showAllPrints)
    local i = 0
    while true do
        local key = string.format("modDesc.registerFillTypes.fillTypeCategories.fillTypeCategory(%d)", i)
        if not hasXMLProperty(xmlFile, key) then
            break
        end

        -- If 'Category' does not exist it will be created, otherwise the fill type will be added tp to the given category.
        local name = getXMLString(xmlFile, key .. "#name")
        local fillTypeCategories = StringUtil.splitString(" ", getXMLString(xmlFile, key))

        if name ~= nil then
            name = name:upper()

            if fillTypeCategories ~= nil then
                for i = 1, #fillTypeCategories do
                    local fillTypeIndex = g_fillTypeManager:getFillTypeIndexByName(fillTypeCategories[i])
                    if fillTypeIndex ~= nil then
                        local categoryIndex = g_fillTypeManager.nameToCategoryIndex[name]
                        if categoryIndex == nil then
                            categoryIndex = g_fillTypeManager:addFillTypeCategory(name, false)
                        end

                        g_fillTypeManager:addFillTypeToCategory(fillTypeIndex, categoryIndex)
                    end
                end
            else
                printToLog(true, "Error", "No 'fillTypeCategories' given at %s!", key)
            end
        else
            printToLog(true, "Error", "No 'name' given for category at %s!", key)
        end

        i = i + 1
    end
end

function RegisterFillTypes:loadConverters(xmlFile, showAllPrints)
    local i = 0
    while true do
        local key = string.format("modDesc.registerFillTypes.fillTypeConverters.fillTypeConverter(%d)", i)
        if not hasXMLProperty(xmlFile, key) then
            break
        end

        -- If 'Converter' does not exist it will be created.
        local converterName = getXMLString(xmlFile, key .. "#name")
        if converterName ~= nil then
            converterName = converterName:upper()

            local converter = g_fillTypeManager:getConverterDataByName(converterName)
            if converter == nil then
                converter = g_fillTypeManager:addFillTypeConverter(converterName, false)
            end

            local j = 0
            while true do
                local converterKey = string.format("%s.converter(%d)", j)
                if not hasXMLProperty(xmlFile, converterKey) then
                    break
                end

                local sourceFillTypeName = getXMLString(xmlFile, converterKey .. "#from")
                local targetFillTypeName = getXMLString(xmlFile, converterKey .. "#to")

                if sourceFillTypeName ~= nil and targetFillTypeName ~= nil then
                    local sourceFillTypeIndex = g_fillTypeManager:getFillTypeIndexByName(sourceFillTypeName)
                    local targetFillTypeIndex = g_fillTypeManager:getFillTypeIndexByName(targetFillTypeName)
                    local conversionFactor = Utils.getNoNil(getXMLFloat(xmlFile, converterKey .. "#factor"), 1.0)

                    if sourceFillTypeIndex ~= nil then
                        if targetFillTypeIndex ~= nil then
                            g_fillTypeManager:addFillTypeConversion(converter, sourceFillTypeIndex, targetFillTypeIndex, conversionFactor)
                        else
                            printToLog(true, "Error", "Invalid fill type '%s' given at %s!", targetFillTypeName, key)
                        end
                    else
                        printToLog(true, "Error", "Invalid fill type '%s' given at %s!", sourceFillTypeIndex, key)
                    end
                end

                j = j + 1
            end
        else
            printToLog(true, "Error", "No 'name' given for fill type converter at %s!", key)
        end

        i = i + 1
    end
end

function RegisterFillTypes:addToAnimalFoodGroups(xmlFile, showAllPrints)
    local i = 0
    while true do
        local key = string.format("modDesc.registerFillTypes.addToAnimalFoodGroups.animalFoodGroup(%d)", i)
        if not hasXMLProperty(xmlFile, key) then
            break
        end


        local animalType = getXMLString(xmlFile, key .. "#type")
        if animalType ~= nil then
            animalType = animalType:upper()

            local foodGroupContent = g_animalFoodManager:getFoodGroupByAnimalType(animalType)
            if foodGroupContent ~= nil then
                local foodGroupToUse

                -- Find Food Group using an existing Fill Type for the Food Group.
                local existingFillTypeStr = getXMLString(xmlFile, key .. "#existingFillType")
                if existingFillTypeStr ~= nil then
                    local existingFillType = g_fillTypeManager:getFillTypeIndexByName(existingFillTypeStr)
                    for _, foodGroup in pairs(foodGroupContent) do
                        for _, foodGroupFillTypeIndex in pairs(foodGroup.fillTypes) do
                            if foodGroupFillTypeIndex == existingFillType then
                                foodGroupToUse = foodGroup
                                break
                            end
                        end
                    end
                else
                    -- Direct index location of the Food Group to use if known.
                    local index = getXMLInt(xmlFile, key .. "#foodGroupIndex")
                    foodGroupToUse = foodGroupContent[index]
                end

                if foodGroupToUse ~= nil then
                    local fillTypesStr = Utils.getNoNil(getXMLString(xmlFile, key .. "#fillTypes"), "")
                    local fillTypes = g_fillTypeManager:getFillTypesByNames(fillTypesStr, "Warning: Invalid fill type '%s' give at '" .. key .. "'!")

                    local numFillTypes = #fillTypes
                    if numFillTypes > 0 then
                        local existingFillTypes = {}

                        for _, fillTypeIndex in pairs (foodGroupToUse.fillTypes) do
                            existingFillTypes[fillTypeIndex] = true
                        end

                        for _, fillTypeIndex in pairs (fillTypes) do
                            if not existingFillTypes[fillTypeIndex] then
                                existingFillTypes[fillTypeIndex] = true
                                table.insert(foodGroupToUse.fillTypes, fillTypeIndex)
                            end
                        end
                    end
                else
                    printToLog(true, "Error", "A valid Food Group could not be found at %s!", key)
                end
            else
                printToLog(true, "Error", "A valid Food Group could not be found or Animal Type %s does not exist!", animalType, key)
            end
        else
            printToLog(true, "Error", "No 'type' given at %s!", key)
        end

        i = i + 1
    end
end

function RegisterFillTypes:addToSellingStations(xmlFile, showAllPrints)
    local i = 0
    while true do
        local key = string.format("modDesc.registerFillTypes.addToSellingStations.fillType(%d)", i)
        if not hasXMLProperty(xmlFile, key) then
            break
        end

        -- This is the fill type to inject into the sell points.
        local fillTypeName = getXMLString(xmlFile, key .. "#name")

        -- This is an existing fill type the sell point must include to allow new fill type.
        local requiredFillTypeName = getXMLString(xmlFile, key .. "#required")

        if fillTypeName ~= nil and requiredFillTypeName ~= nil then
            local fillTypeIndex = g_fillTypeManager:getFillTypeIndexByName(fillTypeName)
            if fillTypeIndex ~= nil then
                local requiredFillTypeIndex = g_fillTypeManager:getFillTypeIndexByName(requiredFillTypeName)
                if requiredFillTypeIndex ~= nil then
                    if SellingStation.FILLTYPES_TO_INJECT == nil then
                        SellingStation.FILLTYPES_TO_INJECT = {}

                        SellingStation.initPricingDynamics = Utils.prependedFunction(SellingStation.initPricingDynamics, function(self)
                            if SellingStation.FILLTYPES_TO_INJECT ~= nil and self.addAcceptedFillType ~= nil then
                                for _, fillType in pairs (SellingStation.FILLTYPES_TO_INJECT) do
                                    if self.acceptedFillTypes[fillType.requiredFillTypeIndex] ~= nil and self.acceptedFillTypes[fillType.fillTypeIndex] == nil then
                                        self:addAcceptedFillType(fillType.fillTypeIndex, fillType.priceScale, fillType.supportsGreatDemand, fillType.disablePriceDrop)
                                        -- print(string.format("  Info: %s successfully injected fillType '%s' to Selling station %s.", fillType.modName, fillTypeName, self.stationName))
                                    end
                                end
                            end
                        end)

                        FSBaseMission.delete = Utils.appendedFunction(FSBaseMission.delete, function(self)
                            SellingStation.FILLTYPES_TO_INJECT = nil
                            -- print("  Info: 'SellingStation.FILLTYPES_TO_INJECT' clean up completed.")
                        end)
                    end

                    if SellingStation.FILLTYPES_TO_INJECT[fillTypeIndex] == nil then
                        local fillType = {fillTypeIndex = fillTypeIndex, requiredFillTypeIndex = requiredFillTypeIndex}

                        fillType.priceScale = Utils.getNoNil(getXMLFloat(xmlFile, key .. "#priceScale"), 1.0)
                        fillType.supportsGreatDemand = Utils.getNoNil(getXMLBool(xmlFile, key.."#supportsGreatDemand"), false)
                        fillType.disablePriceDrop = Utils.getNoNil(getXMLBool(xmlFile, key.."#disablePriceDrop"), false)
                        fillType.modName = RegisterFillTypes.modName
                        fillType.fillTypeName = fillTypeName

                        SellingStation.FILLTYPES_TO_INJECT[fillTypeIndex] = fillType
                    else
                        if showAllPrints then
                            local fillTypeData = SellingStation.FILLTYPES_TO_INJECT[fillTypeIndex]
                            printToLog(true, "Info", "Fill type %s has already added to Selling Stations by %s, ignoring.", fillTypeName, fillTypeData.modName)
                        end
                    end
                else
                    printToLog(true, "Error", "Invalid fill type '%s' given at '%s#required'!", requiredFillTypeName, key)
                end
            else
                printToLog(true, "Error", "Invalid fill type '%s' given at '%s#name'!", fillTypeName, key)
            end
        else
            printToLog(true, "Error", "'name' (FillType to add.) or 'required' (FillType sell point must include already.) not found at %s!", key)
        end

        i = i + 1
    end
end

RegisterFillTypes.init()
