local h=game:GetService("\082\101\112\108\105\099\097\116\101\100\083\116\111\114\097\103\101")local F=game:GetService("\080\108\097\121\101\114\115")local m=h.AvatarEditor local T=require(m.Shared.Util.Maid)local l=require(m.Shared.Util.Promise)local N=require(m.Shared.Util.Signal)local a=require(m.Shared.Settings)local Q=require(m.Client.Theme)local M=F.LocalPlayer local j={}j.__index=j local function D()local h=m.CostumeTemplate:Clone()return h end function j.new(h)local F=setmetatable({},j)F.Maid=T.new()F.Listeners=T.new()F.ScrollingFrame=h.ScrollingFrame F.GridLayout=F.ScrollingFrame.UIGridLayout F.Wear=N.new()F.Delete=N.new()F.Children={}F.Pool={}for h=1,50,1 do F.Pool[h]=D()end F.Maid:GiveTask(Q.Changed:Connect(function()F:Render()end))F.Maid:GiveTask(Q:Bind(F.ScrollingFrame,"\083\099\114\111\108\108\066\097\114\073\109\097\103\101\067\111\108\111\114\051","\083\099\114\111\108\108\098\097\114"));((l.new(function(h,F)local m=M:WaitForChild("\065\069\095\067\111\115\116\117\109\101\115")h(m)end)):andThen(function(h)F.Folder=h F.Maid:GiveTask(h.ChildAdded:Connect(function()F:Render()end))F.Maid:GiveTask(h.ChildRemoved:Connect(function()F:Render()end))F:Render()end)):catch(warn)return F end function j.GetItem(h)local F=h.Pool local m=table.remove(F,#F)if not m then m=D()end return m end function j.Render(h)if not h.Folder then return end local m=h.Folder local T=h.Listeners local N=h.Children local M=h.ScrollingFrame local j=h.GridLayout local D=h.Pool local L=m:GetChildren()local y={}T:DoCleaning()for m,j in ipairs(L)do local D=N[m]or h:GetItem()y[m]=D D.ItemLabel.Text=j.Name D.More.Visible=false T:GiveTask(Q:Bind(D,"\066\097\099\107\103\114\111\117\110\100\067\111\108\111\114\051","\066\117\116\116\111\110"))T:GiveTask(Q:Bind(D.ItemLabel,"\084\101\120\116\067\111\108\111\114\051","\084\101\120\116"))T:GiveTask(Q:Bind(D.ItemLabel,"\084\101\120\116\083\116\114\111\107\101\067\111\108\111\114\051","\084\101\120\116\083\116\114\111\107\101"))T:GiveTask(Q:Bind(D.More,"\066\097\099\107\103\114\111\117\110\100\067\111\108\111\114\051","\068\101\108\101\116\101"))T:GiveTask(Q:Bind(D.More,"\084\101\120\116\067\111\108\111\114\051","\084\101\120\116"));((l.new(function(h,m)local T,l=pcall(function()return F:CreateHumanoidModelFromDescription(j,Enum.HumanoidRigType.R15,Enum.AssetTypeVerification.ClientOnly)end)if T then h(l)else m(l)end end)):andThen(function(h)T:GiveTask(h)h:SetPrimaryPartCFrame(CFrame.new())local F=h.Humanoid F.DisplayDistanceType=Enum.HumanoidDisplayDistanceType.None F.HealthDisplayType=Enum.HumanoidHealthDisplayType.AlwaysOff h.Animate:Destroy()local m=D.ViewportFrame local l=Instance.new("\067\097\109\101\114\097")T:GiveTask(l)l.CFrame=CFrame.lookAt(Vector3.new(-2,2,-5),h.PrimaryPart.Position)l.Parent=D m.CurrentCamera=l h.Parent=m.WorldModel T:GiveTask(function()m.CurrentCamera=nil end)end)):catch(warn)T:GiveTask(D.More.Activated:Connect(function(F)h.Delete:Fire(j)end))T:GiveTask(D.TouchLongPress:Connect(function(F,m)D.ItemLabel.Visible=false D.More.Visible=false h.Delete:Fire(j)end))T:GiveTask(D.InputBegan:Connect(function(h)if not a.HOVER_INPUTS[h.UserInputType]then return end D.ItemLabel.Visible=true if h.UserInputType==Enum.UserInputType.MouseMovement then D.More.Visible=true end end))T:GiveTask(D.InputEnded:Connect(function(h)if not a.HOVER_INPUTS[h.UserInputType]then return end D.ItemLabel.Visible=false D.More.Visible=false end))T:GiveTask(D.Activated:Connect(function(F)h.Wear:Fire(j)end))D.Parent=M end for h=#L+1,#N,1 do local F=N[h]F.Parent=nil table.insert(D,F)end h.Children=y M.CanvasSize=UDim2.new(0,0,0,j.AbsoluteContentSize.Y)end function j.Destroy(h)h.Maid:DoCleaning()h.Maid=nil h.Listeners:DoCleaning()h.Listeners=nil for h,F in ipairs(h.Children)do F:Destroy()end table.clear(h.Children)for h,F in ipairs(h.Pool)do F:Destroy()end table.clear(h.Pool)setmetatable(h,nil)end return j


local ReplicatedStorage = game:GetService("ReplicatedStorage")
local Players = game:GetService("Players")

local AvatarEditor = ReplicatedStorage.AvatarEditor
local Maid = require(AvatarEditor.Shared.Util.Maid)
local Promise = require(AvatarEditor.Shared.Util.Promise)
local Signal = require(AvatarEditor.Shared.Util.Signal)
local Settings = require(AvatarEditor.Shared.Settings)
local Theme = require(AvatarEditor.Client.Theme)

local player = Players.LocalPlayer

local Class = {}
Class.__index = Class


local function createButton()
	local button = AvatarEditor.CostumeTemplate:Clone()
	return button
end


function Class.new(frame)
	local self = setmetatable({}, Class)
	
	self.Maid = Maid.new()
	self.Listeners = Maid.new()
	self.ScrollingFrame = frame.ScrollingFrame
	self.GridLayout = self.ScrollingFrame.UIGridLayout
	self.Wear = Signal.new()
	self.Delete = Signal.new()
	self.Children = {}
	self.Pool = {}
	
	for i = 1, 50 do
		self.Pool[i] = createButton()
	end
	
	self.Maid:GiveTask(Theme.Changed:Connect(function()
		self:Render()
	end))
	
	self.Maid:GiveTask(Theme:Bind(self.ScrollingFrame, "ScrollBarImageColor3", "Scrollbar"))
	
	Promise.new(function(resolve, reject)
		local folder = player:WaitForChild("AE_Costumes")
		resolve(folder)
	end)
	:andThen(function(folder)
		self.Folder = folder
		self.Maid:GiveTask(folder.ChildAdded:Connect(function()
			self:Render()
		end))
		self.Maid:GiveTask(folder.ChildRemoved:Connect(function()
			self:Render()
		end))
		self:Render()
	end)
	:catch(warn)
	
	return self
end


function Class:GetItem()
	local pool = self.Pool
	local button = table.remove(pool, #pool)
	if not button then
		button = createButton()
	end
	return button
end


function Class:Render()
	if not self.Folder then
		return
	end
	
	local folder = self.Folder
	local maid = self.Listeners
	local children = self.Children
	local scrollingFrame = self.ScrollingFrame
	local uiGridLayout = self.GridLayout
	local pool = self.Pool
	
	local list = folder:GetChildren()
	local newChildren = {}
	
	maid:DoCleaning()
	
	for i, v in ipairs(list) do
		local button = children[i] or self:GetItem()
		newChildren[i] = button
		
		button.ItemLabel.Text = v.Name
		button.More.Visible = false
		
		maid:GiveTask(Theme:Bind(button, "BackgroundColor3", "Button"))
		maid:GiveTask(Theme:Bind(button.ItemLabel, "TextColor3", "Text"))
		maid:GiveTask(Theme:Bind(button.ItemLabel, "TextStrokeColor3", "TextStroke"))
		maid:GiveTask(Theme:Bind(button.More, "BackgroundColor3", "Delete"))
		maid:GiveTask(Theme:Bind(button.More, "TextColor3", "Text"))
		
		Promise.new(function(resolve, reject)
			local success, result = pcall(function()
				return Players:CreateHumanoidModelFromDescription(v, Enum.HumanoidRigType.R15, Enum.AssetTypeVerification.ClientOnly)
			end)
			if success then
				resolve(result)
			else
				reject(result)
			end
		end)
		:andThen(function(result)
			maid:GiveTask(result)
			result:SetPrimaryPartCFrame(CFrame.new())
			
			local humanoid = result.Humanoid
			humanoid.DisplayDistanceType = Enum.HumanoidDisplayDistanceType.None
			humanoid.HealthDisplayType = Enum.HumanoidHealthDisplayType.AlwaysOff
			result.Animate:Destroy()
			
			local viewport = button.ViewportFrame
			local camera = Instance.new("Camera")
			maid:GiveTask(camera)
			camera.CFrame = CFrame.lookAt(Vector3.new(-2, 2, -5), result.PrimaryPart.Position)
			camera.Parent = button
			viewport.CurrentCamera = camera
			result.Parent = viewport.WorldModel
			maid:GiveTask(function()
				viewport.CurrentCamera = nil
			end)
		end)
		:catch(warn)
		
		maid:GiveTask(button.More.Activated:Connect(function(inputObject)
			self.Delete:Fire(v)
		end))
		
		maid:GiveTask(button.TouchLongPress:Connect(function(touchPositions, inputState)
			button.ItemLabel.Visible = false
			button.More.Visible = false
			self.Delete:Fire(v)
		end))
		
		maid:GiveTask(button.InputBegan:Connect(function(inputObject)
			if not Settings.HOVER_INPUTS[inputObject.UserInputType] then
				return
			end

			button.ItemLabel.Visible = true
			if inputObject.UserInputType == Enum.UserInputType.MouseMovement then
				button.More.Visible = true
			end
		end))

		maid:GiveTask(button.InputEnded:Connect(function(inputObject)
			if not Settings.HOVER_INPUTS[inputObject.UserInputType] then
				return
			end

			button.ItemLabel.Visible = false
			button.More.Visible = false
		end))
		
		maid:GiveTask(button.Activated:Connect(function(inputObject)
			self.Wear:Fire(v)
		end))
		
		button.Parent = scrollingFrame
	end
	
	for i = #list + 1, #children do
		local button = children[i]
		button.Parent = nil
		table.insert(pool, button)
	end
	
	self.Children = newChildren
	scrollingFrame.CanvasSize = UDim2.new(0, 0, 0, uiGridLayout.AbsoluteContentSize.Y)
end


function Class:Destroy()
	self.Maid:DoCleaning()
	self.Maid = nil
	self.Listeners:DoCleaning()
	self.Listeners = nil
	for i, v in ipairs(self.Children) do
		v:Destroy()
	end
	table.clear(self.Children)
	for i, v in ipairs(self.Pool) do
		v:Destroy()
	end
	table.clear(self.Pool)
	setmetatable(self, nil)
end


return Class
