local e={[Enum.NormalId.Top]=Vector3.new(0,1,0);[Enum.NormalId.Bottom]=Vector3.new(0,-1,0),[Enum.NormalId.Front]=Vector3.new(0,0,-1),[Enum.NormalId.Back]=Vector3.new(0,0,1);[Enum.NormalId.Left]=Vector3.new(-1,0,0),[Enum.NormalId.Right]=Vector3.new(1,0,0)}function HandleDragging.new(e)local u={Tool=e,IsHandleDragging=false,Handles=nil;InitialExtentsSize=nil;InitialExtentsCFrame=nil,InitialState=nil,InitialFocusCFrame=nil}return setmetatable(u,HandleDragging)end function HandleDragging.AttachHandles(p,u,R)if R and not p.Tool.Maid.AutofocusHandle then p.Tool.Maid.AutofocusHandle=Selection.FocusChanged:Connect(function()p:AttachHandles(Selection.Focus,true)end)elseif not R and p.Tool.Maid.AutofocusHandle then p.Tool.Maid.AutofocusHandle=nil end if p.Handles then p.Handles:BlacklistObstacle(BoundingBox.GetBoundingBox())p.Handles:SetAdornee(u)return end local j local function q()Core.Targeting.CancelSelecting()p.IsHandleDragging=true if BoundingBox.GetBoundingBox()then local e,u=BoundingBox.CalculateExtents(Selection.Parts,BoundingBox.StaticExtents)p.InitialExtentsSize=e p.InitialExtentsCFrame=u BoundingBox.PauseMonitoring()end local e,u=p.Tool:PreparePartsForDragging()p.InitialState=e p.InitialFocusCFrame=u p.Tool:TrackChange()if Core.Mode=="\084\111\111\108"then j=Security.GetPermissions(Security.GetSelectionAreas(Selection.Parts),Core.Player)end end local function G(u,R)if not p.IsHandleDragging then return end R=MoveUtil.GetIncrementMultiple(R,p.Tool.Increment)p.Tool:MovePartsAlongAxesByFace(u,R,p.InitialState,p.InitialFocusCFrame)if Core.Mode=="\084\111\111\108"and Security.ArePartsViolatingAreas(Selection.Parts,Core.Player,false,j)then local e,u=next(p.InitialState)e.CFrame=u.CFrame MoveUtil.TranslatePartsRelativeToPart(e,p.InitialState)R=0 end p.Tool.DragChanged:Fire(R)if p.Tool.Axes=="\071\108\111\098\097\108"and BoundingBox.GetBoundingBox()then(BoundingBox.GetBoundingBox()).CFrame=p.InitialExtentsCFrame+e[u]*R end end local function k()if not p.IsHandleDragging then return end p.IsHandleDragging=false for e,u in pairs(p.InitialState)do e:MakeJoints()Core.RestoreJoints(u.Joints)e.CanCollide=u.CanCollide e.Anchored=u.Anchored end p.Tool:RegisterChange()BoundingBox.RecalculateStaticExtents()BoundingBox.ResumeMonitoring()end local y=require(Libraries:WaitForChild("\072\097\110\100\108\101\115"))p.Handles=y.new({Color=p.Tool.Color.Color,Parent=Core.UIContainer,Adornee=u;ObstacleBlacklist={BoundingBox.GetBoundingBox()};OnDragStart=q,OnDrag=G,OnDragEnd=k})end function HandleDragging.HideHandles(e)if not e.Handles then return end e.Handles=e.Handles:Destroy()e.Tool.Maid.AutofocusHandle=nil end return HandleDragging

local AxisMultipliers = {
	[Enum.NormalId.Top] = Vector3.new(0, 1, 0);
	[Enum.NormalId.Bottom] = Vector3.new(0, -1, 0);
	[Enum.NormalId.Front] = Vector3.new(0, 0, -1);
	[Enum.NormalId.Back] = Vector3.new(0, 0, 1);
	[Enum.NormalId.Left] = Vector3.new(-1, 0, 0);
	[Enum.NormalId.Right] = Vector3.new(1, 0, 0);
}

function HandleDragging.new(Tool)
    local self = {
		Tool = Tool;

		-- Handle state
		IsHandleDragging = false;
		Handles = nil;

		-- Selection state
		InitialExtentsSize = nil;
		InitialExtentsCFrame = nil;
		InitialState = nil;
		InitialFocusCFrame = nil;
    }

    return setmetatable(self, HandleDragging)
end

