--
--	Dynamically Loaded Moving PowerTakeOff
--
--	@author: 	 Wopster - VertexDezign.net
--	@descripion: A Power Take Off that acts like a movingPart inserted as the default ptoInput for the attacherJoint
--	@website:	 http://vertexdezign.net
--	@history:	 v1.0 - 2016-01-15 - Initial implementation
--

-- Environment
Env = {
	DEBUG = false,
	MOD_DIR = g_currentModDirectory
}

dynamicallyLoadedMovingPto = {}

function dynamicallyLoadedMovingPto.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(Cylindered, specializations) and SpecializationUtil.hasSpecialization(Attachable, specializations)
end

function dynamicallyLoadedMovingPto:load(xmlFile)
	self.loadMovingPto = dynamicallyLoadedMovingPto.loadMovingPto
	self.vibrateMovingPto = dynamicallyLoadedMovingPto.vibrateMovingPto
	self.overrideVehicleAttachImplement = dynamicallyLoadedMovingPto.overrideVehicleAttachImplement
	self.overrideVehicleDetachImplement = dynamicallyLoadedMovingPto.overrideVehicleDetachImplement

	self.movingPtoInput = {}

	local i = 0
	while true do
		local key = string.format("vehicle.inputAttacherJoints.inputAttacherJoint(%d)", i)

		if not hasXMLProperty(xmlFile, key) then
			break
		end
		
		if hasXMLProperty(xmlFile, key .. "#movingPtoIndex") then
			local linkNode = Utils.indexToObject(self.components, getXMLString(xmlFile, key .. "#movingPtoIndex"))
			
			if linkNode ~= nil then
				self:loadMovingPto(xmlFile, key, self.inputAttacherJoints[i + 1], linkNode)
			end
		end

		i = i + 1
    end
end

function dynamicallyLoadedMovingPto:loadMovingPto(xmlFile, key, inputAttacherJoint, linkNode)
	local filename = getXMLString(xmlFile, key .. "#movingPtoFilename")
	
	if filename ~= nil then
		local i3dNode = Utils.loadSharedI3DFile(filename, self.baseDirectory, false, false, false)

		if i3dNode ~= 0 then
            local dummyRoot = getChildAt(i3dNode, 0)
            
			if dummyRoot ~= nil then
				local rootNode = dummyRoot
				local startNode = getXMLFloat(xmlFile, key .. "#movingPtoFilenameNode")
				
				if startNode ~= nil then
					rootNode = getChildAt(dummyRoot, startNode)
				end

				link(linkNode, rootNode)
				delete(i3dNode)
				setTranslation(rootNode, 0, 0, 0)

				local mainNode = getChildAt(rootNode, 0)
				local attachRootNode = getChildAt(rootNode, 1)
				local dirAndScaleNode = getChildAt(rootNode, 2)
				local movingNode = getChildAt(mainNode, 0)
				local attachNode = getChildAt(movingNode, 0)
				local attachRefNode = getChildAt(attachNode, 0)
				local _, _, baseDistance = getTranslation(attachRefNode)
				
				unlink(attachNode)

				local ax, ay, az = getTranslation(attachRefNode)
				setTranslation(attachNode, -ax, -ay, -az)

				local movingPtoRotSpeed = getXMLFloat(xmlFile, key .. "#movingPtoRotSpeed")
				
				if movingPtoRotSpeed == nil then
					-- Default rotSpeed
					movingPtoRotSpeed = 1100
				end
				
				self.movingPtoInput = {
					node = attachRootNode,
					rootNode = rootNode,
					mainNode = mainNode,
					dirAndScaleNode = dirAndScaleNode,
					movingNode = movingNode,
					attachNode = attachNode,
					baseDistance = baseDistance,
					rotationNodes = {
						isRunning = false,
						nodes = {
							[1] = {
								shaderComponentScale = {},
								currentRot = 0,
								isActive = true,
								node = attachRootNode,
								rotSpeed = math.abs(math.rad(movingPtoRotSpeed)),
								rotAxis = 3,
								turnOnFadeTime = 2000,
								turnOffFadeTime = 5000,
								turnOnOffCurValue = 0,
							},
							[2] = {
								shaderComponentScale = {},
								currentRot = 0,
								isActive = true,
								node = attachRefNode,
								rotSpeed = math.abs(math.rad(movingPtoRotSpeed)),
								rotAxis = 3,
								turnOnFadeTime = 2000,
								turnOffFadeTime = 5000,
								turnOnOffCurValue = 0,
							}
						}						
					}
				}

				local parkNode = Utils.indexToObject(self.components, getXMLString(xmlFile, key .. "#movingPtoParkIndex"))

				if parkNode ~= nil then
					self.movingPtoInput.parkNode = parkNode
				else
					print("dynamicallyLoadedMovingPto - Error: Park index not defined!")
				end

				if self.movingPtoInput.parkNode ~= nil then
					link(self.movingPtoInput.parkNode, self.movingPtoInput.attachNode)
				end
				
				setRotation(self.movingPtoInput.attachNode, math.rad(40), 0, 0)

				inputAttacherJoint.ptoInput = {
					node = self.movingPtoInput.node,
					rotSpeed = 0,
					rootNode = self.movingPtoInput.rootNode,
					dirAndScaleNode = self.movingPtoInput.dirAndScaleNode,
					attachNode = self.movingPtoInput.attachNode,
					baseDistance = self.movingPtoInput.baseDistance
				}

				local entry = {
					node = self.movingPtoInput.mainNode,
					referencePoint = self.movingPtoInput.attachNode,
					referenceFrame = self.movingPtoInput.attachNode,
					invertZ = false,
					scaleZ = false,
					limitedAxis = nil,
					playSound = false,
					moveToReferenceFrame = false,
					doDirectionAlignment = true,
					alignToWorldY  = false,
					useLocalOffset = false,
					localReferenceDistance = nil,
					movingPto = true,
					translatingParts = {},
					dependentParts = {},
					dependentPartNodes = {}
				}

				local x, y, z = worldToLocal(entry.node, getWorldTranslation(entry.referencePoint))

				entry.referenceDistance = 0
				entry.localReferencePoint = {x, y, z}

				local x, y, z = getTranslation(self.movingPtoInput.movingNode)

				local transEntry = {
					node = self.movingPtoInput.movingNode,
					startPos = {x, y, z},
					referenceDistance = 0,
					referenceDistancePoint = nil
				}

				table.insert(entry.translatingParts, transEntry)
				table.insert(self.movingParts, entry)
				table.insert(self.activeDirtyMovingParts, entry)
			end
		end
	end
