local Y={}Y.__index=Y function Y.AddChannel(b,Y)if b.ChatChannels[Y:lower()]then error(string.format("\067\104\097\110\110\101\108 \037\113 \097\108\114\097\100\121 \101\120\105\115\116\115\046",Y))end local function e(e,s)if s:lower()=="\047\108\101\097\118\101"then local s=b:GetChannel(Y)local C=b:GetSpeaker(e)if s and C then if s.Leavable then C:LeaveChannel(Y)C:SendSystemMessage(string.format("\089\111\117 \104\097\118\101 \108\101\102\116 \099\104\097\110\110\101\108 \'\037\115\'",Y),"\083\121\115\116\101\109")else C:SendSystemMessage("\089\111\117 \099\097\110\110\111\116 \108\101\097\118\101 \116\104\105\115 \099\104\097\110\110\101\108\046",Y)end end return true end return false end local s=ChatChannel.new(b,Y)b.ChatChannels[Y:lower()]=s s:RegisterProcessCommandsFunction("\100\101\102\097\117\108\116\095\099\111\109\109\097\110\100\115",e,ChatConstants.HighPriority)local C,V=pcall(function()b.eChannelAdded:Fire(Y)end)if not C and V then print("\069\114\114\111\114 \097\100\100\100\105\110\103 \099\104\097\110\110\101\108\058 "..V)end return s end function Y.RemoveChannel(b,Y)if b.ChatChannels[Y:lower()]then local e=b.ChatChannels[Y:lower()].Name b.ChatChannels[Y:lower()]:InternalDestroy()b.ChatChannels[Y:lower()]=nil local s,C=pcall(function()b.eChannelRemoved:Fire(e)end)if not s and C then print("\069\114\114\111\114 \114\101\109\111\118\105\110\103 \099\104\097\110\110\101\108\058 "..C)end else warn(string.format("\067\104\097\110\110\101\108 \037\113 \100\111\101\115 \110\111\116 \101\120\105\115\116\046",Y))end end function Y.GetChannel(b,Y)return b.ChatChannels[Y:lower()]end function Y.AddSpeaker(b,Y)if b.Speakers[Y:lower()]then error("\083\112\101\097\107\101\114 \""..(Y.."\" \097\108\114\101\097\100\121 \101\120\105\115\116\115\033"))end local e=Speaker.new(b,Y)b.Speakers[Y:lower()]=e local s,C=pcall(function()b.eSpeakerAdded:Fire(Y)end)if not s and C then print("\069\114\114\111\114 \097\100\100\105\110\103 \115\112\101\097\107\101\114\058 "..C)end return e end function Y.InternalUnmuteSpeaker(b,Y)for b,e in pairs(b.ChatChannels)do if e:IsSpeakerMuted(Y)then e:UnmuteSpeaker(Y)end end end function Y.RemoveSpeaker(b,Y)if b.Speakers[Y:lower()]then local e=b.Speakers[Y:lower()].Name b:InternalUnmuteSpeaker(e)b.Speakers[Y:lower()]:InternalDestroy()b.Speakers[Y:lower()]=nil local s,C=pcall(function()b.eSpeakerRemoved:Fire(e)end)if not s and C then print("\069\114\114\111\114 \114\101\109\111\118\105\110\103 \115\112\101\097\107\101\114\058 "..C)end else warn("\083\112\101\097\107\101\114 \""..(Y.."\" \100\111\101\115 \110\111\116 \101\120\105\115\116\033"))end end function Y.GetSpeaker(b,Y)return b.Speakers[Y:lower()]end function Y.GetChannelList(Y)local b={}for Y,e in pairs(Y.ChatChannels)do if not e.Private then table.insert(b,e.Name)end end return b end function Y.GetAutoJoinChannelList(Y)local b={}for Y,e in pairs(Y.ChatChannels)do if e.AutoJoin then table.insert(b,e)end end return b end function Y.GetSpeakerList(Y)local b={}for Y,e in pairs(Y.Speakers)do table.insert(b,e.Name)end return b end function Y.SendGlobalSystemMessage(b,Y)for b,e in pairs(b.Speakers)do e:SendSystemMessage(Y,nil)end end function Y.RegisterFilterMessageFunction(s,Y,b,e)s.FilterMessageFunctions:AddFunction(Y,b,e)end function Y.UnregisterFilterMessageFunction(b,Y)b.FilterMessageFunctions:RemoveFunction(Y)end function Y.RegisterProcessCommandsFunction(s,Y,b,e)s.ProcessCommandsFunctions:AddFunction(Y,b,e)end function Y.UnregisterProcessCommandsFunction(b,Y)b.ProcessCommandsFunctions:RemoveFunction(Y)end local b=0 local e=0 local s=0 function Y.InternalNotifyFilterIssue(Y)if tick()-e>FILTER_THRESHOLD_TIME then s=0 end s=s+1 e=tick()if s>=FILTER_NOTIFCATION_THRESHOLD then if tick()-b>FILTER_NOTIFCATION_INTERVAL then b=tick()local e=Y:GetChannel("\083\121\115\116\101\109")if e then e:SendSystemMessage("\084\104\101 \099\104\097\116 \102\105\108\116\101\114 \105\115 \099\117\114\114\101\110\116\108\121 \101\120\112\101\114\105\101\110\099\105\110\103 \105\115\115\117\101\115 \097\110\100 \109\101\115\115\097\103\101\115 \109\097\121 \098\101 \115\108\111\119 \116\111 \097\112\112\101\097\114\046",errorExtraData)end end end end local C={}

