local l={"\083\112\111\116\076\105\103\104\116","\080\111\105\110\116\076\105\103\104\116";"\083\117\114\102\097\099\101\076\105\103\104\116"}function OpenLightOptions(s)local L=LightingTool.UI[s]local Q=Core.Tool.Interfaces.BTLightingToolGUI[s]CloseLightOptions(s)local H=UDim2.new(0,0,0,Q.Options.Size.Y.Offset)L.Options.Size=UDim2.new(L.Options.Size.X.Scale,L.Options.Size.X.Offset,L.Options.Size.Y.Scale,0)L.ClipsDescendants=false L.Options:TweenSize(Q.Options.Size+H,Enum.EasingDirection.Out,Enum.EasingStyle.Quad,.5,true,function()L.Options.ClipsDescendants=false end)LightingTool.UI:TweenSize(Core.Tool.Interfaces.BTLightingToolGUI.Size+H,Enum.EasingDirection.Out,Enum.EasingStyle.Quad,.5,true)local t=Support.FindTableOccurrence(l,s)for s=t+1,#l,1 do local L=l[s]local Q=LightingTool.UI[L]Q:TweenPosition(UDim2.new(Q.Position.X.Scale,Q.Position.X.Offset,Q.Position.Y.Scale,(30+30*(s-1))+H.Y.Offset),Enum.EasingDirection.Out,Enum.EasingStyle.Quad,.5,true)end EnableSurfaceClickSelection(s)end function CloseLightOptions(s)for l,L in pairs(l)do local Q=LightingTool.UI[L]local H=Core.Tool.Interfaces.BTLightingToolGUI[L]local t=H.Options.Size Q:TweenPosition(UDim2.new(Q.Position.X.Scale,Q.Position.X.Offset,Q.Position.Y.Scale,30+30*(l-1)),Enum.EasingDirection.Out,Enum.EasingStyle.Quad,.5,true)if not s or s and L~=s then Q.Options.ClipsDescendants=true Q.Options:TweenSize(UDim2.new(Q.Options.Size.X.Scale,Q.Options.Size.X.Offset,Q.Options.Size.Y.Scale,0),Enum.EasingDirection.Out,Enum.EasingStyle.Quad,.5,true,function()Q.ClipsDescendants=true Q.Options.Size=t end)end end if not s then LightingTool.UI:TweenSize(Core.Tool.Interfaces.BTLightingToolGUI.Size,Enum.EasingDirection.Out,Enum.EasingStyle.Quad,.5,true)end end function UpdateUI()if not LightingTool.UI then return end for l,s in pairs(l)do local L=GetLights(s)local Q=LightingTool.UI[s]local H=Q.Options local t=H.RangeOption.Input.TextBox local h=H.BrightnessOption.Input.TextBox local b=H.ColorOption.HSVPicker local k=H.ColorOption.Indicator local z=H.ShadowsOption.Checkbox local P=Q.AddButton local v=Q.RemoveButton if#L==0 and not Q.ClipsDescendants then CloseLightOptions()end if#L==0 then P.Visible=true P.Position=UDim2.new(1,-P.AbsoluteSize.X-5,0,3)v.Visible=false elseif#L<#Selection.Parts then P.Visible=true P.Position=UDim2.new(1,-P.AbsoluteSize.X-5,0,3)v.Visible=true v.Position=UDim2.new(1,((-P.AbsoluteSize.X-5)-v.AbsoluteSize.X)-2,0,3)elseif#L==#Selection.Parts then v.Visible=true v.Position=UDim2.new(1,-v.AbsoluteSize.X-5,0,3)P.Visible=false end UpdateDataInputs({[t]=Support.Round(Support.IdentifyCommonProperty(L,"\082\097\110\103\101"),2)or"\042",[h]=Support.Round(Support.IdentifyCommonProperty(L,"\066\114\105\103\104\116\110\101\115\115"),2)or"\042"})if s=="\083\112\111\116\076\105\103\104\116"or s=="\083\117\114\102\097\099\101\076\105\103\104\116"then local l=H.AngleOption.Input.TextBox local s=Core.Cheer(H.SideOption.Dropdown)UpdateDataInputs({[l]=Support.Round(Support.IdentifyCommonProperty(L,"\065\110\103\108\101"),2)or"\042"})local Q=Support.IdentifyCommonProperty(L,"\070\097\099\101")s.SetOption(Q and Q.Name or"\042")end local V=Support.IdentifyCommonProperty(L,"\067\111\108\111\114")if V then k.BackgroundColor3=V k.Varies.Text=""else k.BackgroundColor3=Color3.new(.87058823529412,.87058823529412,.87058823529412)k.Varies.Text="\042"end local S=Support.IdentifyCommonProperty(L,"\083\104\097\100\111\119\115")if S==true then z.Image=Core.Assets.CheckedCheckbox elseif S==false then z.Image=Core.Assets.UncheckedCheckbox elseif S==nil then z.Image=Core.Assets.SemicheckedCheckbox end end end function UpdateDataInputs(l)for l,s in pairs(l)do if not l:IsFocused()then l.Text=tostring(s)end end end function AddLights(l)local s={}for L,Q in pairs(Selection.Parts)do if not Support.GetChildOfClass(Q,l)then table.insert(s,{Part=Q;LightType=l})end end local L=Core.SyncAPI:Invoke("\067\114\101\097\116\101\076\105\103\104\116\115",s)local Q={Lights=L;Selection=Selection.Items,Unapply=function(l)Selection.Replace(l.Selection)Core.SyncAPI:Invoke("\082\101\109\111\118\101",l.Lights)end;Apply=function(l)Core.SyncAPI:Invoke("\085\110\100\111\082\101\109\111\118\101",l.Lights)Selection.Replace(l.Selection)end}Core.History.Add(Q)OpenLightOptions(l)end function RemoveLights(l)local s=GetLights(l)local L={Lights=s,Selection=Selection.Items;Unapply=function(l)Core.SyncAPI:Invoke("\085\110\100\111\082\101\109\111\118\101",l.Lights)Selection.Replace(l.Selection)end,Apply=function(l)Selection.Replace(l.Selection)Core.SyncAPI:Invoke("\082\101\109\111\118\101",l.Lights)end}Core.SyncAPI:Invoke("\082\101\109\111\118\101",s)Core.History.Add(L)end function TrackChange()HistoryRecord={Before={},After={};Selection=Selection.Items;Unapply=function(l)Selection.Replace(l.Selection)Core.SyncAPI:Invoke("\083\121\110\099\076\105\103\104\116\105\110\103",l.Before)end;Apply=function(l)Selection.Replace(l.Selection)Core.SyncAPI:Invoke("\083\121\110\099\076\105\103\104\116\105\110\103",l.After)end}end function RegisterChange()if not HistoryRecord then return end Core.SyncAPI:Invoke("\083\121\110\099\076\105\103\104\116\105\110\103",HistoryRecord.After)Core.History.Add(HistoryRecord)HistoryRecord=nil end function SetRange(l,s)if not s then return end TrackChange()for L,Q in pairs(GetLights(l))do table.insert(HistoryRecord.Before,{Part=Q.Parent,LightType=l,Range=Q.Range})table.insert(HistoryRecord.After,{Part=Q.Parent;LightType=l,Range=s})end RegisterChange()end function SetBrightness(l,s)if not s then return end TrackChange()for L,Q in pairs(GetLights(l))do table.insert(HistoryRecord.Before,{Part=Q.Parent,LightType=l,Brightness=Q.Brightness})table.insert(HistoryRecord.After,{Part=Q.Parent,LightType=l;Brightness=s})end RegisterChange()end function SetColor(l,s)if not s then return end TrackChange()for L,Q in pairs(GetLights(l))do table.insert(HistoryRecord.Before,{Part=Q.Parent,LightType=l;Color=Q.Color})table.insert(HistoryRecord.After,{Part=Q.Parent,LightType=l,Color=s})end RegisterChange()end function ToggleShadows(l)local s=not Support.IdentifyCommonProperty(GetLights(l),"\083\104\097\100\111\119\115")TrackChange()for L,Q in pairs(GetLights(l))do table.insert(HistoryRecord.Before,{Part=Q.Parent,LightType=l;Shadows=Q.Shadows})table.insert(HistoryRecord.After,{Part=Q.Parent;LightType=l;Shadows=s})end RegisterChange()end function SetSurface(l,s)if not s or not(l=="\083\117\114\102\097\099\101\076\105\103\104\116"or l=="\083\112\111\116\076\105\103\104\116")then return end TrackChange()for L,Q in pairs(GetLights(l))do table.insert(HistoryRecord.Before,{Part=Q.Parent;LightType=l,Face=Q.Face})table.insert(HistoryRecord.After,{Part=Q.Parent,LightType=l;Face=s})end RegisterChange()end function SetAngle(l,s)if not s then return end TrackChange()for L,Q in pairs(GetLights(l))do table.insert(HistoryRecord.Before,{Part=Q.Parent,LightType=l;Angle=Q.Angle})table.insert(HistoryRecord.After,{Part=Q.Parent;LightType=l;Angle=s})end RegisterChange()end

