--
-- CutterSupportFrame
--
-- @author  Manuel Leithner
-- @date  01/10/19
--
-- Copyright (C) GIANTS Software GmbH, Confidential, All Rights Reserved.

local modName = g_currentModName

local function getSpecTable(self)
    return self["spec_"..modName..".cutterSupportFrame"]
end

-- @category Specializations
CutterSupportFrame = {}


---Checks if all prerequisite specializations are loaded
-- @param table specializations specializations
-- @return boolean hasPrerequisite true if all prerequisite specializations are loaded
-- @includeCode
function CutterSupportFrame.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(AnimatedVehicle, specializations) and SpecializationUtil.hasSpecialization(AttacherJoints, specializations)
end

---
-- @includeCode
function CutterSupportFrame.registerFunctions(vehicleType)
    SpecializationUtil.registerFunction(vehicleType, "setCutterSupportFrameValue", CutterSupportFrame.setCutterSupportFrameValue)
end

---
-- @includeCode
function CutterSupportFrame.registerOverwrittenFunctions(vehicleType)
    SpecializationUtil.registerOverwrittenFunction(vehicleType, "loadAnimationPart",           CutterSupportFrame.loadAnimationPart)
    SpecializationUtil.registerOverwrittenFunction(vehicleType, "initializeAnimationPart",     CutterSupportFrame.initializeAnimationPart)
    SpecializationUtil.registerOverwrittenFunction(vehicleType, "postInitializeAnimationPart", CutterSupportFrame.postInitializeAnimationPart)
    SpecializationUtil.registerOverwrittenFunction(vehicleType, "updateAnimationPart",         CutterSupportFrame.updateAnimationPart)
    SpecializationUtil.registerOverwrittenFunction(vehicleType, "resetAnimationPartValues",    CutterSupportFrame.resetAnimationPartValues)
    SpecializationUtil.registerOverwrittenFunction(vehicleType, "getCanBeTurnedOn",            CutterSupportFrame.getCanBeTurnedOn)
end

---
-- @includeCode
function CutterSupportFrame.registerEventListeners(vehicleType)
    SpecializationUtil.registerEventListener(vehicleType, "onLoad", CutterSupportFrame)
    SpecializationUtil.registerEventListener(vehicleType, "onPreAttachImplement", CutterSupportFrame)
    SpecializationUtil.registerEventListener(vehicleType, "onTurnedOn", CutterSupportFrame)
    SpecializationUtil.registerEventListener(vehicleType, "onTurnedOff", CutterSupportFrame)
end

function CutterSupportFrame:onLoad(savegame)
    local spec = getSpecTable(self)

    spec.supportFrameValues = {}
end

function CutterSupportFrame:onPreAttachImplement(object, inputJointDescIndex, jointDescIndex)
    if object.setSupportFrameValue ~= nil then
        local spec = getSpecTable(self)
        for frameIndex, value in pairs(spec.supportFrameValues) do
            object:setSupportFrameValue(frameIndex, value)
        end
    end
end

function CutterSupportFrame:onTurnedOn()
    local spec = self.spec_attacherJoints
    for _, attacherJoint in ipairs(spec.attacherJoints) do
        if attacherJoint.jointIndex == 0 then
            attacherJoint.jointIndex = math.huge
            attacherJoint.attachDeactivationHackActive = true
        end
    end
end

function CutterSupportFrame:onTurnedOff()
    local spec = self.spec_attacherJoints
    for _, attacherJoint in ipairs(spec.attacherJoints) do
        if attacherJoint.attachDeactivationHackActive then
            attacherJoint.jointIndex = 0
            attacherJoint.attachDeactivationHackActive = nil
        end
    end
end

function CutterSupportFrame:getCanBeTurnedOn(superFunc)
    if #self:getAttachedImplements() > 0 then
        return false
    end

    return superFunc(self)
end

function CutterSupportFrame:setCutterSupportFrameValue(frameIndex, value)
    local spec = getSpecTable(self)

    spec.supportFrameValues[frameIndex] = value

    for _, implement in ipairs(self:getAttachedImplements()) do
        local object = implement.object
        if object.setSupportFrameValue ~= nil then
            object:setSupportFrameValue(frameIndex, value)
        end
    end
