--[[
    PoweredActionEventExtension

    Changes the addPoweredActionEvent function to check if pto and connection hoses are conected before allowing the action event to be executed.

	@author: 		BayernGamers
	@date: 			01.06.2025
	@version:		1.0

	History:		v1.0 @01.06.2025 - initial implementation in FS25
                    ------------------------------------------------------------------------------------------------------

	
	License:        Terms:
                        Usage:
                            Feel free to use this work as-is as long as you adhere to the following terms:
						Attribution:
							You must give appropriate credit to the original author when using this work.
						No Derivatives:
							You may not alter, transform, or build upon this work in any way.
						Usage:
							The work may be used for personal and commercial purposes, provided it is not modified or adapted.
						Additional Clause:
							This script may not be converted, adapted, or incorporated into any other game versions or platforms except by GIANTS Software.
]]
source(Utils.getFilename("scripts/utils/Logger.lua", g_currentModDirectory))
source(Utils.getFilename("scripts/utils/ConnectionHoseUtil.lua", g_currentModDirectory))
source(Utils.getFilename("scripts/utils/PowerTakeOffUtil.lua", g_currentModDirectory))

local log = Logger.new(true, Logger.DEBUG_LEVELS.HIGH, "PoweredActionEventExtension.lua")

PoweredActionEventExtension = {}
PoweredActionEventExtension.MOD_DIRECTORY = g_currentModDirectory
PoweredActionEventExtension.MOD_NAME = g_currentModName

function PoweredActionEventExtension.getIsConnected(actionVehicle, inputBinding, inputValue)

    if inputValue ~= 0 then
        if SpecializationUtil.hasSpecialization(Attachable, actionVehicle.specializations) then

            if inputBinding == InputAction.LOWER_IMPLEMENT or inputBinding == InputAction.LOWER_ALL_IMPLEMENTS then
                if SpecializationUtil.hasSpecialization(Cutter, actionVehicle.specializations) and not SpecializationUtil.hasSpecialization(Combine, actionVehicle.specializations) then
                    log:printDevInfo("Implement is a cutter, allowing lower action without checking PTO or hoses", Logger.DEBUG_LEVELS.HIGH)
                    return true, nil
                end

                if (actionVehicle.spec_pickup == nil or (actionVehicle.spec_pickup ~= nil and actionVehicle.spec_pickup.animationName == "")) and actionVehicle.spec_attachable.lowerAnimation == nil and (actionVehicle.spec_foldable ~= nil and actionVehicle.spec_foldable.foldMiddleAnimTime == nil) and actionVehicle.spec_attachable.inputAttacherJoints ~= nil then
                    for _, inputAttacherJoint in pairs(actionVehicle.spec_attachable.inputAttacherJoints) do
                        if not inputAttacherJoint.useFoldingLoweredState then
                            log:printDevInfo("Implement does not have folding lowered state, allowing lower action without checking PTO or hoses", Logger.DEBUG_LEVELS.HIGH)
                            return true, nil
                        end
                    end
                end
            end

            local hasPTO = false
            local attacherVehicle = actionVehicle:getAttacherVehicle()
            local inputAttacherJointIndex = nil
            local jointDescIndex = nil
            local implementIndex = nil
            
            if attacherVehicle ~= nil then
                implementIndex = attacherVehicle:getImplementIndexByObject(actionVehicle)
                jointDescIndex = attacherVehicle:getAttacherJointIndexFromImplementIndex(implementIndex)
                inputAttacherJointIndex = actionVehicle:getActiveInputAttacherJointDescIndex()

                hasPTO = PowerTakeOffUtil.getHasInputPTO(actionVehicle, inputAttacherJointIndex) and PowerTakeOffUtil.getHasOutputPTO(attacherVehicle, jointDescIndex)
            end
            --local hasConnectionHoses = false
            local hasSkipNodes = false

            --[[
            if SpecializationUtil.hasSpecialization(PowerTakeOffs, actionVehicle.specializations) then
                local spec_powerTakeOffs = actionVehicle.spec_powerTakeOffs

                hasPTO = #spec_powerTakeOffs.inputPowerTakeOffs > 0

                if actionVehicle.getAttacherVehicle ~= nil then
                    local attacherVehicle = actionVehicle:getAttacherVehicle()

                    if attacherVehicle ~= nil and attacherVehicle.spec_powerTakeOffs ~= nil then
                        hasPTO = hasPTO and #attacherVehicle.spec_powerTakeOffs.outputPowerTakeOffs > 0
                    end
                end
            end
            ]]

            if SpecializationUtil.hasSpecialization(ConnectionHoses, actionVehicle.specializations) then
                local spec_connectionHoses = actionVehicle.spec_connectionHoses

                --hasConnectionHoses = #spec_connectionHoses.toolConnectorHoses > 0 or #spec_connectionHoses.hoseNodes > 0 or #spec_connectionHoses.customHoseTargets > 0 or #spec_connectionHoses.customHoses > 0 or #spec_connectionHoses.hoseSkipNodes > 0
                hasSkipNodes = #spec_connectionHoses.hoseSkipNodes > 0
            end

            --local hasConnectionHoses = ConnectionHoseUtil.getHasInputConnectionHoses(actionVehicle, inputAttacherJointIndex)
            --local hasConnectionHoses = ConnectionHoseUtil.getHasHydraulicInputConnectionHoses(actionVehicle, inputAttacherJointIndex) and ConnectionHoseUtil.getHasAttacherVehicleHydraulicOutputHoses(actionVehicle)
            local hasConnectionHoses = (ConnectionHoseUtil.getHasHydraulicInputConnectionHoses(actionVehicle, inputAttacherJointIndex) and ConnectionHoseUtil.getHasAttacherVehicleHydraulicOutputHoses(actionVehicle)) or 
                ConnectionHoseUtil.getHasCompatibleCustomHoseTypes(actionVehicle, inputAttacherJointIndex)

            if hasConnectionHoses then
                if attacherVehicle ~= nil then
                    local jointDescIndex = attacherVehicle:getAttacherJointIndexFromImplementIndex(implementIndex)

                    if jointDescIndex ~= nil and attacherVehicle.spec_attachConnectionHosesManually ~= nil and attacherVehicle.spec_attachConnectionHosesManually.attachedHoses ~= nil then
                        local isSkipNodeConnected = AttachConnectionHosesManually.getHasSkipNodeConnection(actionVehicle)

                        if attacherVehicle.spec_attachConnectionHosesManually.attachedHoses[jointDescIndex] == nil and not isSkipNodeConnected then
                            log:printDevInfo("Hoses not attached, cannot execute action", Logger.DEBUG_LEVELS.HIGH)
                            return false, g_i18n:getText("warning_attachHosesFirst")
                        end
                    end
                end
                -- Check if we may need an "else return false" here
            end

            if hasPTO then
                if attacherVehicle ~= nil then
                    local jointDescIndex = attacherVehicle:getAttacherJointIndexFromImplementIndex(implementIndex)

                    if jointDescIndex ~= nil and attacherVehicle.spec_attachPowerTakeOffsManually ~= nil and attacherVehicle.spec_attachPowerTakeOffsManually.attachedPTOs ~= nil then
                        if attacherVehicle.spec_attachPowerTakeOffsManually.attachedPTOs[jointDescIndex] == nil then
                            log:printDevInfo("PTO not attached, cannot execute action", Logger.DEBUG_LEVELS.HIGH)
                            return false, g_i18n:getText("warning_attachPTOFirst")
                        end
                    end
                end
                -- Check if we may need an "else return false" here
            end
        end
    end

    return true, nil
