---
-- ToolMirrors
--
-- @author      nilBrain
-- @date        2025-11-15
--
-- Copyright (C) nilBrain | Philipp Jaeger, Confidential, All Rights Reserved.

ToolMirrors = {}

local modName = g_currentModName

ToolMirrors.SPEC_NAME = modName .. ".toolMirrors"
ToolMirrors.SPEC_TABLE_NAME = "spec_" .. modName .. ".toolMirrors"

ToolMirrors.DEFAULT_PRIO = 2
ToolMirrors.MIRROR_OBJECT_MASK = 16711807 -- 0x00FF007F: visible everywhere except other mirrors

---Called while initializing the specialization
function ToolMirrors.initSpecialization()
    local schema = Vehicle.xmlSchema

    schema:register(XMLValueType.NODE_INDEX, "vehicle.toolMirrors.mirror(?)#node", "Mirror node")
    schema:register(XMLValueType.INT, "vehicle.toolMirrors.mirror(?)#prio", "Priority", ToolMirrors.DEFAULT_PRIO)
end

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

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

---Called on load
-- @param table savegame savegame
function ToolMirrors:onLoad(savegame)
    local spec = self[ToolMirrors.SPEC_TABLE_NAME]
    spec.mirrors = {}

    for _, key in self.xmlFile:iterator("vehicle.toolMirrors.mirror") do
        local node = self.xmlFile:getNode(key .. "#node", nil, self.components, self.i3dMappings)
        if node ~= nil then
            local parent = getParent(node)

            -- skip mirrors whose parent is already configured (visible) — they are handled elsewhere
            if parent ~= nil and parent ~= 0 and getEffectiveVisibility(parent) then
                continue
            end

            local prio = self.xmlFile:getInt(key .. "#prio", ToolMirrors.DEFAULT_PRIO)

            local shapesObjectMask = bit32.bor(ObjectMask.SHAPE_VIS_MIRROR, ObjectMask.SHAPE_VIS_MIRROR_ONLY)
            setReflectionMapObjectMasks(node, shapesObjectMask, ObjectMask.LIGHT_VIS_MIRROR, true)

            if getObjectMask(node) == 0 then
                setObjectMask(node, ToolMirrors.MIRROR_OBJECT_MASK)
            end

            setVisibility(node, false)

            table.insert(spec.mirrors, {node=node, prio=prio, cosAngle=1, parentNode=parent})
        end
    end
end

---Called when the vehicle gets attached
-- @param Vehicle attacherVehicle attacher vehicle
-- @param integer inputJointDescIndex index of input attacher joint
-- @param integer jointDescIndex index of attacher joint it gets attached to
-- @param boolean loadFromSavegame attachment is loaded from savegame
function ToolMirrors:onPostAttach(attacherVehicle, inputJointDescIndex, jointDescIndex, loadFromSavegame)
    local spec = self[ToolMirrors.SPEC_TABLE_NAME]
    local rootVehicle = attacherVehicle:getRootVehicle()

    if rootVehicle.spec_enterable == nil or rootVehicle.spec_enterable.mirrors == nil then
        return
    end

    local enterableMirrors = rootVehicle.spec_enterable.mirrors
    for _, mirror in ipairs(spec.mirrors) do
        table.insert(enterableMirrors, mirror)
    end
end

---Called when the vehicle gets detached
-- @param Vehicle attacherVehicle attacher vehicle
-- @param Vehicle implement implement vehicle
function ToolMirrors:onPreDetach(attacherVehicle, implement)
    local spec = self[ToolMirrors.SPEC_TABLE_NAME]
    local rootVehicle = attacherVehicle:getRootVehicle()

    if rootVehicle.spec_enterable == nil or rootVehicle.spec_enterable.mirrors == nil then
        return
    end

    local enterableMirrors = rootVehicle.spec_enterable.mirrors
    for _, mirror in ipairs(spec.mirrors) do
        table.removeElement(enterableMirrors, mirror)
    end
end