end

function CutterSupportFrame:loadAnimationPart(superFunc, xmlFile, partKey, part)
    if not superFunc(self, xmlFile, partKey, part) then
        return false
    end

    local cutterSupportFrameIndex = getXMLInt(xmlFile, partKey.."#cutterSupportFrameIndex")

    local cutterSupportStartValue = getXMLFloat(xmlFile, partKey.."#cutterSupportStartValue")
    local cutterSupportEndValue = getXMLFloat(xmlFile, partKey.."#cutterSupportEndValue")

    if cutterSupportFrameIndex ~= nil and cutterSupportStartValue ~= nil and cutterSupportEndValue ~= nil then
        part.cutterSupportFrameIndex = cutterSupportFrameIndex
        part.cutterSupportStartValue = cutterSupportStartValue
        part.cutterSupportEndValue = cutterSupportEndValue
    end

    return true
end

function CutterSupportFrame:initializeAnimationPart(superFunc, animation, part, i, numParts)
    superFunc(self, animation, part, i, numParts)

    -- find the next tipSideEmptyFactor part
    if part.cutterSupportEndValue ~= nil then
        for j=i+1, numParts do
            local part2 = animation.parts[j]
            if part.cutterSupportFrameIndex == part2.cutterSupportFrameIndex and part2.cutterSupportEndValue ~= nil then
                if part.startTime + part.duration > part2.startTime+0.001 then
                    g_logManager:xmlWarning(self.configFileName, "Overlapping cutter support frame value parts for support frame '%d' in animation '%s'", part.cutterSupportFrameIndex, animation.name)
                end
                part.nextCutterSupportFramePart = part2
                part2.prevCutterSupportFramePart = part
                if part2.cutterSupportStartValue == nil then
                    part2.cutterSupportStartValue = part.cutterSupportEndValue
                end
                break
            end
        end
    end
end

function CutterSupportFrame:postInitializeAnimationPart(superFunc, animation, part, i, numParts)
    superFunc(self, animation, part, i, numParts)

    if part.cutterSupportEndValue ~= nil and part.cutterSupportStartValue == nil then
        part.cutterSupportStartValue = 0
    end
end

function CutterSupportFrame:updateAnimationPart(superFunc, animation, part, durationToEnd, dtToUse, realDt)
    local hasPartChanged = superFunc(self, animation, part, durationToEnd, dtToUse, realDt)

    if part.cutterSupportStartValue ~= nil and (durationToEnd > 0 or AnimatedVehicle.getNextPartIsPlaying(part.nextCutterSupportFramePart, part.prevCutterSupportFramePart, animation, true)) then
        local destFactor = part.cutterSupportEndValue
        if animation.currentSpeed < 0 then
            destFactor = part.cutterSupportStartValue
        end
        if part.currentCutterSupportValue == nil then
            part.currentCutterSupportValue = part.cutterSupportStartValue
            if animation.currentSpeed < 0 then
                part.currentCutterSupportValue = part.cutterSupportEndValue
            end
        end

        if part.cutterSupportFrameSpeed == nil then
            local invDuration = 1.0/math.max(durationToEnd, 0.001)
            part.cutterSupportFrameSpeed = (destFactor-part.currentCutterSupportValue)*invDuration
        end

        local newValue = AnimatedVehicle.getMovedLimitedValue(part.currentCutterSupportValue, destFactor, part.cutterSupportFrameSpeed, dtToUse)
        if newValue ~= part.currentCutterSupportValue then
            part.currentCutterSupportValue = newValue

            self:setCutterSupportFrameValue(part.cutterSupportFrameIndex, newValue)

            for _, part2 in ipairs(animation.parts) do
                if part2.cutterSupportFrameIndex == part.cutterSupportFrameIndex then
                    if part2.currentCutterSupportValue ~= nil then
                        part2.currentCutterSupportValue = newValue
                    end
                end
            end

            hasPartChanged = true
        end
    end

    return hasPartChanged
end

function CutterSupportFrame:resetAnimationPartValues(superFunc, part)
    superFunc(self, part)
    part.cutterSupportFrameSpeed = nil
end