end

function dynamicallyLoadedMovingPto:delete()
end

function dynamicallyLoadedMovingPto:mouseEvent(posX, posY, isDown, isUp, button)
end

function dynamicallyLoadedMovingPto:keyEvent(unicode, sym, modifier, isDown)
end

function dynamicallyLoadedMovingPto:update(dt)
	if self.movingPtoInput ~= nil then
		if self.movingPtoInput.rotationNodes ~= nil then
			if self.isClient then
				Utils.updateRotationNodes(self, self.movingPtoInput.rotationNodes, dt, self:getIsActive() and self:getIsTurnedOn())
			end
		end

		if self.movingPtoInput.mainNode ~= nil then
			self:vibrateMovingPto(self.movingPtoInput.mainNode, dt, self:getIsTurnedOn())
		end
	end
end

function dynamicallyLoadedMovingPto:draw()
end

function dynamicallyLoadedMovingPto:vibrateMovingPto(node, dt, isTurnedOn)
	if isTurnedOn then
		local offset = 0.0005
		local x, y, z = getTranslation(node)
		local trans = {0, 0, z}
		
		if x < offset and y < offset then
			trans = {x + (offset * 2), y + (offset * 2), z}
		else
			trans = {x - (offset * 2), y - (offset * 2), z}
		end
		
		setTranslation(node, unpack(trans))
	end
end

