local X=require(script.Digit)local w={}local G={Frame=true;Digits=true,CommaLabels=true;Text=true}local F={Value="\110\117\109\098\101\114",Duration="\110\117\109\098\101\114";Decimals="\110\117\109\098\101\114";Prefix="\115\116\114\105\110\103";Suffix="\115\116\114\105\110\103",Commas="\098\111\111\108\101\097\110",GuiObject="\073\110\115\116\097\110\099\101"}local E={[Enum.TextXAlignment.Center]=Enum.HorizontalAlignment.Center;[Enum.TextXAlignment.Left]=Enum.HorizontalAlignment.Left,[Enum.TextXAlignment.Right]=Enum.HorizontalAlignment.Right}local j=Instance.new("\070\114\097\109\101")local I=Instance.new("\084\101\120\116\076\097\098\101\108")I.TextSize=25 I.TextColor3=Color3.fromRGB(250,250,255)I.Font=Enum.Font.SourceSans local function c()local w={Value=0;Duration=.3,Decimals=2;Prefix="\036";Suffix="",Commas=false,GuiObject=nil;Digits={Whole=table.create(3);Decimal=table.create(2)};CommaLabels=table.create(2)}local c=setmetatable({},{__index=function(X,G)local F=w[G]if F then return F end local E=pcall(function()local X=j[G]end)if E then return w.Frame[G]end local c,f=pcall(function()return I[G]end)if c then local X=w.Digits.Whole[1]if X then return X[G]else return f end end return nil end;__newindex=function(X,c,f)if G[c]then warn("\065\116\116\101\109\112\116\101\100 \116\111 \115\101\116 \114\101\097\100-\111\110\108\121 \118\097\108\117\101 \083\112\105\110\110\101\114\046"..c)return end local V=pcall(function()local X=j[c]end)if V then local X=typeof(j[c])if X~="\110\105\108"and X~=typeof(f)then warn("\065\116\116\101\109\112\116\101\100 \116\111 \115\101\116 \083\112\105\110\110\101\114\046"..(c..(" \116\111 \105\110\118\097\108\105\100 \118\097\108\117\101 \040"..(tostring(f).."\041"))))return end w.Frame[c]=f return end if c=="\084\101\120\116\088\065\108\105\103\110\109\101\110\116"then w.Layout.HorizontalAlignment=E[f]return end local i=pcall(function()local X=I[c]end)if i then local X=typeof(I[c])if X~="\110\105\108"and X~=typeof(f)then warn("\065\116\116\101\109\112\116\101\100 \116\111 \115\101\116 \083\112\105\110\110\101\114\046"..(c..(" \116\111 \105\110\118\097\108\105\100 \118\097\108\117\101 \040"..(tostring(f).."\041"))))return end for X,w in pairs(w.Digits.Whole)do w[c]=f end for X,w in pairs(w.Digits.Decimal)do w[c]=f end for X,w in pairs(w.CommaLabels)do w[c]=f end w.PrefixLabel[c]=f w.SuffixLabel[c]=f w.DecimalLabel[c]=f w.NegativeLabel[c]=f return end if F[c]then if typeof(f)~=F[c]then warn("\065\116\116\101\109\112\116\101\100 \116\111 \115\101\116 \083\112\105\110\110\101\114\046"..(c..(" \116\111 \105\110\118\097\108\105\100 \118\097\108\117\101 \040"..(tostring(f).."\041"))))return end w[c]=f w:Update(c,f)return end end})function w.Destroy(X)X.Frame:Destroy()table.clear(X)end function w.Update(E,G,F)if G=="\080\114\101\102\105\120"then w.PrefixLabel.Text=w.Prefix return elseif G=="\083\117\102\102\105\120"then w.SuffixLabel.Text=w.Suffix return end local j=math.abs(w.Value)local I=w.Value<0 if w.NegativeLabel then w.NegativeLabel.Visible=I end local f=w.Decimals>0 and string.format("\037\046"..(w.Decimals.."\102"),j)or string.format("\037\100",j)local V=string.split(f,"\046")local i,C=V[1],V[2]if not i then return end local n=#i for G=1,n,1 do local F=w.Digits.Whole[G]if F then F.Duration=w.Duration F.Value=tonumber(string.sub(i,G,G))else F=X.new(c,G*2-900,tonumber(string.sub(i,G,G)))w.Digits.Whole[G]=F end end for X=n+1,#w.Digits.Whole,1 do local G=w.Digits.Whole[X]if G then G:Destroy()w.Digits.Whole[X]=nil end end if w.Commas then local X=n*2-900 local G=string.format("\037\100",math.floor(math.abs(w.Value)))local F=0 for G=0,#G-1,3 do if G==0 then continue end F+=1 local E=w.CommaLabels[F]if not E then E=Instance.new("\084\101\120\116\076\097\098\101\108")E.Name="\067\111\109\109\097"E.BackgroundTransparency=1 E.Size=UDim2.new(0,0,1,0)E.Font=c.Font E.TextSize=c.TextSize E.TextColor3=c.TextColor3 E.Text="\044"E.AutomaticSize=Enum.AutomaticSize.X E.Parent=w.Frame w.CommaLabels[F]=E end E.LayoutOrder=(X-(G-1)*2)-1 end for X=F+1,#w.CommaLabels,1 do w.CommaLabels[X]:Destroy()w.CommaLabels[X]=nil end end if not C then if w.DecimalLabel then w.DecimalLabel.Visible=false end for X,w in ipairs(w.Digits.Decimal)do w:Destroy()end table.clear(w.Digits.Decimal)return end if w.DecimalLabel then w.DecimalLabel.Visible=true end for G=1,#C,1 do local F=w.Digits.Decimal[G]if F then F.Duration=w.Duration F.Value=tonumber(string.sub(C,G,G))else F=X.new(c,G,tonumber(string.sub(C,G,G)))w.Digits.Decimal[G]=F end end for X=#C+1,#w.Digits.Decimal,1 do local G=w.Digits.Decimal[X]if G then G:Destroy()w.Digits.Decimal[X]=nil end end end return c,w end function w.new()local X,w=c()local G=Instance.new("\070\114\097\109\101")G.BackgroundTransparency=1 G.ClipsDescendants=true G.Size=UDim2.new(0,200,0,50)G.Position=UDim2.new(0,0,0,0)local F=Instance.new("\085\073\076\105\115\116\076\097\121\111\117\116")F.SortOrder=Enum.SortOrder.LayoutOrder F.FillDirection=Enum.FillDirection.Horizontal F.HorizontalAlignment=Enum.HorizontalAlignment.Center F.VerticalAlignment=Enum.VerticalAlignment.Center F.Padding=UDim.new(0,0)F.Parent=G local E=Instance.new("\084\101\120\116\076\097\098\101\108")E.Name="\080\114\101\102\105\120"E.LayoutOrder=-1000 E.BackgroundTransparency=1 E.Size=UDim2.new(0,0,1,0)E.Font=X.Font E.TextSize=X.TextSize E.TextColor3=X.TextColor3 E.Text=X.Prefix E.AutomaticSize=Enum.AutomaticSize.X E.Parent=G local j=Instance.new("\084\101\120\116\076\097\098\101\108")j.Name="\083\117\102\102\105\120"j.LayoutOrder=1000 j.BackgroundTransparency=1 j.Size=UDim2.new(0,0,1,0)j.Font=X.Font j.TextSize=X.TextSize j.TextColor3=X.TextColor3 j.Text=X.Suffix j.AutomaticSize=Enum.AutomaticSize.X j.Parent=G local I=Instance.new("\084\101\120\116\076\097\098\101\108")I.Name="\068\101\099\105\109\097\108"I.LayoutOrder=0 I.BackgroundTransparency=1 I.Size=UDim2.new(0,0,1,0)I.Font=X.Font I.TextSize=X.TextSize I.TextColor3=X.TextColor3 I.Text="\046"I.AutomaticSize=Enum.AutomaticSize.X I.Parent=G local f=Instance.new("\084\101\120\116\076\097\098\101\108")f.Name="\078\101\103\097\116\105\118\101"f.LayoutOrder=-999 f.BackgroundTransparency=1 f.Size=UDim2.new(0,0,1,0)f.Font=X.Font f.TextSize=X.TextSize f.TextColor3=X.TextColor3 f.Text="-"f.AutomaticSize=Enum.AutomaticSize.X f.Parent=G w.Frame=G w.Layout=F w.PrefixLabel=E w.SuffixLabel=j w.DecimalLabel=I w.NegativeLabel=f X.GuiObject=G X:Update()return X end function w.fromGuiObject(X)if not typeof(X)=="\073\110\115\116\097\110\099\101"then return end if not X:IsA("\071\117\105\079\098\106\101\099\116")then return end local G=w.new()G.Name="\083\112\105\110\110\101\114\095"..X.Name G.SizeConstraint=X.SizeConstraint G.Size=X.Size G.Position=X.Position G.AnchorPoint=X.AnchorPoint G.Rotation=X.Rotation G.LayoutOrder=X.LayoutOrder G.ZIndex=X.ZIndex G.Visible=X.Visible G.BackgroundColor3=X.BackgroundColor3 G.BorderColor3=X.BorderColor3 G.BorderSizePixel=X.BorderSizePixel G.BackgroundTransparency=X.BackgroundTransparency if X:IsA("\084\101\120\116\076\097\098\101\108")or X:IsA("\084\101\120\116\066\117\116\116\111\110")or X:IsA("\084\101\120\116\066\111\120")then G.Font=X.Font G.TextSize=X.TextSize G.TextColor3=X.TextColor3 G.TextTransparency=X.TextTransparency G.TextStrokeColor3=X.TextStrokeColor3 G.TextStrokeTransparency=X.TextStrokeTransparency G.Layout.HorizontalAlignment=E[X.TextXAlignment]end G.Parent=X.Parent X.Visible=false return G end return w
local DigitModule = require(script.Digit)

