---
-- ExactFillNodeBlock
--
--
-- @author      nilBrain
-- @date        2026-07-12
--
-- Copyright (C) nilBrain | Philipp Jaeger, Confidential, All Rights Reserved.

ExactFillNodeBlock = {}

local modName = g_currentModName

ExactFillNodeBlock.SPEC_NAME = modName .. ".exactFillNodeBlock"
ExactFillNodeBlock.SPEC_TABLE_NAME = "spec_" .. modName .. ".exactFillNodeBlock"

ExactFillNodeBlock.CLAIM_TIMEOUT_MS = 500

---Checks if all prerequisite specializations are loaded
-- @param table specializations specializations
-- @return boolean hasPrerequisite true if all prerequisite specializations are loaded
function ExactFillNodeBlock.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(FillUnit, specializations)
end

---Register all function overwritings
-- @param table vehicleType vehicle type
function ExactFillNodeBlock.registerOverwrittenFunctions(vehicleType)
    SpecializationUtil.registerOverwrittenFunction(vehicleType, "getFillUnitIndexFromNode", ExactFillNodeBlock.getFillUnitIndexFromNode)
    SpecializationUtil.registerOverwrittenFunction(vehicleType, "getFillUnitFromNode", ExactFillNodeBlock.getFillUnitFromNode)
    SpecializationUtil.registerOverwrittenFunction(vehicleType, "getFillUnitExtraDistanceFromNode", ExactFillNodeBlock.getFillUnitExtraDistanceFromNode)
end

---Register all events that should be called for this specialization
-- @param table vehicleType vehicle type
function ExactFillNodeBlock.registerEventListeners(vehicleType)
    SpecializationUtil.registerEventListener(vehicleType, "onLoad", ExactFillNodeBlock)
    SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", ExactFillNodeBlock)
end

---Register all functions from the specialization that can be called on vehicle level
-- @param table vehicleType vehicle type
function ExactFillNodeBlock.registerFunctions(vehicleType)
    SpecializationUtil.registerFunction(vehicleType, "claimExactFillRootNode", ExactFillNodeBlock.claimExactFillRootNode)
end

---Called on load
-- @param table savegame savegame
function ExactFillNodeBlock:onLoad(savegame)
    local spec = self[ExactFillNodeBlock.SPEC_TABLE_NAME]
    spec.activeNode = nil
    spec.activeNodeTimeout = 0
end

---Called on update tick — releases the claimed node once it has not been used for a while
-- @param float dt time since last call in ms
function ExactFillNodeBlock:onUpdateTick(dt)
    local spec = self[ExactFillNodeBlock.SPEC_TABLE_NAME]
    if spec.activeNode == nil then
        return
    end

    spec.activeNodeTimeout = spec.activeNodeTimeout - dt
    if spec.activeNodeTimeout <= 0 then
        spec.activeNode = nil
    end
end

---Claims the given node as the currently active exact-fill root node
-- @param entityId node exact-fill root node
-- @return boolean isClaimAllowed true if the node is the active one (or became the active one)
function ExactFillNodeBlock:claimExactFillRootNode(node)
    local spec = self[ExactFillNodeBlock.SPEC_TABLE_NAME]

    if spec.activeNode ~= nil and spec.activeNode ~= node then
        return false
    end

    spec.activeNode = node
    spec.activeNodeTimeout = ExactFillNodeBlock.CLAIM_TIMEOUT_MS

    return true
end

---Overwritten getFillUnitIndexFromNode — only the currently claimed node resolves to a fill unit
-- @param function superFunc original function
-- @param entityId node exact-fill root node
-- @return integer|nil fillUnitIndex fill unit index for the given node
function ExactFillNodeBlock:getFillUnitIndexFromNode(superFunc, node)
    if not self:claimExactFillRootNode(node) then
        return nil
    end

    return superFunc(self, node)
end

---Overwritten getFillUnitFromNode — only the currently claimed node resolves to a fill unit
-- @param function superFunc original function
-- @param entityId node exact-fill root node
-- @return table|nil fillUnit fill unit for the given node
function ExactFillNodeBlock:getFillUnitFromNode(superFunc, node)
    if not self:claimExactFillRootNode(node) then
        return nil
    end

    return superFunc(self, node)
end

---Overwritten getFillUnitExtraDistanceFromNode — only the currently claimed node resolves
-- @param function superFunc original function
-- @param entityId node exact-fill root node
-- @return float extraDistance extra effect distance for the given node
function ExactFillNodeBlock:getFillUnitExtraDistanceFromNode(superFunc, node)
    if not self:claimExactFillRootNode(node) then
        return 0
    end

    return superFunc(self, node)
end