local LightTypes = { 'SpotLight', 'PointLight', 'SurfaceLight' };

function OpenLightOptions(LightType)
	-- Opens the settings UI for the given light type

	-- Get the UI
	local UI = LightingTool.UI[LightType];
	local UITemplate = Core.Tool.Interfaces.BTLightingToolGUI[LightType];

	-- Close up all light option UIs
	CloseLightOptions(LightType);

	-- Calculate how much to expand this options UI by
	local HeightExpansion = UDim2.new(0, 0, 0, UITemplate.Options.Size.Y.Offset);

	-- Start the options UI size from 0
	UI.Options.Size = UDim2.new(UI.Options.Size.X.Scale, UI.Options.Size.X.Offset, UI.Options.Size.Y.Scale, 0);

	-- Allow the options UI to be seen
	UI.ClipsDescendants = false;

	-- Perform the options UI resize animation
	UI.Options:TweenSize(
		UITemplate.Options.Size + HeightExpansion,
		Enum.EasingDirection.Out, Enum.EasingStyle.Quad, 0.5, true,
		function ()

			-- Allow visibility of overflowing UIs within the options UI
			UI.Options.ClipsDescendants = false;

		end
	);

	-- Expand the main UI to accommodate the expanded options UI
	LightingTool.UI:TweenSize(
		Core.Tool.Interfaces.BTLightingToolGUI.Size + HeightExpansion,
		Enum.EasingDirection.Out, Enum.EasingStyle.Quad, 0.5, true
	);

	-- Push any UIs below this one downwards
	local LightTypeIndex = Support.FindTableOccurrence(LightTypes, LightType);
	for LightTypeIndex = LightTypeIndex + 1, #LightTypes do

		-- Get the UI
		local LightType = LightTypes[LightTypeIndex];
		local UI = LightingTool.UI[LightType];

		-- Perform the position animation
		UI:TweenPosition(
			UDim2.new(
				UI.Position.X.Scale,
				UI.Position.X.Offset,
				UI.Position.Y.Scale,
				30 + 30 * (LightTypeIndex - 1) + HeightExpansion.Y.Offset
			),
			Enum.EasingDirection.Out, Enum.EasingStyle.Quad, 0.5, true
		);

	end;

	-- Enable surface setting by clicking
	EnableSurfaceClickSelection(LightType);