local NumberSpinner = {}

local READ_ONLY = {
	Frame = true,
	Digits = true,
	CommaLabels = true,
	Text = true,
}
local CUSTOM_PROPS = {
	Value = "number",
	Duration = "number",
	Decimals = "number",
	Prefix = "string",
	Suffix = "string",
	Commas = "boolean",
	GuiObject = "Instance",
}
local TEXT_TO_LAYOUT = {
	[Enum.TextXAlignment.Center] = Enum.HorizontalAlignment.Center,
	[Enum.TextXAlignment.Left] = Enum.HorizontalAlignment.Left,
	[Enum.TextXAlignment.Right] = Enum.HorizontalAlignment.Right,
}

local DUMMY_FRAME = Instance.new("Frame")
local DUMMY_LABEL = Instance.new("TextLabel")
DUMMY_LABEL.TextSize = 25
DUMMY_LABEL.TextColor3 = Color3.fromRGB(250, 250, 255)
DUMMY_LABEL.Font = Enum.Font.SourceSans

local function newSpinner()
	local Spinner = {
		-- Props
		Value = 0,
		Duration = 0.3,
		Decimals = 2,
		Prefix = "$",
		Suffix = "",
		Commas = false,

		GuiObject = nil,

		-- Internal
		Digits = {
			Whole = table.create(3),
			Decimal = table.create(2),
		},
		CommaLabels = table.create(2),
	}

	local SpinnerProxy = setmetatable({}, {
		__index = function(_, key)
			local Direct = Spinner[key]
			if Direct then
				return Direct
			end

			local Success = pcall(function()
				local _x = DUMMY_FRAME[key]
			end)
			if Success then
				return Spinner.Frame[key]
			end

			local _Success, TextProp = pcall(function()
				return DUMMY_LABEL[key]
			end)
			if _Success then
				local d = Spinner.Digits.Whole[1]
				if d then
					return d[key]
				else
					return TextProp
				end
			end

			--warn("Nothing found for",key)
			return nil
		end,
		__newindex = function(_, key, value)
			if READ_ONLY[key] then
				warn("Attempted to set read-only value Spinner." .. key)
				return
			end

			-- Handle setting of Frame properties
			local Success = pcall(function()
				local _x = DUMMY_FRAME[key]
			end)
			if Success then
				local t = typeof(DUMMY_FRAME[key])
				if (t ~= "nil") and (t ~= typeof(value)) then
					warn("Attempted to set Spinner." .. key .. " to invalid value (" .. tostring(value) .. ")")
					return
				end
				Spinner.Frame[key] = value
				return
			end

			-- Handle alignment since it's a special case
			if key == "TextXAlignment" then
				Spinner.Layout.HorizontalAlignment = TEXT_TO_LAYOUT[value]
				return
			end

			-- Handle setting of text related properties
			local _Success = pcall(function()
				local _x = DUMMY_LABEL[key]
			end)
			if _Success then
				local t = typeof(DUMMY_LABEL[key])
				if (t ~= "nil") and (t ~= typeof(value)) then
					warn("Attempted to set Spinner." .. key .. " to invalid value (" .. tostring(value) .. ")")
					return
				end
				for _i, Digit in pairs(Spinner.Digits.Whole) do
					Digit[key] = value
				end
				for _i, Digit in pairs(Spinner.Digits.Decimal) do
					Digit[key] = value
				end
				for _i, Comma in pairs(Spinner.CommaLabels) do
					Comma[key] = value
				end
				Spinner.PrefixLabel[key] = value
				Spinner.SuffixLabel[key] = value
				Spinner.DecimalLabel[key] = value
				Spinner.NegativeLabel[key] = value
				return
			end

			-- Handle setting of the custom spinner properties
			if CUSTOM_PROPS[key] then
				if typeof(value) ~= CUSTOM_PROPS[key] then
					warn("Attempted to set Spinner." .. key .. " to invalid value (" .. tostring(value) .. ")")
					return
				end
				Spinner[key] = value
				Spinner:Update(key, value)
				return
			end
		end,
	})

	function Spinner:Destroy()
		self.Frame:Destroy()
		table.clear(self)
	end

	function Spinner:Update(Type, _Value)
		if Type == "Prefix" then
			Spinner.PrefixLabel.Text = Spinner.Prefix
			return
		elseif Type == "Suffix" then
			Spinner.SuffixLabel.Text = Spinner.Suffix
			return
		end

		local AbsValue = math.abs(Spinner.Value)
		local isNegative = Spinner.Value < 0

		if Spinner.NegativeLabel then
			Spinner.NegativeLabel.Visible = isNegative
		end

		local TextValue = Spinner.Decimals > 0 and string.format("%." .. Spinner.Decimals .. "f", AbsValue)
			or string.format("%d", AbsValue)
		local split = string.split(TextValue, ".")
		local whole, decimal = split[1], split[2]
		if not whole then
			return
		end

		local numWhole = #whole
		for i = 1, numWhole do
			local d = Spinner.Digits.Whole[i]

			if d then
				d.Duration = Spinner.Duration
				d.Value = tonumber(string.sub(whole, i, i))
			else
				d = DigitModule.new(SpinnerProxy, (i * 2) - 900, tonumber(string.sub(whole, i, i)))
				Spinner.Digits.Whole[i] = d
			end
		end
		for i = numWhole + 1, #Spinner.Digits.Whole do
			local d = Spinner.Digits.Whole[i]
			if d then
				d:Destroy()
				Spinner.Digits.Whole[i] = nil
			end
		end

		if Spinner.Commas then
			local endLayout = (numWhole * 2) - 900
			local str = string.format("%d", math.floor(math.abs(Spinner.Value)))
			local commaIndex = 0
			for i = 0, #str - 1, 3 do
				if i == 0 then
					continue
				end
				commaIndex += 1
				local CommaLabel = Spinner.CommaLabels[commaIndex]
				if not CommaLabel then
					CommaLabel = Instance.new("TextLabel")
					CommaLabel.Name = "Comma"
					CommaLabel.BackgroundTransparency = 1
					CommaLabel.Size = UDim2.new(0, 0, 1, 0)
					CommaLabel.Font = SpinnerProxy.Font
					CommaLabel.TextSize = SpinnerProxy.TextSize
					CommaLabel.TextColor3 = SpinnerProxy.TextColor3
					CommaLabel.Text = ","
					CommaLabel.AutomaticSize = Enum.AutomaticSize.X
					CommaLabel.Parent = Spinner.Frame

					Spinner.CommaLabels[commaIndex] = CommaLabel
				end

				CommaLabel.LayoutOrder = (endLayout - ((i - 1) * 2) - 1)
			end

			for i = commaIndex + 1, #Spinner.CommaLabels do
				Spinner.CommaLabels[i]:Destroy()
				Spinner.CommaLabels[i] = nil
			end
		end

		if not decimal then
			if Spinner.DecimalLabel then
				Spinner.DecimalLabel.Visible = false
			end
			for _, d in ipairs(Spinner.Digits.Decimal) do
				d:Destroy()
			end
			table.clear(Spinner.Digits.Decimal)
			return
		end

		if Spinner.DecimalLabel then
			Spinner.DecimalLabel.Visible = true
		end
		for i = 1, #decimal do
			local d = Spinner.Digits.Decimal[i]

			if d then
				d.Duration = Spinner.Duration
				d.Value = tonumber(string.sub(decimal, i, i))
			else
				d = DigitModule.new(SpinnerProxy, i, tonumber(string.sub(decimal, i, i)))
				Spinner.Digits.Decimal[i] = d
			end
		end
		for i = #decimal + 1, #Spinner.Digits.Decimal do
			local d = Spinner.Digits.Decimal[i]
			if d then
				d:Destroy()
				Spinner.Digits.Decimal[i] = nil
			end
		end
	end

	return SpinnerProxy, Spinner