end

function PoweredActionEventExtension.addPoweredActionEvent(vehicle, superFunc, actionName, inputBinding, callback, originalCallback, triggerUp, triggerDown, triggerAlways, startActive, callbackState, customIconName, ignoreCollisions, reportAnyDeviceCollision)
	return vehicle:addActionEvent(actionName, inputBinding, callback, function(actionVehicle, actionName, inputValue, callbackState, isAnalog, isMouse, deviceCategory, binding)
		-- upvalues: (copy) originalCallback
		local isPowered, warningText = actionVehicle:getIsPowered()
        local isConnected, connectionWarningText = PoweredActionEventExtension.getIsConnected(actionVehicle, inputBinding, inputValue)
		if isPowered and isConnected then
			originalCallback(actionVehicle, actionName, inputValue, callbackState, isAnalog, isMouse, deviceCategory, binding)
		elseif inputValue ~= 0 and warningText ~= nil then
			g_currentMission:showBlinkingWarning(warningText, 2000)
        elseif inputValue ~= nil and connectionWarningText ~= nil then
            g_currentMission:showBlinkingWarning(connectionWarningText, 2000)
        end
	end, triggerUp, triggerDown, triggerAlways, startActive, callbackState, customIconName, ignoreCollisions, reportAnyDeviceCollision)
end

Vehicle.addPoweredActionEvent = Utils.overwrittenFunction(Vehicle.addPoweredActionEvent, PoweredActionEventExtension.addPoweredActionEvent)