if not Utils.dynamicallyLoadedMovingPtoFixApplied then
	Utils.dynamicallyLoadedMovingPtoFixApplied = true
	
	local oldVehicleAttachFunc = Vehicle.attachImplement
	Vehicle.attachImplement = function(self, object, inputJointDescIndex, jointDescIndex, noEventSend, index, startLowered)
		local jointDesc = self.attacherJoints[jointDescIndex]
		object:onPreAttach(self, inputJointDescIndex)

		local upperAlpha, lowerAlpha = self:calculateAttacherJointMoveUpperLowerAlpha(jointDesc, object)

		if startLowered == nil then
			startLowered = true

			if object.attacherJoint.allowsLowering and jointDesc.allowsLowering then
				local ax,ay,az = getWorldTranslation(object.attacherJoint.node)

				-- test which position to use
				if jointDesc.rotationNode ~= nil then
					setRotation(jointDesc.rotationNode, Utils.vector3ArrayLerp(jointDesc.minRot, jointDesc.maxRot, upperAlpha))
				end

				if jointDesc.rotationNode2 ~= nil then
					setRotation(jointDesc.rotationNode2, Utils.vector3ArrayLerp(jointDesc.minRot2, jointDesc.maxRot2, upperAlpha))
				end

				local x,y,z = getWorldTranslation(jointDesc.jointTransform)
				local distanceSqUpper = Utils.vector3LengthSq(x-ax, y-ay, z-az)

				if jointDesc.rotationNode ~= nil then
					setRotation(jointDesc.rotationNode, Utils.vector3ArrayLerp(jointDesc.minRot, jointDesc.maxRot, lowerAlpha))
				end

				if jointDesc.rotationNode2 ~= nil then
					setRotation(jointDesc.rotationNode2, Utils.vector3ArrayLerp(jointDesc.minRot2, jointDesc.maxRot2, lowerAlpha))
				end

				local x,y,z = getWorldTranslation(jointDesc.jointTransform)
				local distanceSqLower = Utils.vector3LengthSq(x-ax, y-ay, z-az)

				if distanceSqUpper < distanceSqLower * 1.1 then -- Use the position which has the smaller distance (use a slight preference for min rot)
					startLowered = false
				end
			else
				if not object.attacherJoint.isDefaultLowered then
					startLowered = false
				end
			end
		end

		if noEventSend == nil or noEventSend == false then
			if g_server ~= nil then
				g_server:broadcastEvent(VehicleAttachEvent:new(self, object, inputJointDescIndex, jointDescIndex, startLowered), nil, nil, self)
			else
				g_client:getServerConnection():sendEvent(VehicleAttachEvent:new(self, object, inputJointDescIndex, jointDescIndex, startLowered))
			end
		end

		if jointDesc.transNode ~= nil and object.attacherJoint.attacherHeight ~= nil then
			-- limit attacher height
			local yTarget = Utils.clamp(object.attacherJoint.attacherHeight, jointDesc.transMinYHeight, jointDesc.transMaxYHeight)
			-- get current joint position relative to rootnode
			local _,yRoot,_ = worldToLocal(self.rootNode, getWorldTranslation(jointDesc.jointTransform))
			-- get joint - transnode offset
			local _,yOffset,_         = worldToLocal(jointDesc.transNode, getWorldTranslation(jointDesc.jointTransform))
			-- get new transNode y position
			local _,yTrans,_ = worldToLocal(getParent(jointDesc.transNode),  localToWorld(self.rootNode, 0, yRoot - ((yRoot - yTarget) + yOffset), 0))
			local x,_,z = getTranslation(jointDesc.transNode)

			setTranslation(jointDesc.transNode, x, yTrans, z)
		end

		if object.attacherJoint.topReferenceNode ~= nil then
			if jointDesc.topArm ~= nil and jointDesc.topArm.toggleVisibility then
				setVisibility(jointDesc.topArm.rotationNode, true)
			end
		end

		local implement = {}
		implement.object = object
		implement.object:onAttach(self, jointDescIndex)
		implement.jointDescIndex = jointDescIndex

		jointDesc.upperAlpha = upperAlpha
		jointDesc.lowerAlpha = lowerAlpha
		jointDesc.moveAlpha = upperAlpha

		if startLowered then
			jointDesc.moveAlpha = lowerAlpha
		end

		if jointDesc.rotationNode ~= nil then
			setRotation(jointDesc.rotationNode, Utils.vector3ArrayLerp(jointDesc.minRot, jointDesc.maxRot, jointDesc.moveAlpha))
		end

		if jointDesc.rotationNode2 ~= nil then
			setRotation(jointDesc.rotationNode2, Utils.vector3ArrayLerp(jointDesc.minRot2, jointDesc.maxRot2, jointDesc.moveAlpha))
		end

		self:updateAttacherJointRotation(jointDesc, object)

		if self.isServer then
			local xNew = jointDesc.jointOrigTrans[1] + jointDesc.jointPositionOffset[1]
			local yNew = jointDesc.jointOrigTrans[2] + jointDesc.jointPositionOffset[2]
			local zNew = jointDesc.jointOrigTrans[3] + jointDesc.jointPositionOffset[3]

			-- transform offset position to world coord and to jointTransform coord to get position offset dependend on angle and position
			local x,y,z = localToWorld(getParent(jointDesc.jointTransform), xNew, yNew, zNew)
			local x1,y1,z1 = worldToLocal(jointDesc.jointTransform, x,y,z)

			-- move jointTransform to offset pos
			setTranslation(jointDesc.jointTransform, xNew, yNew, zNew)

			-- transform it to implement position and angle
			x,y,z = localToWorld(implement.object.attacherJoint.node,x1,y1,z1)
			local x2,y2,z2 = worldToLocal(getParent(implement.object.attacherJoint.node), x,y,z)
			setTranslation(implement.object.attacherJoint.node, x2,y2, z2)

			local constr = JointConstructor:new()
			constr:setActors(jointDesc.rootNode, implement.object.attacherJoint.rootNode)
			constr:setJointTransforms(jointDesc.jointTransform, implement.object.attacherJoint.node)
			--constr:setBreakable(20, 10)

			implement.jointRotLimit = {}
			implement.jointTransLimit = {}
			implement.maxRotLimit = {}
			implement.maxTransLimit = {}
			implement.minRotLimit = {}
			implement.minTransLimit = {}

			for i=1, 3 do
				local maxRotLimit = jointDesc.maxRotLimit[i]*implement.object.attacherJoint.rotLimitScale[i]
				local minRotLimit = jointDesc.minRotLimit[i]*implement.object.attacherJoint.rotLimitScale[i]

				if implement.object.attacherJoint.fixedRotation then
					maxRotLimit = 0
					minRotLimit = 0
				end

				local maxTransLimit = jointDesc.maxTransLimit[i]*implement.object.attacherJoint.transLimitScale[i]
				local minTransLimit = jointDesc.minTransLimit[i]*implement.object.attacherJoint.transLimitScale[i]

				implement.maxRotLimit[i] = maxRotLimit
				implement.minRotLimit[i] = minRotLimit
				implement.maxTransLimit[i] = maxTransLimit
				implement.minTransLimit[i] = minTransLimit

				local rotLimit = maxRotLimit
				local transLimit = maxTransLimit

				if jointDesc.allowsLowering and jointDesc.allowsJointLimitMovement then
					if implement.object.attacherJoint.allowsJointRotLimitMovement then
						rotLimit = Utils.lerp(minRotLimit, maxRotLimit, jointDesc.moveAlpha)
					end
					if implement.object.attacherJoint.allowsJointTransLimitMovement then
						transLimit = Utils.lerp(minTransLimit, maxTransLimit, jointDesc.moveAlpha)
					end
				end

				constr:setRotationLimit(i-1, -rotLimit, rotLimit)
				implement.jointRotLimit[i] = rotLimit

				constr:setTranslationLimit(i-1, true, -transLimit, transLimit)
				implement.jointTransLimit[i] = transLimit
			end

			if jointDesc.enableCollision then
				constr:setEnableCollision(true)
			end

			local springX = math.max(jointDesc.rotLimitSpring[1], implement.object.attacherJoint.rotLimitSpring[1])
			local springY = math.max(jointDesc.rotLimitSpring[2], implement.object.attacherJoint.rotLimitSpring[2])
			local springZ = math.max(jointDesc.rotLimitSpring[3], implement.object.attacherJoint.rotLimitSpring[3])
			local dampingX = math.max(jointDesc.rotLimitDamping[1], implement.object.attacherJoint.rotLimitDamping[1])
			local dampingY = math.max(jointDesc.rotLimitDamping[2], implement.object.attacherJoint.rotLimitDamping[2])
			local dampingZ = math.max(jointDesc.rotLimitDamping[3], implement.object.attacherJoint.rotLimitDamping[3])
			constr:setRotationLimitSpring(springX, dampingX, springY, dampingY, springZ, dampingZ)

			local transSpringX = math.max(jointDesc.transLimitSpring[1], implement.object.attacherJoint.transLimitSpring[1])
			local transSpringY = math.max(jointDesc.transLimitSpring[2], implement.object.attacherJoint.transLimitSpring[2])
			local transSpringZ = math.max(jointDesc.transLimitSpring[3], implement.object.attacherJoint.transLimitSpring[3])
			local transDampingX = math.max(jointDesc.transLimitDamping[1], implement.object.attacherJoint.transLimitDamping[1])
			local transDampingY = math.max(jointDesc.transLimitDamping[2], implement.object.attacherJoint.transLimitDamping[2])
			local transDampingZ = math.max(jointDesc.transLimitDamping[3], implement.object.attacherJoint.transLimitDamping[3])
			constr:setTranslationLimitSpring(transSpringX, transDampingX, transSpringY, transDampingY, transSpringZ, transDampingZ)

			jointDesc.jointIndex = constr:finalize()

			-- restore implement attacher joint position (to ensure correct bottom arm alignment)
			setTranslation(implement.object.attacherJoint.node, unpack(object.attacherJoint.jointOrigTrans))
		else
			jointDesc.jointIndex = -1
		end

		jointDesc.moveDown = implement.object.attacherJoint.isDefaultLowered
		object:onSetLowered(jointDesc.moveDown)

		if object.ptoInput ~= nil and jointDesc.ptoOutput ~= nil then
			jointDesc.ptoActive = true

			if object.ptoInput.rootNode ~= nil then
				if object.movingPtoInput ~= nil then
					if object.movingPtoInput.attachNode ~= nil then
						link(jointDesc.ptoOutput.node, object.movingPtoInput.attachNode)
						setTranslation(object.movingPtoInput.attachNode, 0, 0, 0)
						setRotation(object.movingPtoInput.attachNode, math.rad(180), 0, 0)
					end
				else
					link(jointDesc.ptoOutput.node, object.ptoInput.rootNode)
					link(object.ptoInput.node, object.ptoInput.attachNode)

					if object.addWashableNode ~= nil then
						object:addWashableNode(object.ptoInput.rootNode)
						object:addWashableNode(object.ptoInput.attachNode)
						object:addWashableNode(object.ptoInput.dirAndScaleNode)
						object:setDirtAmount(object:getDirtAmount(), force)
					end
				end
			else
				link(jointDesc.ptoOutput.node, jointDesc.ptoOutput.rootNode)
				link(object.ptoInput.node, jointDesc.ptoOutput.attachNode)

				if object.addWashableNode ~= nil then
					object:addWashableNode(jointDesc.ptoOutput.rootNode)
					object:addWashableNode(jointDesc.ptoOutput.attachNode)
					object:addWashableNode(jointDesc.ptoOutput.dirAndScaleNode)
					object:setDirtAmount(object:getDirtAmount(), force)
				end
			end

			self:updatePowerTakeoff(implement, 0)
		end

		if index == nil then
			table.insert(self.attachedImplements, implement)
			index = table.getn(self.attachedImplements)
		else
			-- make the table at least as big as the number of implements
			local numAdd = index-table.getn(self.attachedImplements)

			for i=1, numAdd do
				table.insert(self.attachedImplements, {})
			end

			self.attachedImplements[index] = implement
		end

		self:updateAttacherJointGraphics(implement, 0)

		for _,v in pairs(self.specializations) do
			if v.attachImplement ~= nil then
				v.attachImplement(self, implement)
			end
		end

		implement.object:onAttached(self, jointDescIndex)

		if self.isClient then
			implement.object:setSelectedImplement(nil)

			if implement.object:getIsSelectable() and implement.object.forceSelection then
				-- find the root element
				local rootAttacherVehicle = self:getRootAttacherVehicle()
				-- select the new element as selected
				rootAttacherVehicle:setSelectedImplement(implement)
			end
		end
	end
		
	local oldVehicleDetachFunc = Vehicle.detachImplement
	Vehicle.detachImplement = function(self, implementIndex, noEventSend)
		if noEventSend == nil or noEventSend == false then
			if g_server ~= nil then
				g_server:broadcastEvent(VehicleDetachEvent:new(self, self.attachedImplements[implementIndex].object), nil, nil, self)
			else
				-- Send detach request to server and return
				local implement = self.attachedImplements[implementIndex]

				if implement.object ~= nil then
					g_client:getServerConnection():sendEvent(VehicleDetachEvent:new(self, implement.object))
				end

				return
			end
		end

		for k,v in pairs(self.specializations) do
			if v.detachImplement ~= nil then
				v.detachImplement(self, implementIndex)
			end
		end

		local implement = self.attachedImplements[implementIndex]
		local jointDesc

		if implement.object ~= nil then
			jointDesc = self.attacherJoints[implement.jointDescIndex]

			if jointDesc.transNode ~= nil then
				setTranslation(jointDesc.transNode, unpack(jointDesc.transNodeOrgTrans))
			end

			if self.isServer then
				removeJoint(jointDesc.jointIndex)
			end

			jointDesc.jointIndex = 0
		end

		local rootAttacherVehicle = self:getRootAttacherVehicle()
		local selectNewImplement = false

		if self.isClient then
			if rootAttacherVehicle.selectedImplement == implement then
				selectNewImplement = true
				rootAttacherVehicle:setSelectedImplement(nil)
			end
		end

		if implement.object ~= nil then
			local object = implement.object

			implement.object:onDetach(self, jointDescIndex)
			implement.object = nil

			if self.isClient then
				if jointDesc.topArm ~= nil then
					setRotation(jointDesc.topArm.rotationNode, jointDesc.topArm.rotX, jointDesc.topArm.rotY, jointDesc.topArm.rotZ)

					if jointDesc.topArm.translationNode ~= nil then
						setTranslation(jointDesc.topArm.translationNode, 0, 0, 0)
					end

					if jointDesc.topArm.scaleNode ~= nil then
						setScale(jointDesc.topArm.scaleNode, 1, 1, 1)
					end

					if jointDesc.topArm.toggleVisibility then
						setVisibility(jointDesc.topArm.rotationNode, false)
					end
				end

				if jointDesc.bottomArm ~= nil then
					setRotation(jointDesc.bottomArm.rotationNode, jointDesc.bottomArm.rotX, jointDesc.bottomArm.rotY, jointDesc.bottomArm.rotZ)

					if jointDesc.bottomArm.translationNode ~= nil then
						setTranslation(jointDesc.bottomArm.translationNode, 0, 0, 0)
					end

					if self.setMovingToolDirty ~= nil then
						self:setMovingToolDirty(jointDesc.bottomArm.rotationNode)
					end
				end
			end

			if self.isServer then
				-- restore original translation
				setTranslation(jointDesc.jointTransform, unpack(jointDesc.jointOrigTrans))
				setTranslation(object.attacherJoint.node, unpack(object.attacherJoint.jointOrigTrans))

				if jointDesc.rotationNode ~= nil then
					setRotation(jointDesc.rotationNode, unpack(jointDesc.minRot))
				end
			end

			if jointDesc.ptoActive then
				if object.ptoInput.rootNode ~= nil then
					if object.movingPtoInput ~= nil then
						if object.movingPtoInput.attachNode ~= nil then
							unlink(object.movingPtoInput.attachNode, jointDesc.ptoOutput.node)
							link(object.movingPtoInput.parkNode, object.movingPtoInput.attachNode)
							setTranslation(object.movingPtoInput.attachNode, 0, 0, 0)
							setRotation(object.movingPtoInput.attachNode, math.rad(40), 0, 0)

							for _, entry in pairs(object.activeDirtyMovingParts) do
								if entry.movingPto ~= nil then
									if entry.movingPto then
										Cylindered.updateMovingPart(object, entry, false)
									end
								end
							end
						end
					else
						unlink(object.ptoInput.rootNode)
						unlink(object.ptoInput.attachNode)

						if object.removeWashableNode ~= nil then
							object:removeWashableNode(object.ptoOutput.rootNode)
							object:removeWashableNode(object.ptoOutput.attachNode)
							object:removeWashableNode(object.ptoOutput.dirAndScaleNode)
						end
					end
				else
					unlink(jointDesc.ptoOutput.rootNode)
					unlink(jointDesc.ptoOutput.attachNode)

					if object.removeWashableNode ~= nil then
						object:removeWashableNode(jointDesc.ptoOutput.rootNode)
						object:removeWashableNode(jointDesc.ptoOutput.attachNode)
						object:removeWashableNode(jointDesc.ptoOutput.dirAndScaleNode)
					end
				end

				jointDesc.ptoActive = false
			end

			object:onDetached(self, jointDescIndex)
		end

		table.remove(self.attachedImplements, implementIndex)

		if self.isClient then
			if selectNewImplement then
				local newSelectedImplement = nil
				local newIndex = math.min(implementIndex, table.getn(self.attachedImplements))

				if newIndex == 0 then
					if self ~= rootAttacherVehicle then
						-- select self
						newSelectedImplement = self.attacherVehicle:getImplementByObject(self)
					end
				else
					-- select the implement at the new index
					newSelectedImplement = self.attachedImplements[newIndex]
				end

				rootAttacherVehicle:setSelectedImplement(newSelectedImplement)
			end
		end
	end
end