end

function NumberSpinner.new()
	local Spinner, RawSpinner = newSpinner()

	local Frame = Instance.new("Frame")
	Frame.BackgroundTransparency = 1
	Frame.ClipsDescendants = true
	Frame.Size = UDim2.new(0, 200, 0, 50)
	Frame.Position = UDim2.new(0, 0, 0, 0)

	local Layout = Instance.new("UIListLayout")
	Layout.SortOrder = Enum.SortOrder.LayoutOrder
	Layout.FillDirection = Enum.FillDirection.Horizontal
	Layout.HorizontalAlignment = Enum.HorizontalAlignment.Center
	Layout.VerticalAlignment = Enum.VerticalAlignment.Center
	Layout.Padding = UDim.new(0, 0)
	Layout.Parent = Frame

	local Prefix = Instance.new("TextLabel")
	Prefix.Name = "Prefix"
	Prefix.LayoutOrder = -1000
	Prefix.BackgroundTransparency = 1
	Prefix.Size = UDim2.new(0, 0, 1, 0)
	Prefix.Font = Spinner.Font
	Prefix.TextSize = Spinner.TextSize
	Prefix.TextColor3 = Spinner.TextColor3
	Prefix.Text = Spinner.Prefix
	Prefix.AutomaticSize = Enum.AutomaticSize.X
	Prefix.Parent = Frame

	local Suffix = Instance.new("TextLabel")
	Suffix.Name = "Suffix"
	Suffix.LayoutOrder = 1000
	Suffix.BackgroundTransparency = 1
	Suffix.Size = UDim2.new(0, 0, 1, 0)
	Suffix.Font = Spinner.Font
	Suffix.TextSize = Spinner.TextSize
	Suffix.TextColor3 = Spinner.TextColor3
	Suffix.Text = Spinner.Suffix
	Suffix.AutomaticSize = Enum.AutomaticSize.X
	Suffix.Parent = Frame

	local Decimal = Instance.new("TextLabel")
	Decimal.Name = "Decimal"
	Decimal.LayoutOrder = 0
	Decimal.BackgroundTransparency = 1
	Decimal.Size = UDim2.new(0, 0, 1, 0)
	Decimal.Font = Spinner.Font
	Decimal.TextSize = Spinner.TextSize
	Decimal.TextColor3 = Spinner.TextColor3
	Decimal.Text = "."
	Decimal.AutomaticSize = Enum.AutomaticSize.X
	Decimal.Parent = Frame

	local Negative = Instance.new("TextLabel")
	Negative.Name = "Negative"
	Negative.LayoutOrder = -999
	Negative.BackgroundTransparency = 1
	Negative.Size = UDim2.new(0, 0, 1, 0)
	Negative.Font = Spinner.Font
	Negative.TextSize = Spinner.TextSize
	Negative.TextColor3 = Spinner.TextColor3
	Negative.Text = "-"
	Negative.AutomaticSize = Enum.AutomaticSize.X
	Negative.Parent = Frame

	RawSpinner.Frame = Frame
	RawSpinner.Layout = Layout
	RawSpinner.PrefixLabel = Prefix
	RawSpinner.SuffixLabel = Suffix
	RawSpinner.DecimalLabel = Decimal
	RawSpinner.NegativeLabel = Negative

	Spinner.GuiObject = Frame

	Spinner:Update()

	return Spinner