end;

function CloseLightOptions(Exception)
	-- Closes all light options, except the one for the given light type

	-- Go through each light type
	for LightTypeIndex, LightType in pairs(LightTypes) do

		-- Get the UI for each light type
		local UI = LightingTool.UI[LightType];
		local UITemplate = Core.Tool.Interfaces.BTLightingToolGUI[LightType];

		-- Remember the initial size for each options UI
		local InitialSize = UITemplate.Options.Size;

		-- Move each light type UI to its starting position
		UI:TweenPosition(
			UDim2.new(
				UI.Position.X.Scale,
				UI.Position.X.Offset,
				UI.Position.Y.Scale,
				30 + 30 * (LightTypeIndex - 1)
			),
			Enum.EasingDirection.Out, Enum.EasingStyle.Quad, 0.5, true
		);

		-- Make sure to not resize the exempt light type UI
		if not Exception or Exception and LightType ~= Exception then

			-- Allow the options UI to be resized
			UI.Options.ClipsDescendants = true;

			-- Perform the resize animation to close up
			UI.Options:TweenSize(
				UDim2.new(UI.Options.Size.X.Scale, UI.Options.Size.X.Offset, UI.Options.Size.Y.Scale, 0),
				Enum.EasingDirection.Out, Enum.EasingStyle.Quad, 0.5, true,
				function ()

					-- Hide the option UI
					UI.ClipsDescendants = true;

					-- Set the options UI's size to its initial size (for reexpansion)
					UI.Options.Size = InitialSize;

				end
			);

		end;

	end;

	-- Contract the main UI if no option UIs are being opened
	if not Exception then
		LightingTool.UI:TweenSize(
			Core.Tool.Interfaces.BTLightingToolGUI.Size,
			Enum.EasingDirection.Out, Enum.EasingStyle.Quad, 0.5, true
		);
	end;

