TrailerHookControl = {}

function TrailerHookControl.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(AttacherJoints, specializations)
end

function TrailerHookControl.registerEventListeners(vehicleType)
    SpecializationUtil.registerEventListener(vehicleType, "onLoad", TrailerHookControl)
    SpecializationUtil.registerEventListener(vehicleType, "onUpdateTick", TrailerHookControl)
    SpecializationUtil.registerEventListener(vehicleType, "onPostAttachImplement", TrailerHookControl)
    SpecializationUtil.registerEventListener(vehicleType, "onPostDetachImplement", TrailerHookControl)
end

function TrailerHookControl:getHasAttachedObject(attacherSpec)
    if attacherSpec ~= nil and attacherSpec.attachedImplements ~= nil then
        for _, attachedImplement in pairs(attacherSpec.attachedImplements) do
            if attachedImplement ~= nil then
                return true
            end
        end
    end

    if self.getAttachedImplements ~= nil then
        local attachedImplements = self:getAttachedImplements() or {}
        if next(attachedImplements) ~= nil then
            return true
        end
    end

    if attacherSpec == nil or attacherSpec.attacherJoints == nil then
        return false
    end

    for _, attacherJoint in ipairs(attacherSpec.attacherJoints) do
        if attacherJoint ~= nil then
            if attacherJoint.jointIndex ~= nil and attacherJoint.jointIndex ~= 0 then
                return true
            end

            if attacherJoint.object ~= nil
                or attacherJoint.implement ~= nil
                or attacherJoint.attachedVehicle ~= nil
                or attacherJoint.attacherVehicle ~= nil
                or attacherJoint.connectingVehicle ~= nil
                or attacherJoint.rootVehicle ~= nil
                or attacherJoint.isUsed == true then
                return true
            end
        end
    end

    return false
end

function TrailerHookControl:onLoad(savegame)
    local spec = {}
    self.spec_trailerHookControl = spec

    spec.circleNode = self.xmlFile:getValue("vehicle.trailerHookControl#circleNode", nil, self.components, self.i3dMappings)
    spec.isTrailerAttached = false

    spec.closedRotation = {math.rad(-90), 0, 0}
    spec.openRotation = {math.rad(-90), 0, math.rad(-50)}
    spec.attachedRotation = {math.rad(-90), 0, math.rad(-12)}
end

function TrailerHookControl:onPostAttachImplement(attachable, inputJointDescIndex, jointDescIndex)
    local spec = self.spec_trailerHookControl
    if spec ~= nil then
        spec.isTrailerAttached = true
    end
end

function TrailerHookControl:onPostDetachImplement(implementIndex)
    local spec = self.spec_trailerHookControl
    if spec ~= nil then
        spec.isTrailerAttached = TrailerHookControl.getHasAttachedObject(self, self.spec_attacherJoints)
    end
end

function TrailerHookControl:onUpdateTick(dt, isActiveForInput, isActiveForInputIgnoreSelection, isSelected)
    local spec = self.spec_trailerHookControl
    local attacherSpec = self.spec_attacherJoints

    if spec == nil or spec.circleNode == nil or attacherSpec == nil or attacherSpec.attacherJoints == nil then
        return
    end

    local hasAttachedImplement = spec.isTrailerAttached or TrailerHookControl.getHasAttachedObject(self, attacherSpec)
    spec.isTrailerAttached = hasAttachedImplement

    local hookOpen = false
    if self.getAnimationTime ~= nil then
        hookOpen = (self:getAnimationTime("Attache") or 0) > 0.99
    end

    if hasAttachedImplement then
        setRotation(spec.circleNode, spec.attachedRotation[1], spec.attachedRotation[2], spec.attachedRotation[3])
    elseif hookOpen then
        setRotation(spec.circleNode, spec.openRotation[1], spec.openRotation[2], spec.openRotation[3])
    else
        setRotation(spec.circleNode, spec.closedRotation[1], spec.closedRotation[2], spec.closedRotation[3])
    end

    local shouldBlock = not hookOpen and not hasAttachedImplement
    for _, attacherJoint in ipairs(attacherSpec.attacherJoints) do
        if attacherJoint ~= nil then
            attacherJoint.isBlocked = shouldBlock
        end
    end
end
