function Icon.set(O,a,s,z,i)local j=O._settingsDictionary[a]assert(j~=nil,("\115\101\116\116\105\110\103 \'\037\115\' \100\111\101\115 \110\111\116 \101\120\105\115\116"):format(a))if type(z)=="\115\116\114\105\110\103"then z=z:lower()end local m=O:get(a,z)if z=="\104\111\118\101\114\105\110\103"then j.hoveringValue=s if i~="\095\105\103\110\111\114\101\080\114\101\118\105\111\117\115"then j.additionalValues["\112\114\101\118\105\111\117\115\095"..z]=m end if type(i)=="\115\116\114\105\110\103"then j.additionalValues[i..("\095"..z)]=m end O:_update(a)else local R=z local S=j.type if S=="\116\111\103\103\108\101\097\098\108\101"then local a={}if R=="\100\101\115\101\108\101\099\116\101\100"or R=="\115\101\108\101\099\116\101\100"then table.insert(a,R)else table.insert(a,"\100\101\115\101\108\101\099\116\101\100")table.insert(a,"\115\101\108\101\099\116\101\100")R=nil end for a,z in pairs(a)do j.values[z]=s if i~="\095\105\103\110\111\114\101\080\114\101\118\105\111\117\115"then j.additionalValues["\112\114\101\118\105\111\117\115\095"..z]=m end if type(i)=="\115\116\114\105\110\103"then j.additionalValues[i..("\095"..z)]=m end end else j.value=s if type(i)=="\115\116\114\105\110\103"then if i~="\095\105\103\110\111\114\101\080\114\101\118\105\111\117\115"then j.additionalValues.previous=m end j.additionalValues[i]=m end end if m==s then return O,"\086\097\108\117\101 \119\097\115 \097\108\114\101\097\100\121 \115\101\116"end local f=O:getToggleState()if not O._updateAfterSettingAll and(j.instanceNames and(f==R or R==nil))then local s=a=="\105\099\111\110\083\105\122\101"and(m and m.X.Scale==1)local z=j.tweenAction and(not s and O:get(j.tweenAction))or TweenInfo.new(0)O:_update(a,f,z)end end if j.callMethods then for a,i in pairs(j.callMethods)do i(O,s,z)end end if j.callSignals then for a,s in pairs(j.callSignals)do s:Fire()end end return O end function Icon.get(i,a,s,z)local O=i._settingsDictionary[a]assert(O~=nil,("\115\101\116\116\105\110\103 \'\037\115\' \100\111\101\115 \110\111\116 \101\120\105\115\116"):format(a))local j,m if typeof(s)=="\115\116\114\105\110\103"then s=s:lower()end if s=="\104\111\118\101\114\105\110\103"and z==nil then j=O.hoveringValue m=type(z)=="\115\116\114\105\110\103"and O.additionalValues[z..("\095"..s)]end local R=O.type if R=="\116\111\103\103\108\101\097\098\108\101"then local a=(s=="\100\101\115\101\108\101\099\116\101\100"or s=="\115\101\108\101\099\116\101\100")and s or i:getToggleState()if m==nil then m=type(z)=="\115\116\114\105\110\103"and O.additionalValues[z..("\095"..a)]end if j==nil then j=O.values[a]end else if m==nil then m=type(z)=="\115\116\114\105\110\103"and O.additionalValues[z]end if j==nil then j=O.value end end return j,m end function Icon.getHovering(s,a)local z=s._settingsDictionary[a]assert(z~=nil,("\115\101\116\116\105\110\103 \'\037\115\' \100\111\101\115 \110\111\116 \101\120\105\115\116"):format(a))return z.hoveringValue end function Icon.getToggleState(s,a)a=a or s.isSelected return a and"\115\101\108\101\099\116\101\100"or"\100\101\115\101\108\101\099\116\101\100"end function Icon.getIconState(a)if a.hovering then return"\104\111\118\101\114\105\110\103"else return a:getToggleState()end end function Icon._update(i,a,s,z)local O=i._settingsDictionary[a]assert(O~=nil,("\115\101\116\116\105\110\103 \'\037\115\' \100\111\101\115 \110\111\116 \101\120\105\115\116"):format(a))s=s or i:getToggleState()local j=O.value or O.values and O.values[s]if i.hovering and O.hoveringValue then j=O.hoveringValue end if j==nil then return end local m=z or O.tweenAction and i:get(O.tweenAction)or i:get("\116\111\103\103\108\101\084\114\097\110\115\105\116\105\111\110\073\110\102\111")or TweenInfo.new(.15)local R=O.propertyName local S={string=true,NumberSequence=true;Text=true,EnumItem=true;ColorSequence=true}local f=i._uniqueSettingsDictionary[a]local T=j if O.useForcedGroupValue then T=O.forcedGroupValue end if O.instanceNames then for s,z in pairs(O.instanceNames)do local O=i.instances[z]local v=typeof(O[R])local N=S[v]if f then f(a,O,R,T)elseif N then O[R]=j else(tweenService:Create(O,m,{[R]=T})):Play()end if a=="\105\099\111\110\083\105\122\101"and O[R]~=T then i.updated:Fire()end end end end function Icon._updateAll(z,a,s)for i,O in pairs(z._settingsDictionary)do if O.instanceNames then z:_update(i,a,s)end end end function Icon._updateHovering(s,a)for z,i in pairs(s._settingsDictionary)do if i.instanceNames and i.hoveringValue~=nil then s:_update(z,nil,a)end end end function Icon._updateStateOverlay(z,a,s)local i=z.instances.iconOverlay i.BackgroundTransparency=a or 1 i.BackgroundColor3=s or Color3.new(1,1,1)end function Icon.setTheme(z,a,s)z._updateAfterSettingAll=s for a,s in pairs(a)do if a=="\116\111\103\103\108\101\097\098\108\101"then for a,s in pairs(s.deselected)do if not z.lockedSettings[a]then z:set(a,s,"\098\111\116\104")end end for a,s in pairs(s.selected)do if not z.lockedSettings[a]then z:set(a,s,"\115\101\108\101\099\116\101\100")end end else for a,s in pairs(s)do if not z.lockedSettings[a]then z:set(a,s)end end end end z._updateAfterSettingAll=nil if s then z:_updateAll()end return z end function Icon.setEnabled(s,a)s.enabled=a s.instances.iconContainer.Visible=a s.updated:Fire()return s end function Icon.setName(s,a)s.name=a s.instances.iconContainer.Name=a return s end function Icon.setProperty(z,a,s)z[a]=s return z end function Icon._playClickSound(a)local s=a.instances.clickSound if s.SoundId~=nil and(#s.SoundId>0 and s.Volume>0)then local a=s:Clone()a.Parent=s.Parent a:Play()debris:AddItem(a,s.TimeLength)end end function Icon.select(s,a)if s.locked then return s end s.isSelected=true s:_setToggleItemsVisible(true,a)s:_updateNotice()s:_updateAll()s:_playClickSound()if#s.dropdownIcons>0 or#s.menuIcons>0 then IconController:_updateSelectionGroup()end s.selected:Fire()s.toggled:Fire(s.isSelected)return s end function Icon.deselect(s,a)if s.locked then return s end s.isSelected=false s:_setToggleItemsVisible(false,a)s:_updateNotice()s:_updateAll()s:_playClickSound()if#s.dropdownIcons>0 or#s.menuIcons>0 then IconController:_updateSelectionGroup()end s.deselected:Fire()s.toggled:Fire(s.isSelected)return s end function Icon.notify(z,a,s)(coroutine.wrap(function()if not a then a=z.deselected end if z._parentIcon then z._parentIcon:notify(a)end local i=Signal.new()local O=z._endNotices:Connect(function()i:Fire()end)local j=a:Connect(function()i:Fire()end)s=s or httpService:GenerateGUID(true)z.notices[s]={completeSignal=i;clearNoticeEvent=a}z.totalNotices+=1 z:_updateNotice()z.notified:Fire(s)i:Wait()O:Disconnect()j:Disconnect()i:Disconnect()z.totalNotices-=1 z.notices[s]=nil z:_updateNotice()end))()return z end function Icon._updateNotice(a)local s=true if a.totalNotices<1 then s=false end if not a.isSelected then if(#a.dropdownIcons>0 or#a.menuIcons>0)and a.totalNotices>0 then s=true end end if a.isSelected then if#a.dropdownIcons>0 or#a.menuIcons>0 then s=false end end local z=s and 0 or 1 a:set("\110\111\116\105\099\101\073\109\097\103\101\084\114\097\110\115\112\097\114\101\110\099\121",z)a:set("\110\111\116\105\099\101\084\101\120\116\084\114\097\110\115\112\097\114\101\110\099\121",z)a.instances.noticeLabel.Text=a.totalNotices<100 and a.totalNotices or"\057\057\043"end function Icon.clearNotices(a)a._endNotices:Fire()return a end function Icon.disableStateOverlay(s,a)if a==nil then a=true end local z=s.instances.iconOverlay z.Visible=not a return s end

function Icon:set(settingName, value, iconState, setAdditional)
	local settingDetail = self._settingsDictionary[settingName]
	assert(settingDetail ~= nil, ("setting '%s' does not exist"):format(settingName))
	if type(iconState) == "string" then
		iconState = iconState:lower()
	end
	local previousValue = self:get(settingName, iconState)

	if iconState == "hovering" then
		-- Apply hovering state if valid
		settingDetail.hoveringValue = value
		if setAdditional ~= "_ignorePrevious" then
			settingDetail.additionalValues["previous_"..iconState] = previousValue
		end
		if type(setAdditional) == "string" then
			settingDetail.additionalValues[setAdditional.."_"..iconState] = previousValue
		end
		self:_update(settingName)

	else
		-- Update the settings value
		local toggleState = iconState
		local settingType = settingDetail.type
		if settingType == "toggleable" then
			local valuesToSet = {}
			if toggleState == "deselected" or toggleState == "selected" then
				table.insert(valuesToSet, toggleState)
			else
				table.insert(valuesToSet, "deselected")
				table.insert(valuesToSet, "selected")
				toggleState = nil
			end
			for i, v in pairs(valuesToSet) do
				settingDetail.values[v] = value
				if setAdditional ~= "_ignorePrevious" then
					settingDetail.additionalValues["previous_"..v] = previousValue
				end
				if type(setAdditional) == "string" then
					settingDetail.additionalValues[setAdditional.."_"..v] = previousValue
				end
			end
		else
			settingDetail.value = value
			if type(setAdditional) == "string" then
				if setAdditional ~= "_ignorePrevious" then
					settingDetail.additionalValues["previous"] = previousValue
				end
				settingDetail.additionalValues[setAdditional] = previousValue
			end
		end

		-- Check previous and new are not the same
		if previousValue == value then
			return self, "Value was already set"
		end

		-- Update appearances of associated instances
		local currentToggleState = self:getToggleState()
		if not self._updateAfterSettingAll and settingDetail.instanceNames and (currentToggleState == toggleState or toggleState == nil) then
			local ignoreTweenAction = (settingName == "iconSize" and previousValue and previousValue.X.Scale == 1)
			local tweenInfo = (settingDetail.tweenAction and not ignoreTweenAction and self:get(settingDetail.tweenAction)) or TweenInfo.new(0)
			self:_update(settingName, currentToggleState, tweenInfo)
		end
	end

	-- Call any methods present
	if settingDetail.callMethods then
		for _, callMethod in pairs(settingDetail.callMethods) do
			callMethod(self, value, iconState)
		end
	end
	
	-- Call any signals present
	if settingDetail.callSignals then
		for _, callSignal in pairs(settingDetail.callSignals) do
			callSignal:Fire()
		end
	end
	return self
end

function Icon:get(settingName, iconState, getAdditional)
	local settingDetail = self._settingsDictionary[settingName]
	assert(settingDetail ~= nil, ("setting '%s' does not exist"):format(settingName))
	local valueToReturn, additionalValueToReturn
	if typeof(iconState) == "string" then
		iconState = iconState:lower()
	end

	--if ((self.hovering and settingDetail.hoveringValue) or iconState == "hovering") and getAdditional == nil then
	if (iconState == "hovering") and getAdditional == nil then
		valueToReturn = settingDetail.hoveringValue
		additionalValueToReturn = type(getAdditional) == "string" and settingDetail.additionalValues[getAdditional.."_"..iconState]
	end

	local settingType = settingDetail.type
	if settingType == "toggleable" then
		local toggleState = ((iconState == "deselected" or iconState == "selected") and iconState) or self:getToggleState()
		if additionalValueToReturn == nil then
			additionalValueToReturn = type(getAdditional) == "string" and settingDetail.additionalValues[getAdditional.."_"..toggleState]
		end
		if valueToReturn == nil then
			valueToReturn = settingDetail.values[toggleState]
		end
	
	else
		if additionalValueToReturn == nil then
			additionalValueToReturn = type(getAdditional) == "string" and settingDetail.additionalValues[getAdditional]
		end
		if valueToReturn == nil then
			valueToReturn = settingDetail.value
		end
	end

	return valueToReturn, additionalValueToReturn
end

function Icon:getHovering(settingName)
	local settingDetail = self._settingsDictionary[settingName]
	assert(settingDetail ~= nil, ("setting '%s' does not exist"):format(settingName))
	return settingDetail.hoveringValue
end

function Icon:getToggleState(isSelected)
	isSelected = isSelected or self.isSelected
	return (isSelected and "selected") or "deselected"
end

function Icon:getIconState()
	if self.hovering then
		return "hovering"
	else
		return self:getToggleState()
	end
end

function Icon:_update(settingName, toggleState, customTweenInfo)
	local settingDetail = self._settingsDictionary[settingName]
	assert(settingDetail ~= nil, ("setting '%s' does not exist"):format(settingName))
	toggleState = toggleState or self:getToggleState()
	local value = settingDetail.value or (settingDetail.values and settingDetail.values[toggleState])
	if self.hovering and settingDetail.hoveringValue then
		value = settingDetail.hoveringValue
	end
	if value == nil then return end
	local tweenInfo = customTweenInfo or (settingDetail.tweenAction and self:get(settingDetail.tweenAction)) or self:get("toggleTransitionInfo") or TweenInfo.new(0.15)
	local propertyName = settingDetail.propertyName
	local invalidPropertiesTypes = {
		["string"] = true,
		["NumberSequence"] = true,
		["Text"] = true,
		["EnumItem"] = true,
		["ColorSequence"] = true,
	}
	local uniqueSetting = self._uniqueSettingsDictionary[settingName]
	local newValue = value
	if settingDetail.useForcedGroupValue then
		newValue = settingDetail.forcedGroupValue
	end
	if settingDetail.instanceNames then
		for _, instanceName in pairs(settingDetail.instanceNames) do
			local instance = self.instances[instanceName]
			local propertyType = typeof(instance[propertyName])
			local cannotTweenProperty = invalidPropertiesTypes[propertyType]
			if uniqueSetting then
				uniqueSetting(settingName, instance, propertyName, newValue)
			elseif cannotTweenProperty then
				instance[propertyName] = value
			else
				tweenService:Create(instance, tweenInfo, {[propertyName] = newValue}):Play()
			end
			--
			if settingName == "iconSize" and instance[propertyName] ~= newValue then
				self.updated:Fire()
			end
			--
		end
	end
end

function Icon:_updateAll(iconState, customTweenInfo)
	for settingName, settingDetail in pairs(self._settingsDictionary) do
		if settingDetail.instanceNames then
			self:_update(settingName, iconState, customTweenInfo)
		end
	end
end

function Icon:_updateHovering(customTweenInfo)
	for settingName, settingDetail in pairs(self._settingsDictionary) do
		if settingDetail.instanceNames and settingDetail.hoveringValue ~= nil then
			self:_update(settingName, nil, customTweenInfo)
		end
	end
end

function Icon:_updateStateOverlay(transparency, color)
	local stateOverlay = self.instances.iconOverlay
	stateOverlay.BackgroundTransparency = transparency or 1
	stateOverlay.BackgroundColor3 = color or Color3.new(1, 1, 1)
end

function Icon:setTheme(theme, updateAfterSettingAll)
	self._updateAfterSettingAll = updateAfterSettingAll
	for settingsType, settingsDetails in pairs(theme) do
		if settingsType == "toggleable" then
			for settingName, settingValue in pairs(settingsDetails.deselected) do
				if not self.lockedSettings[settingName] then
					self:set(settingName, settingValue, "both")
				end
			end
			for settingName, settingValue in pairs(settingsDetails.selected) do
				if not self.lockedSettings[settingName] then
					self:set(settingName, settingValue, "selected")
				end
			end
		else
			for settingName, settingValue in pairs(settingsDetails) do
				if not self.lockedSettings[settingName] then
					self:set(settingName, settingValue)
				end
			end
		end
	end
	self._updateAfterSettingAll = nil
	if updateAfterSettingAll then
		self:_updateAll()
	end
	return self
end

function Icon:setEnabled(bool)
	self.enabled = bool
	self.instances.iconContainer.Visible = bool
	self.updated:Fire()
	return self
end

function Icon:setName(string)
	self.name = string
	self.instances.iconContainer.Name = string
	return self
end

function Icon:setProperty(propertyName, value)
	self[propertyName] = value
	return self
end

function Icon:_playClickSound()
	local clickSound = self.instances.clickSound
	if clickSound.SoundId ~= nil and #clickSound.SoundId > 0 and clickSound.Volume > 0 then
		local clickSoundCopy = clickSound:Clone()
		clickSoundCopy.Parent = clickSound.Parent
		clickSoundCopy:Play()
		debris:AddItem(clickSoundCopy, clickSound.TimeLength)
	end
end

function Icon:select(byIcon)
	if self.locked then return self end
	self.isSelected = true
	self:_setToggleItemsVisible(true, byIcon)
	self:_updateNotice()
	self:_updateAll()
	self:_playClickSound()
	if #self.dropdownIcons > 0 or #self.menuIcons > 0 then
		IconController:_updateSelectionGroup()
	end
    self.selected:Fire()
    self.toggled:Fire(self.isSelected)
	return self
end

function Icon:deselect(byIcon)
	if self.locked then return self end
	self.isSelected = false
	self:_setToggleItemsVisible(false, byIcon)
	self:_updateNotice()
	self:_updateAll()
	self:_playClickSound()
	if #self.dropdownIcons > 0 or #self.menuIcons > 0 then
		IconController:_updateSelectionGroup()
	end
    self.deselected:Fire()
    self.toggled:Fire(self.isSelected)
	return self
end

function Icon:notify(clearNoticeEvent, noticeId)
	coroutine.wrap(function()
		if not clearNoticeEvent then
			clearNoticeEvent = self.deselected
		end
		if self._parentIcon then
			self._parentIcon:notify(clearNoticeEvent)
		end
		
		local notifComplete = Signal.new()
		local endEvent = self._endNotices:Connect(function()
			notifComplete:Fire()
		end)
		local customEvent = clearNoticeEvent:Connect(function()
			notifComplete:Fire()
		end)
		
		noticeId = noticeId or httpService:GenerateGUID(true)
		self.notices[noticeId] = {
			completeSignal = notifComplete,
			clearNoticeEvent = clearNoticeEvent,
		}
		self.totalNotices += 1
		self:_updateNotice()

		self.notified:Fire(noticeId)
		notifComplete:Wait()
		
		endEvent:Disconnect()
		customEvent:Disconnect()
		notifComplete:Disconnect()
		
		self.totalNotices -= 1
		self.notices[noticeId] = nil
		self:_updateNotice()
	end)()
	return self
end

function Icon:_updateNotice()
	local enabled = true
	if self.totalNotices < 1 then
		enabled = false
	end
	-- Deselect
	if not self.isSelected then
		if (#self.dropdownIcons > 0 or #self.menuIcons > 0) and self.totalNotices > 0 then
			enabled = true
		end
	end
	-- Select
	if self.isSelected then
		if #self.dropdownIcons > 0 or #self.menuIcons > 0 then
			enabled = false
		end
	end
	local value = (enabled and 0) or 1
	self:set("noticeImageTransparency", value)
	self:set("noticeTextTransparency", value)
	self.instances.noticeLabel.Text = (self.totalNotices < 100 and self.totalNotices) or "99+"
end

function Icon:clearNotices()
	self._endNotices:Fire()
	return self
end

function Icon:disableStateOverlay(bool)
	if bool == nil then
		bool = true
	end
	local stateOverlay = self.instances.iconOverlay
	stateOverlay.Visible = not bool
	return self
end


