--[[

Game:    Farming Simulator 19
Script:  FillLevelDashboard
Author:  ThundR
Created: 12/26/2020
Version: 1.0.0.0

--]]

-- <<[Declarations]>> -----------------------------------------------------------------------------

local g_modName = g_currentModName
local g_specName = "spec_"..g_modName..".fillLevelDashboard"

FillLevelDashboard = {}

function FillLevelDashboard.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Enterable, specializations)
        and SpecializationUtil.hasSpecialization(Dashboard, specializations)
end

function FillLevelDashboard.registerEventListeners(vehicleType)
    SpecializationUtil.registerEventListener(vehicleType, "onLoad", FillLevelDashboard)
end

function FillLevelDashboard.registerFunctions(vehicleType)
    SpecializationUtil.registerFunction(vehicleType, "dbGetFillLevel", FillLevelDashboard.dbGetFillLevel)
    SpecializationUtil.registerFunction(vehicleType, "dbGetFillWeight", FillLevelDashboard.dbGetFillWeight)
    SpecializationUtil.registerFunction(vehicleType, "dbGetWeightPerVolume", FillLevelDashboard.dbGetWeightPerVolume)
end

function FillLevelDashboard:onLoad(savegame)
    local spec = self[g_specName]
    local baseKey = "vehicle.fillLevelDashboard"
    local dashboardKey = baseKey..".dashboards"

    local xmlFile = self.xmlFile

    spec.allowedFillTypes = g_fillTypeManager:getFillTypesByCategoryNames("bulk")
    spec.volumeUnit = Utils.getNoNil(getXMLString(xmlFile, baseKey.."#volumeUnit"), "liter")
    spec.weightUnit = Utils.getNoNil(getXMLString(xmlFile, baseKey.."#weightUnit"), "kilogram")

    if self.loadDashboardsFromXML ~= nil then
        self:loadDashboardsFromXML(xmlFile, dashboardKey,
            {
                valueTypeToLoad = "fillLevel",
                valueObject = self,
                valueFunc = "dbGetFillLevel",
                minFunc = 0,
                maxFunc = 999999
            }
        )
        self:loadDashboardsFromXML(xmlFile, dashboardKey,
            {
                valueTypeToLoad = "fillWeight",
                valueObject = self,
                valueFunc = "dbGetFillWeight",
                minFunc = 0,
                maxFunc = 999999,
            }
        )
        self:loadDashboardsFromXML(xmlFile, dashboardKey,
            {
                valueTypeToLoad = "weightVolume",
                valueObject = self,
                valueFunc = "dbGetWeightPerVolume",
                minFunc = 0,
                maxFunc = 99999,
            }
        )
    end
end

-- <<[Specialization Functions]>> -----------------------------------------------------------------

function FillLevelDashboard:dbGetFillLevel()
    local spec = self[g_specName]
    local totalFillLevel = 0

    if self:getIsActive() then
        local dbVehicle = Utils.getNoNil(self:getSelectedVehicle(), self)
        local rootVehicle = Utils.getNoNil(self:getRootVehicle(), self)
        local fillLevelInfo = {}

        if dbVehicle == rootVehicle then
            dbVehicle:getFillLevelInformation(fillLevelInfo)
        elseif dbVehicle.spec_fillUnit ~= nil then
            local fillUnitSpec = dbVehicle.spec_fillUnit

            for _, fillUnit in pairs(fillUnitSpec.fillUnits) do
                if fillUnit.capacity > 0 and fillUnit.showOnHud then
                    local fillType  = fillUnit.fillType
                    local fillLevel = fillUnit.fillLevel
                    local capacity  = fillUnit.capacity

                    local added = false

                    for _, entry in ipairs(fillLevelInfo) do
                        if entry.fillType == fillType then
                            entry.fillLevel = entry.fillLevel + fillLevel
                            entry.capacity = entry.capacity + capacity
                            added = true
                            break
                        end
                    end

                    if not added then
                        table.insert(fillLevelInfo, {fillType=fillType, fillLevel=fillLevel, capacity=capacity})
                    end
                end
            end
        end

        for _, entry in ipairs(fillLevelInfo) do
            local fillTypeInfo = g_fillTypeManager:getFillTypeByIndex(entry.fillType)
            for _, allowedFillType in pairs(spec.allowedFillTypes) do
                if fillTypeInfo.index == allowedFillType then
                    local fillLevel = Utils.getNoNil(entry.fillLevel, 0)

                    if g_ucLite ~= nil then
                        local unitInfo = g_ucLite:getUnit(spec.volumeUnit)
                        if unitInfo ~= nil then
                            fillLevel = fillLevel * unitInfo.factor
                        end
                    end

                    totalFillLevel = totalFillLevel + fillLevel
                    break
                end
            end
        end
    end

    return totalFillLevel
end

function FillLevelDashboard:dbGetFillWeight()
    local spec = self[g_specName]
    local totalFillWeight = 0

    if self:getIsActive() then
        local dbVehicle = Utils.getNoNil(self:getSelectedVehicle(), self)
        local rootVehicle = Utils.getNoNil(self:getRootVehicle(), self)
        local fillLevelInfo = {}

        if dbVehicle == rootVehicle then
            dbVehicle:getFillLevelInformation(fillLevelInfo)
        elseif dbVehicle.spec_fillUnit ~= nil then
            local fillUnitSpec = dbVehicle.spec_fillUnit

            for _, fillUnit in pairs(fillUnitSpec.fillUnits) do
                if fillUnit.capacity > 0 and fillUnit.showOnHud then
                    local fillType  = fillUnit.fillType
                    local fillLevel = fillUnit.fillLevel
                    local capacity  = fillUnit.capacity

                    local added = false

                    for _, entry in ipairs(fillLevelInfo) do
                        if entry.fillType == fillType then
                            entry.fillLevel = entry.fillLevel + fillLevel
                            entry.capacity = entry.capacity + capacity
                            added = true
                            break
                        end
                    end

                    if not added then
                        table.insert(fillLevelInfo, {fillType=fillType, fillLevel=fillLevel, capacity=capacity})
                    end
                end
            end
        end

        for _, entry in ipairs(fillLevelInfo) do
            local fillTypeInfo = g_fillTypeManager:getFillTypeByIndex(entry.fillType)
            for _, allowedFillType in pairs(spec.allowedFillTypes) do
                if fillTypeInfo.index == allowedFillType then
                    local fillLevel = Utils.getNoNil(entry.fillLevel, 0)
                    local massPerLiter = Utils.getNoNil(fillTypeInfo.massPerLiter, 0)
                    local fillWeight = fillLevel * massPerLiter * 1000 -- convert to kg

                    if g_ucLite ~= nil then
                        local ucFillType = g_ucLite:getFillType(fillTypeInfo.name)
                        local unitInfo = g_ucLite:getUnit(spec.weightUnit)
                        if ucFillType ~= nil and unitInfo ~= nil then
                            massPerLiter = Utils.getNoNil(ucFillType.massPerLiter, 0)
                            fillWeight = fillLevel * massPerLiter * unitInfo.factor
                        end
                    end

                    totalFillWeight = totalFillWeight + fillWeight
                    break
                end
            end
        end
    end

    return totalFillWeight
end

function FillLevelDashboard:dbGetWeightPerVolume()
    local fillLevel = self:dbGetFillLevel()
    local weightPerVolume = 0

    if fillLevel > 0 then
        weightPerVolume = MathUtil.round(self:dbGetFillWeight() / fillLevel, 1)
    end
    return weightPerVolume
end