function HandleDragging:AttachHandles(Part, Autofocus)
	-- Creates and attaches handles to `Part`, and optionally automatically attaches to the focused part

	-- Enable autofocus if requested and not already on
	if Autofocus and not self.Tool.Maid.AutofocusHandle then
		self.Tool.Maid.AutofocusHandle = Selection.FocusChanged:Connect(function ()
			self:AttachHandles(Selection.Focus, true)
		end)

	-- Disable autofocus if not requested and on
	elseif not Autofocus and self.Tool.Maid.AutofocusHandle then
		self.Tool.Maid.AutofocusHandle = nil
	end

	-- Just attach and show the handles if they already exist
	if self.Handles then
		self.Handles:BlacklistObstacle(BoundingBox.GetBoundingBox())
		self.Handles:SetAdornee(Part)
		return
	end

	local AreaPermissions
	local function OnHandleDragStart()
		-- Prepare for moving parts when the handle is clicked

		-- Prevent selection
		Core.Targeting.CancelSelecting()

		-- Indicate dragging via handles
		self.IsHandleDragging = true

		-- Freeze bounding box extents while dragging
		if BoundingBox.GetBoundingBox() then
			local InitialExtentsSize, InitialExtentsCFrame =
				BoundingBox.CalculateExtents(Selection.Parts, BoundingBox.StaticExtents)
			self.InitialExtentsSize = InitialExtentsSize
			self.InitialExtentsCFrame = InitialExtentsCFrame
			BoundingBox.PauseMonitoring()
		end

		-- Stop parts from moving, and capture the initial state of the parts
		local InitialState, InitialFocusCFrame = self.Tool:PreparePartsForDragging()
		self.InitialState = InitialState
		self.InitialFocusCFrame = InitialFocusCFrame

		-- Track the change
		self.Tool:TrackChange()

		-- Cache area permissions information
		if Core.Mode == 'Tool' then
			AreaPermissions = Security.GetPermissions(Security.GetSelectionAreas(Selection.Parts), Core.Player)
		end

	end

	local function OnHandleDrag(Face, Distance)
		-- Update parts when the handles are moved

		-- Only drag if handle is enabled
		if not self.IsHandleDragging then
			return
		end

		-- Calculate the increment-aligned drag distance
		Distance = MoveUtil.GetIncrementMultiple(Distance, self.Tool.Increment)

		-- Move the parts along the selected axes by the calculated distance
		self.Tool:MovePartsAlongAxesByFace(Face, Distance, self.InitialState, self.InitialFocusCFrame)

		-- Make sure we're not entering any unauthorized private areas
		if Core.Mode == 'Tool' and Security.ArePartsViolatingAreas(Selection.Parts, Core.Player, false, AreaPermissions) then
			local Part, InitialPartState = next(self.InitialState)
			Part.CFrame = InitialPartState.CFrame
			MoveUtil.TranslatePartsRelativeToPart(Part, self.InitialState)
			Distance = 0
		end

		-- Signal out change in dragged distance
		self.Tool.DragChanged:Fire(Distance)

		-- Update bounding box if enabled in global axes movements
		if self.Tool.Axes == 'Global' and BoundingBox.GetBoundingBox() then
			BoundingBox.GetBoundingBox().CFrame = self.InitialExtentsCFrame + (AxisMultipliers[Face] * Distance)
		end

	end

	local function OnHandleDragEnd()
		if not self.IsHandleDragging then
			return
		end

		-- Disable dragging
		self.IsHandleDragging = false

		-- Make joints, restore original anchor and collision states
		for Part, State in pairs(self.InitialState) do
			Part:MakeJoints()
			Core.RestoreJoints(State.Joints)
			Part.CanCollide = State.CanCollide
			Part.Anchored = State.Anchored
		end

		-- Register change
		self.Tool:RegisterChange()

		-- Resume bounding box updates
		BoundingBox.RecalculateStaticExtents()
		BoundingBox.ResumeMonitoring()
	end

	-- Create the handles
	local Handles = require(Libraries:WaitForChild 'Handles')
	self.Handles = Handles.new({
		Color = self.Tool.Color.Color,
		Parent = Core.UIContainer,
		Adornee = Part,
		ObstacleBlacklist = { BoundingBox.GetBoundingBox() },
		OnDragStart = OnHandleDragStart,
		OnDrag = OnHandleDrag,
		OnDragEnd = OnHandleDragEnd
	})

end

function HandleDragging:HideHandles()
	-- Hides the resizing handles

	-- Make sure handles exist and are visible
	if not self.Handles then
		return
	end

	-- Hide the handles
	self.Handles = self.Handles:Destroy()

	-- Disable handle autofocus
	self.Tool.Maid.AutofocusHandle = nil

end

return HandleDragging