end;

function UpdateUI()
	-- Updates information on the UI

	-- Make sure the UI's on
	if not LightingTool.UI then
		return;
	end;

	-- Go through each light type and update each options UI
	for _, LightType in pairs(LightTypes) do

		local Lights = GetLights(LightType);
		local LightSettingsUI = LightingTool.UI[LightType];

		-- Option input references
		local Options = LightSettingsUI.Options;
		local RangeInput = Options.RangeOption.Input.TextBox;
		local BrightnessInput = Options.BrightnessOption.Input.TextBox;
		local ColorPicker = Options.ColorOption.HSVPicker;
		local ColorIndicator = Options.ColorOption.Indicator;
		local ShadowsCheckbox = Options.ShadowsOption.Checkbox;

		-- Add/remove button references
		local AddButton = LightSettingsUI.AddButton;
		local RemoveButton = LightSettingsUI.RemoveButton;

		-- Hide option UIs for light types not present in the selection
		if #Lights == 0 and not LightSettingsUI.ClipsDescendants then
			CloseLightOptions();
		end;

		-------------------------------------------
		-- Show and hide "ADD" and "REMOVE" buttons
		-------------------------------------------

		-- If no selected parts have lights
		if #Lights == 0 then

			-- Show add button only
			AddButton.Visible = true;
			AddButton.Position = UDim2.new(1, -AddButton.AbsoluteSize.X - 5, 0, 3);
			RemoveButton.Visible = false;

		-- If only some selected parts have lights
		elseif #Lights < #Selection.Parts then

			-- Show both add and remove buttons
			AddButton.Visible = true;
			AddButton.Position = UDim2.new(1, -AddButton.AbsoluteSize.X - 5, 0, 3);
			RemoveButton.Visible = true;
			RemoveButton.Position = UDim2.new(1, -AddButton.AbsoluteSize.X - 5 - RemoveButton.AbsoluteSize.X - 2, 0, 3);

		-- If all selected parts have lights
		elseif #Lights == #Selection.Parts then

			-- Show remove button
			RemoveButton.Visible = true;
			RemoveButton.Position = UDim2.new(1, -RemoveButton.AbsoluteSize.X - 5, 0, 3);
			AddButton.Visible = false;

		end;

		--------------------
		-- Update each input
		--------------------

		-- Update the standard inputs
		UpdateDataInputs {
			[RangeInput] = Support.Round(Support.IdentifyCommonProperty(Lights, 'Range'), 2) or '*';
			[BrightnessInput] = Support.Round(Support.IdentifyCommonProperty(Lights, 'Brightness'), 2) or '*';
		};

		-- Update type-specific inputs
		if LightType == 'SpotLight' or LightType == 'SurfaceLight' then

			-- Get the type-specific inputs
			local AngleInput = Options.AngleOption.Input.TextBox;
			local SideDropdown = Core.Cheer(Options.SideOption.Dropdown);

			-- Update the angle input
			UpdateDataInputs {
				[AngleInput] = Support.Round(Support.IdentifyCommonProperty(Lights, 'Angle'), 2) or '*';
			};

			-- Update the surface dropdown input
			local Face = Support.IdentifyCommonProperty(Lights, 'Face');
			SideDropdown.SetOption(Face and Face.Name or '*');

		end;

		-- Update special color input
		local Color = Support.IdentifyCommonProperty(Lights, 'Color');
		if Color then
			ColorIndicator.BackgroundColor3 = Color;
			ColorIndicator.Varies.Text = '';
		else
			ColorIndicator.BackgroundColor3 = Color3.new(222/255, 222/255, 222/255);
			ColorIndicator.Varies.Text = '*';
		end;

		-- Update the special shadows input
		local ShadowsEnabled = Support.IdentifyCommonProperty(Lights, 'Shadows');
		if ShadowsEnabled == true then
			ShadowsCheckbox.Image = Core.Assets.CheckedCheckbox;
		elseif ShadowsEnabled == false then
			ShadowsCheckbox.Image = Core.Assets.UncheckedCheckbox;
		elseif ShadowsEnabled == nil then
			ShadowsCheckbox.Image = Core.Assets.SemicheckedCheckbox;
		end;

	end;

