--[[
Made By TrolledTrollage, Date: 4/4/2022
Module Name: CustomHotbar

!! THIS SCRIPT ONLY WORKS FOR THE CLIENT AREA !!

USAGE EXAMPLE:

-- only works on local scripts
local hotbar = require(script.CustomHotbar)

 -- make new hotbar
local newhotbar = hotbar.new(Hotbar,ButtonTemplate)

-- fires on equip
newhotbar.Equipped:Connect(function(tool,frame)
	print(string.format("Equipped Tool: %s",tool.Name))
end)

-- fires on unequip,if tool was dropped, this wont fire
newhotbar.Unequipped:Connect(function(tool,frame)
	print(string.format("Unequipped Tool: %s",tool.Name))
end)

-- will fire if tool was dropped
newhotbar.Dropped:Connect(function(tool)
	print(string.format("Dropped Tool: %s",tool.Name))
end)

]]





function setup(Bar:GuiObject,Template:Button,E1:BindableEvent,E2:BindableEvent,E3:BindableEvent)
	local UserInputService = game:GetService("UserInputService")
	local TweenService = game:GetService("TweenService")
	local StarterGui = game:GetService("StarterGui")
	local Players = game:GetService("Players")
	
	local Player = Players.LocalPlayer
	local Backpack = Player.Backpack
	local Character = Player.Character
	
	local Equipped,Unequipped,Dropped = E1,E2,E3
	
	local Keys = {
		Zero = 10;
		One = 1;
		Two = 2;
		Three = 3;
		Four = 4;
		Five = 5;
		Six = 6;
		Seven = 7;
		Eight = 8;
		Nine = 9;
	}

	local items = {}
	local frames = {}

	local function handleEquip(tool)
		if tool.Parent ~= Character then
			Character.Humanoid:EquipTool(tool)
		else
			Character.Humanoid:UnequipTools()
		end
	end

	local function checkHotbar(removeIndex)
		if removeIndex then
			for _, toolFrame in pairs(Bar:GetChildren()) do
				if toolFrame:IsA("GuiObject") then
					pcall(function()
						if tonumber(toolFrame.Name) >= removeIndex then
							local newIndex = (tonumber(toolFrame.Name) == 11) and 0 or tonumber(toolFrame.Name) - 1
							local isVisible = (maxBar == 10) and (newIndex <= 9 and true or false)

							toolFrame.LayoutOrder -= 1
							toolFrame.Name -= 1
							toolFrame.Visible = isVisible or ((newIndex ~= 0 and newIndex <= maxBar) and true or false)
							if toolFrame:FindFirstChild("Key") and toolFrame.Key.ClassName == "TextLabel" then
								toolFrame.Key.Text = newIndex
							end
						end
					end)
				end
			end
		end

		for index, tool in ipairs(items) do
			local toolFrame = Bar:FindFirstChild(index)
			local isEquipped = (tool.Parent == Character)

			if not toolFrame then
				return
			end

			if frames[toolFrame] then
				frames[toolFrame] = nil
			end
			
			if isEquipped then
				Equipped:Fire(tool,toolFrame)
			else
				if (tool.Parent == Backpack) then
					Unequipped:Fire(tool,toolFrame)
				end
			end
		end
	end

	local function create(tool)
		local nextIndex = (#items == 10) and 0 or #items
		local isVisible = (maxBar == 10) and (nextIndex <= 9 and true or false) or ((nextIndex ~= 0 and nextIndex <= maxBar) and true or false)

		local toolFrame = Template:Clone()
		toolFrame.LayoutOrder = #items
		toolFrame.Name = #items
		toolFrame.Text = tool.Name
		toolFrame.Visible = isVisible
		if toolFrame:FindFirstChild("Key") and toolFrame.Key.ClassName == "TextLabel" then
			toolFrame.Key.Text = nextIndex
		end
		
		if toolFrame:FindFirstChild("Image") then
			if tool.TextureId ~= "" then
				toolFrame.Image.Image = tool.TextureId
				toolFrame.Text = ""
			end
		end

		toolFrame.Parent = Bar
		if toolFrame:IsA("TextButton") or toolFrame:IsA("ImageButton") then
			toolFrame.MouseButton1Click:Connect(function()
				handleEquip(tool)
			end)
		end

		checkHotbar()
	end

	local function updateAdd(tool)
		if not tool:IsA("Tool") then
			return
		end

		checkHotbar()
		if table.find(items, tool) then
			return
		end

		table.insert(items, tool)
		create(tool)
	end

	local function updateRemove(tool)
		if not tool:IsA("Tool") then
			return
		end

		if (tool.Parent == Character) or (tool.Parent == Backpack) then
			return
		end

		if table.find(items, tool) then
			local index = table.find(items, tool)
			local toolFrame = Bar:FindFirstChild(index)

			if toolFrame then
				toolFrame:Destroy()
			end
			
			Dropped:Fire(tool)
			table.remove(items, index)
			checkHotbar(index)
		end
	end


	coroutine.wrap(function()
		while true do
			local success, err = pcall(function()
				StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Backpack, false)
			end)
			if success then
				break
			end

			task.wait()
		end

		if maxBar > 10 then
			maxBar = 10
		end

		Template.Visible = true
		Template.Parent = nil

		for _, tool in pairs(Backpack:GetChildren()) do
			updateAdd(tool)
		end

		Backpack.ChildAdded:Connect(updateAdd)
		Backpack.ChildRemoved:Connect(updateRemove)
		Character.ChildAdded:Connect(updateAdd)
		Character.ChildRemoved:Connect(updateRemove)
		UserInputService.InputBegan:Connect(function(input, gameProcessed)
			if gameProcessed then
				return
			end

			if Keys[input.KeyCode.Name] then
				local index = Keys[input.KeyCode.Name]

				if items[index] then
					handleEquip(items[index])
				end
			end
		end)
	end)()
end

function Hotbar.new(Bar:Frame?,Template:TextButton?)
	local errorMessage = (Bar and "Argument 2 missing or nil.") or (Template and "Argument 1 missing or nil.") or ("Argument 1, and 2 missing or nil.")
	assert(Bar and Template,errorMessage)
	
	local run = game:GetService("RunService")
	if run:IsClient() then
		local events = {
			equipped = Instance.new("BindableEvent");
			unequipped = Instance.new("BindableEvent");
			dropped = Instance.new("BindableEvent");
		}
		
		local self = setmetatable({
			Equipped = events.equipped.Event;
			Unequipped = events.unequipped.Event;
			Dropped = events.dropped.Event;
		},Hotbar)	
		
		local allow = (table.find(AllowedTypes,Bar.ClassName) and table.find(AllowedTypes,Template.ClassName))
		assert(allow, "Invalid class type:"..Template.ClassName)
		
		setup(Bar,Template,events.equipped,events.unequipped,events.dropped)
		return self		
	else
		warn("Hotbar/Toolbar only works for client, please use a local script instead of a server script.")
		return
	end
end

return Hotbar