local methods = {}
methods.__index = methods

function methods:AddChannel(channelName)
	if (self.ChatChannels[channelName:lower()]) then
		error(string.format("Channel %q alrady exists.", channelName))
	end

	local function DefaultChannelCommands(fromSpeaker, message)
		if (message:lower() == "/leave") then
			local channel = self:GetChannel(channelName)
			local speaker = self:GetSpeaker(fromSpeaker)
			if (channel and speaker) then
				if (channel.Leavable) then
					speaker:LeaveChannel(channelName)
					speaker:SendSystemMessage(string.format("You have left channel '%s'", channelName), "System")
				else
					speaker:SendSystemMessage("You cannot leave this channel.", channelName)
				end
			end

			return true
		end
		return false
	end


	local channel = ChatChannel.new(self, channelName)
	self.ChatChannels[channelName:lower()] = channel

	channel:RegisterProcessCommandsFunction("default_commands", DefaultChannelCommands, ChatConstants.HighPriority)

	local success, err = pcall(function() self.eChannelAdded:Fire(channelName) end)
	if not success and err then
		print("Error addding channel: " ..err)
	end

	return channel
end

function methods:RemoveChannel(channelName)
	if (self.ChatChannels[channelName:lower()]) then
		local n = self.ChatChannels[channelName:lower()].Name

		self.ChatChannels[channelName:lower()]:InternalDestroy()
		self.ChatChannels[channelName:lower()] = nil

		local success, err = pcall(function() self.eChannelRemoved:Fire(n) end)
		if not success and err then
			print("Error removing channel: " ..err)
		end
	else
		warn(string.format("Channel %q does not exist.", channelName))
	end
end

function methods:GetChannel(channelName)
	return self.ChatChannels[channelName:lower()]
end


function methods:AddSpeaker(speakerName)
	if (self.Speakers[speakerName:lower()]) then
		error("Speaker \"" .. speakerName .. "\" already exists!")
	end

	local speaker = Speaker.new(self, speakerName)
	self.Speakers[speakerName:lower()] = speaker

	local success, err = pcall(function() self.eSpeakerAdded:Fire(speakerName) end)
	if not success and err then
		print("Error adding speaker: " ..err)
	end

	return speaker
end

function methods:InternalUnmuteSpeaker(speakerName)
	for channelName, channel in pairs(self.ChatChannels) do
		if channel:IsSpeakerMuted(speakerName) then
			channel:UnmuteSpeaker(speakerName)
		end
	end
end

function methods:RemoveSpeaker(speakerName)
	if (self.Speakers[speakerName:lower()]) then
		local n = self.Speakers[speakerName:lower()].Name
		self:InternalUnmuteSpeaker(n)

		self.Speakers[speakerName:lower()]:InternalDestroy()
		self.Speakers[speakerName:lower()] = nil

		local success, err = pcall(function() self.eSpeakerRemoved:Fire(n) end)
		if not success and err then
			print("Error removing speaker: " ..err)
		end

	else
		warn("Speaker \"" .. speakerName .. "\" does not exist!")
	end
end

function methods:GetSpeaker(speakerName)
	return self.Speakers[speakerName:lower()]
end

function methods:GetChannelList()
	local list = {}
	for i, channel in pairs(self.ChatChannels) do
		if (not channel.Private) then
			table.insert(list, channel.Name)
		end
	end
	return list
end

function methods:GetAutoJoinChannelList()
	local list = {}
	for i, channel in pairs(self.ChatChannels) do
		if channel.AutoJoin then
			table.insert(list, channel)
		end
	end
	return list
end

function methods:GetSpeakerList()
	local list = {}
	for i, speaker in pairs(self.Speakers) do
		table.insert(list, speaker.Name)
	end
	return list
end

function methods:SendGlobalSystemMessage(message)
	for i, speaker in pairs(self.Speakers) do
		speaker:SendSystemMessage(message, nil)
	end
end

function methods:RegisterFilterMessageFunction(funcId, func, priority)
	self.FilterMessageFunctions:AddFunction(funcId, func, priority)
end

function methods:UnregisterFilterMessageFunction(funcId)
	self.FilterMessageFunctions:RemoveFunction(funcId)
end

function methods:RegisterProcessCommandsFunction(funcId, func, priority)
	self.ProcessCommandsFunctions:AddFunction(funcId, func, priority)
end

function methods:UnregisterProcessCommandsFunction(funcId)
	self.ProcessCommandsFunctions:RemoveFunction(funcId)
end

local LastFilterNoficationTime = 0
local LastFilterIssueTime = 0
local FilterIssueCount = 0
function methods:InternalNotifyFilterIssue()
	if (tick() - LastFilterIssueTime) > FILTER_THRESHOLD_TIME then
		FilterIssueCount = 0
	end
	FilterIssueCount = FilterIssueCount + 1
	LastFilterIssueTime = tick()
	if FilterIssueCount >= FILTER_NOTIFCATION_THRESHOLD then
		if (tick() - LastFilterNoficationTime) > FILTER_NOTIFCATION_INTERVAL then
			LastFilterNoficationTime = tick()
			local systemChannel = self:GetChannel("System")
			if systemChannel then
				systemChannel:SendSystemMessage("The chat filter is currently experiencing issues and messages may be slow to appear.", errorExtraData)
			end
		end
	end
end

local StudioMessageFilteredCache = {}