end;

function UpdateDataInputs(Data)
	-- Updates the data in the given TextBoxes when the user isn't typing in them

	-- Go through the inputs and data
	for Input, UpdatedValue in pairs(Data) do

		-- Makwe sure the user isn't typing into the input
		if not Input:IsFocused() then

			-- Set the input's value
			Input.Text = tostring(UpdatedValue);

		end;

	end;

end;

function AddLights(LightType)

	-- Prepare the change request for the server
	local Changes = {};

	-- Go through the selection
	for _, Part in pairs(Selection.Parts) do

		-- Make sure this part doesn't already have a light
		if not Support.GetChildOfClass(Part, LightType) then

			-- Queue a light to be created for this part
			table.insert(Changes, { Part = Part, LightType = LightType });

		end;

	end;

	-- Send the change request to the server
	local Lights = Core.SyncAPI:Invoke('CreateLights', Changes);

	-- Put together the history record
	local HistoryRecord = {
		Lights = Lights;
		Selection = Selection.Items;

		Unapply = function (Record)
			-- Reverts this change

			-- Select changed parts
			Selection.Replace(Record.Selection)

			-- Remove the lights
			Core.SyncAPI:Invoke('Remove', Record.Lights);

		end;

		Apply = function (Record)
			-- Reapplies this change

			-- Restore the lights
			Core.SyncAPI:Invoke('UndoRemove', Record.Lights);

			-- Select changed parts
			Selection.Replace(Record.Selection)

		end;

	};

	-- Register the history record
	Core.History.Add(HistoryRecord);

	-- Open the options UI for this light type
	OpenLightOptions(LightType);

end;

function RemoveLights(LightType)

	-- Get all the lights in the selection
	local Lights = GetLights(LightType);

	-- Create the history record
	local HistoryRecord = {
		Lights = Lights;
		Selection = Selection.Items;

		Unapply = function (Record)
			-- Reverts this change

			-- Restore the lights
			Core.SyncAPI:Invoke('UndoRemove', Record.Lights);

			-- Select changed parts
			Selection.Replace(Record.Selection)

		end;

		Apply = function (Record)
			-- Reapplies this change

			-- Select changed parts
			Selection.Replace(Record.Selection)

			-- Remove the lights
			Core.SyncAPI:Invoke('Remove', Record.Lights);

		end;

	};

	-- Send the removal request
	Core.SyncAPI:Invoke('Remove', Lights);

	-- Register the history record
	Core.History.Add(HistoryRecord);

end;

function TrackChange()

	-- Start the record
	HistoryRecord = {
		Before = {};
		After = {};
		Selection = Selection.Items;

		Unapply = function (Record)
			-- Reverts this change

			-- Select the changed parts
			Selection.Replace(Record.Selection)

			-- Send the change request
			Core.SyncAPI:Invoke('SyncLighting', Record.Before);

		end;

		Apply = function (Record)
			-- Applies this change

			-- Select the changed parts
			Selection.Replace(Record.Selection)

			-- Send the change request
			Core.SyncAPI:Invoke('SyncLighting', Record.After);

		end;

	};

end;