end

function NumberSpinner.fromGuiObject(GuiObject)
	if not typeof(GuiObject) == "Instance" then
		return
	end
	if not GuiObject:IsA("GuiObject") then
		return
	end

	local Spinner = NumberSpinner.new()

	Spinner.Name = "Spinner_" .. GuiObject.Name
	Spinner.SizeConstraint = GuiObject.SizeConstraint
	Spinner.Size = GuiObject.Size
	Spinner.Position = GuiObject.Position
	Spinner.AnchorPoint = GuiObject.AnchorPoint
	Spinner.Rotation = GuiObject.Rotation
	Spinner.LayoutOrder = GuiObject.LayoutOrder
	Spinner.ZIndex = GuiObject.ZIndex
	Spinner.Visible = GuiObject.Visible
	Spinner.BackgroundColor3 = GuiObject.BackgroundColor3
	Spinner.BorderColor3 = GuiObject.BorderColor3
	Spinner.BorderSizePixel = GuiObject.BorderSizePixel
	Spinner.BackgroundTransparency = GuiObject.BackgroundTransparency

	if GuiObject:IsA("TextLabel") or GuiObject:IsA("TextButton") or GuiObject:IsA("TextBox") then
		Spinner.Font = GuiObject.Font
		Spinner.TextSize = GuiObject.TextSize
		Spinner.TextColor3 = GuiObject.TextColor3
		Spinner.TextTransparency = GuiObject.TextTransparency
		Spinner.TextStrokeColor3 = GuiObject.TextStrokeColor3
		Spinner.TextStrokeTransparency = GuiObject.TextStrokeTransparency

		Spinner.Layout.HorizontalAlignment = TEXT_TO_LAYOUT[GuiObject.TextXAlignment]
	end

	Spinner.Parent = GuiObject.Parent

	GuiObject.Visible = false

	return Spinner
end

return NumberSpinner
