-- Listen for changes to the selection and keep the focus updated
Selection.Changed:connect(FocusOnLastSelectedPart);

function GetCore()
	-- Returns the core API
	return require(script.Parent.Core);
end;

function CreateSelectionBoxes(Items)
	-- Creates a SelectionBox for each given item

	-- Get the core API
	local Core = GetCore();

	-- Only create selection boxes if in tool mode
	if Core.Mode ~= 'Tool' then
		return;
	end;

	-- Track new selection boxes
	local SelectionBoxes = {};

	-- Create an outline for each part
	for _, Item in pairs(Items) do

		-- Avoid duplicate selection boxes
		if not Selection.Outlines[Item] then

			-- Create the selection box
			local SelectionBox = Instance.new 'SelectionBox';
			SelectionBox.Name = 'BTSelectionBox';
			SelectionBox.Color = Selection.Color;
			SelectionBox.Adornee = Item;
			SelectionBox.LineThickness = 0.025;
			SelectionBox.Transparency = 0.5;

			-- Register the outline
			Selection.Outlines[Item] = SelectionBox;
			table.insert(SelectionBoxes, SelectionBox);

		end;

	end;

	-- Parent the selection boxes
	for _, SelectionBox in pairs(SelectionBoxes) do
		SelectionBox.Parent = Core.UIContainer;
	end;

end;

function RemoveSelectionBoxes(Items)
	-- Removes the given item's selection box

	-- Only proceed if in tool mode
	if GetCore().Mode ~= 'Tool' then
		return;
	end;

	-- Remove each item's outline
	for _, Item in pairs(Items) do

		-- Get the item's selection box
		local SelectionBox = Selection.Outlines[Item];

		-- Remove the selection box if found
		if SelectionBox then
			SelectionBox:Destroy();
		end;

		-- Deregister the selection box
		Selection.Outlines[Item] = nil;

	end;

end;

function Selection.RecolorOutlines(Color)
	-- Updates selection outline colors

	-- Set `Color` as the new color
	Selection.Color = Color;

	-- Recolor existing outlines
	for _, Outline in pairs(Selection.Outlines) do
		Outline.Color = Selection.Color;
	end;

end;

function Selection.FlashOutlines()
	-- Flashes selection outlines for emphasis

	-- Fade in from complete to normal transparency
	for Transparency = 1, 0.5, -0.1 do

		-- Update each outline
		for _, Outline in pairs(Selection.Outlines) do
			Outline.Transparency = Transparency;
		end;

		-- Fade over time
		wait(0.1);

	end;

end;

function Selection.EnableOutlines()
	-- Shows selection outlines

	local UIContainer = GetCore().UIContainer;

	-- Show each outline
	for _, Outline in pairs(Selection.Outlines) do
		Outline.Parent = UIContainer;
	end;

	-- Hide outlines when tool is disabled
	GetCore().Connections.HideOutlinesOnDisable = GetCore().Disabling:connect(Selection.HideOutlines);

end;

function Selection.EnableMultiselectionHotkeys()
	-- Enables hotkeys for multiselecting

	-- Determine multiselection hotkeys
	local Hotkeys = Support.FlipTable { 'LeftShift', 'RightShift', 'LeftControl', 'RightControl' };

	-- Get core API
	local Core = GetCore();

	-- Listen for matching key presses
	Core.Connections.MultiselectionHotkeys = Support.AddUserInputListener('Began', 'Keyboard', false, function (Input)
		if Hotkeys[Input.KeyCode.Name] then
			Selection.Multiselecting = true;
		end;
	end);

	-- Listen for matching key releases
	Core.Connections.MultiselectingReleaseHotkeys = Support.AddUserInputListener('Ended', 'Keyboard', true, function (Input)

		-- Get currently pressed keys
		local PressedKeys = Support.GetListMembers(Support.GetListMembers(Game:GetService('UserInputService'):GetKeysPressed(), 'KeyCode'), 'Name');

		-- Continue multiselection if a hotkey is still pressed
		for _, PressedKey in pairs(PressedKeys) do
			if Hotkeys[PressedKey] then
				return;
			end;
		end;

		-- Disable multiselection if matching key not found
		Selection.Multiselecting = false;

	end);

end;

function Selection.HideOutlines()
	-- Hides selection outlines

	-- Hide each outline
	for _, Outline in pairs(Selection.Outlines) do
		Outline.Parent = nil;
	end;

end;

function TrackSelectionChange(OldSelection)
	-- Registers a history record for a change in the selection

	-- Avoid overwriting history for selection actions
	if History.Index ~= #History.Stack then
		return;
	end;

	-- Add the history record
	History.Add({

		Before = OldSelection;
		After = Selection.Items;

		Unapply = function (HistoryRecord)
			-- Reverts this change

			-- Restore the old selection
			Selection.Replace(HistoryRecord.Before);

		end;

		Apply = function (HistoryRecord)
			-- Reapplies this change

			-- Restore the new selection
			Selection.Replace(HistoryRecord.After);

		end;
	});

end;

return Selection;