function RegisterChange()
	-- Finishes creating the history record and registers it

	-- Make sure there's an in-progress history record
	if not HistoryRecord then
		return;
	end;

	-- Send the change to the server
	Core.SyncAPI:Invoke('SyncLighting', HistoryRecord.After);

	-- Register the record and clear the staging
	Core.History.Add(HistoryRecord);
	HistoryRecord = nil;

end;

function SetRange(LightType, Range)

	-- Make sure the given range is valid
	if not Range then
		return;
	end;

	-- Start a history record
	TrackChange();

	-- Go through each light
	for _, Light in pairs(GetLights(LightType)) do

		-- Store the state of the light before modification
		table.insert(HistoryRecord.Before, { Part = Light.Parent, LightType = LightType, Range = Light.Range });

		-- Create the change request for this light
		table.insert(HistoryRecord.After, { Part = Light.Parent, LightType = LightType, Range = Range });

	end;

	-- Register the changes
	RegisterChange();

end;

function SetBrightness(LightType, Brightness)

	-- Make sure the given brightness is valid
	if not Brightness then
		return;
	end;

	-- Start a history record
	TrackChange();

	-- Go through each light
	for _, Light in pairs(GetLights(LightType)) do

		-- Store the state of the light before modification
		table.insert(HistoryRecord.Before, { Part = Light.Parent, LightType = LightType, Brightness = Light.Brightness });

		-- Create the change request for this light
		table.insert(HistoryRecord.After, { Part = Light.Parent, LightType = LightType, Brightness = Brightness });

	end;

	-- Register the changes
	RegisterChange();

end;

function SetColor(LightType, Color)

	-- Make sure the given color is valid
	if not Color then
		return;
	end;

	-- Start a history record
	TrackChange();

	-- Go through each light
	for _, Light in pairs(GetLights(LightType)) do

		-- Store the state of the light before modification
		table.insert(HistoryRecord.Before, { Part = Light.Parent, LightType = LightType, Color = Light.Color });

		-- Create the change request for this light
		table.insert(HistoryRecord.After, { Part = Light.Parent, LightType = LightType, Color = Color });

	end;

	-- Register the changes
	RegisterChange();

end;

function ToggleShadows(LightType)

	-- Determine whether to turn shadows on or off
	local ShadowsEnabled = not Support.IdentifyCommonProperty(GetLights(LightType), 'Shadows');

	-- Start a history record
	TrackChange();

	-- Go through each light
	for _, Light in pairs(GetLights(LightType)) do

		-- Store the state of the light before modification
		table.insert(HistoryRecord.Before, { Part = Light.Parent, LightType = LightType, Shadows = Light.Shadows });

		-- Create the change request for this light
		table.insert(HistoryRecord.After, { Part = Light.Parent, LightType = LightType, Shadows = ShadowsEnabled });

	end;

	-- Register the changes
	RegisterChange();

end;

function SetSurface(LightType, Face)

	-- Make sure the given face is valid, and this is an applicable light type
	if not Face or not (LightType == 'SurfaceLight' or LightType == 'SpotLight') then
		return;
	end;

	-- Start a history record
	TrackChange();

	-- Go through each light
	for _, Light in pairs(GetLights(LightType)) do

		-- Store the state of the light before modification
		table.insert(HistoryRecord.Before, { Part = Light.Parent, LightType = LightType, Face = Light.Face });

		-- Create the change request for this light
		table.insert(HistoryRecord.After, { Part = Light.Parent, LightType = LightType, Face = Face });

	end;

	-- Register the changes
	RegisterChange();

end;

function SetAngle(LightType, Angle)

	-- Make sure the given angle is valid
	if not Angle then
		return;
	end;

	-- Start a history record
	TrackChange();

	-- Go through each light
	for _, Light in pairs(GetLights(LightType)) do

		-- Store the state of the light before modification
		table.insert(HistoryRecord.Before, { Part = Light.Parent, LightType = LightType, Angle = Light.Angle });

		-- Create the change request for this light
		table.insert(HistoryRecord.After, { Part = Light.Parent, LightType = LightType, Angle = Angle });

	end;

	-- Register the changes
	RegisterChange();

end;
