local function j(j)local H={}for j,A in pairs(j)do H[j]=A end return H end local H={}local A={eDestroyed=true,eSaidMessage=true;eReceivedMessage=true;eReceivedUnfilteredMessage=true,eMessageDoneFiltering=true,eReceivedSystemMessage=true,eChannelJoined=true;eChannelLeft=true,eMuted=true;eUnmuted=true;eExtraDataUpdated=true,eMainChannelSet=true;eChannelNameColorUpdated=true}local M={Destroyed="\101\068\101\115\116\114\111\121\101\100",SaidMessage="\101\083\097\105\100\077\101\115\115\097\103\101",ReceivedMessage="\101\082\101\099\101\105\118\101\100\077\101\115\115\097\103\101",ReceivedUnfilteredMessage="\101\082\101\099\101\105\118\101\100\085\110\102\105\108\116\101\114\101\100\077\101\115\115\097\103\101";RecievedUnfilteredMessage="\101\082\101\099\101\105\118\101\100\085\110\102\105\108\116\101\114\101\100\077\101\115\115\097\103\101";MessageDoneFiltering="\101\077\101\115\115\097\103\101\068\111\110\101\070\105\108\116\101\114\105\110\103";ReceivedSystemMessage="\101\082\101\099\101\105\118\101\100\083\121\115\116\101\109\077\101\115\115\097\103\101",ChannelJoined="\101\067\104\097\110\110\101\108\074\111\105\110\101\100";ChannelLeft="\101\067\104\097\110\110\101\108\076\101\102\116";Muted="\101\077\117\116\101\100",Unmuted="\101\085\110\109\117\116\101\100",ExtraDataUpdated="\101\069\120\116\114\097\068\097\116\097\085\112\100\097\116\101\100";MainChannelSet="\101\077\097\105\110\067\104\097\110\110\101\108\083\101\116",ChannelNameColorUpdated="\101\067\104\097\110\110\101\108\078\097\109\101\067\111\108\111\114\085\112\100\097\116\101\100"}H.__index=function(j,l)local L=rawget(H,l)if L then return L end if A[l]and not rawget(j,l)then rawset(j,l,Instance.new("\066\105\110\100\097\098\108\101\069\118\101\110\116"))end local E=M[l]if E and not rawget(j,l)then if not rawget(j,E)then rawset(j,E,Instance.new("\066\105\110\100\097\098\108\101\069\118\101\110\116"))end rawset(j,l,(rawget(j,E)).Event)end return rawget(j,l)end function H.LazyFire(H,j,...)local A=rawget(H,j)if A then A:Fire(...)end end function H.SayMessage(M,j,H,A)if M.ChatService:InternalDoProcessCommands(M.Name,j,H)then return end if not H then return end local l=M.Channels[H:lower()]if not l then error("\083\112\101\097\107\101\114 \105\115 \110\111\116 \105\110 \099\104\097\110\110\101\108 \""..(H.."\""))end local L=l:InternalPostMessage(M,j,A)if L then local j,A=pcall(function()M:LazyFire("\101\083\097\105\100\077\101\115\115\097\103\101",L,H)end)if not j and A then print("\069\114\114\111\114 \115\097\121\105\110\103 \109\101\115\115\097\103\101\058 "..A)end end return L end function H.JoinChannel(H,j)if H.Channels[j:lower()]then warn("\083\112\101\097\107\101\114 \105\115 \097\108\114\101\097\100\121 \105\110 \099\104\097\110\110\101\108 \""..(j.."\""))return end local A=H.ChatService:GetChannel(j)if not A then error("\067\104\097\110\110\101\108 \""..(j.."\" \100\111\101\115 \110\111\116 \101\120\105\115\116\033"))end H.Channels[j:lower()]=A A:InternalAddSpeaker(H)local M,l=pcall(function()H.eChannelJoined:Fire(A.Name,A:GetWelcomeMessageForSpeaker(H))end)if not M and l then print("\069\114\114\111\114 \106\111\105\110\105\110\103 \099\104\097\110\110\101\108\058 "..l)end end function H.LeaveChannel(H,j)if not H.Channels[j:lower()]then warn("\083\112\101\097\107\101\114 \105\115 \110\111\116 \105\110 \099\104\097\110\110\101\108 \""..(j.."\""))return end local A=H.Channels[j:lower()]H.Channels[j:lower()]=nil A:InternalRemoveSpeaker(H)local M,l=pcall(function()H:LazyFire("\101\067\104\097\110\110\101\108\076\101\102\116",A.Name)if H.PlayerObj then H.EventFolder.OnChannelLeft:FireClient(H.PlayerObj,A.Name)end end)if not M and l then print("\069\114\114\111\114 \108\101\097\118\105\110\103 \099\104\097\110\110\101\108\058 "..l)end end function H.IsInChannel(H,j)return H.Channels[j:lower()]~=nil end function H.GetChannelList(j)local H={}for j,A in pairs(j.Channels)do table.insert(H,A.Name)end return H end function H.SendMessage(l,j,H,A,M)local L=l.Channels[H:lower()]if L then L:SendMessageToSpeaker(j,l.Name,A,M)else warn(string.format("\083\112\101\097\107\101\114 \'\037\115\' \105\115 \110\111\116 \105\110 \099\104\097\110\110\101\108 \'\037\115\' \097\110\100 \099\097\110\110\111\116 \114\101\099\101\105\118\101 \097 \109\101\115\115\097\103\101 \105\110 \105\116\046",l.Name,H))end end function H.SendSystemMessage(M,j,H,A)local l=M.Channels[H:lower()]if l then l:SendSystemMessageToSpeaker(j,M.Name,A)else warn(string.format("\083\112\101\097\107\101\114 \'\037\115\' \105\115 \110\111\116 \105\110 \099\104\097\110\110\101\108 \'\037\115\' \097\110\100 \099\097\110\110\111\116 \114\101\099\101\105\118\101 \097 \115\121\115\116\101\109 \109\101\115\115\097\103\101 \105\110 \105\116\046",M.Name,H))end end function H.GetPlayer(j)return j.PlayerObj end function H.SetExtraData(A,j,H)A.ExtraData[j]=H A:LazyFire("\101\069\120\116\114\097\068\097\116\097\085\112\100\097\116\101\100",j,H)end function H.GetExtraData(H,j)return H.ExtraData[j]end function H.SetMainChannel(H,j)local A,M=pcall(function()H:LazyFire("\101\077\097\105\110\067\104\097\110\110\101\108\083\101\116",j)if H.PlayerObj then H.EventFolder.OnMainChannelSet:FireClient(H.PlayerObj,j)end end)if not A and M then print("\069\114\114\111\114 \115\101\116\116\105\110\103 \109\097\105\110 \099\104\097\110\110\101\108\058 "..M)end end

local function ShallowCopy(table)
	local copy = {}
	for i, v in pairs(table) do
		copy[i] = v
	end
	return copy
end

local methods = {}

local lazyEventNames =
{
    eDestroyed = true,
	eSaidMessage = true,
	eReceivedMessage = true,
	eReceivedUnfilteredMessage = true,
	eMessageDoneFiltering = true,
	eReceivedSystemMessage = true,
	eChannelJoined = true,
	eChannelLeft = true,
	eMuted = true,
	eUnmuted = true,
	eExtraDataUpdated = true,
	eMainChannelSet = true,
	eChannelNameColorUpdated = true,
}
local lazySignalNames =
{
	Destroyed = "eDestroyed",
	SaidMessage = "eSaidMessage",
	ReceivedMessage = "eReceivedMessage",
	ReceivedUnfilteredMessage = "eReceivedUnfilteredMessage",
    RecievedUnfilteredMessage = "eReceivedUnfilteredMessage", -- legacy mispelling
	MessageDoneFiltering = "eMessageDoneFiltering",
	ReceivedSystemMessage = "eReceivedSystemMessage",
	ChannelJoined = "eChannelJoined",
	ChannelLeft = "eChannelLeft",
	Muted = "eMuted",
	Unmuted = "eUnmuted",
	ExtraDataUpdated = "eExtraDataUpdated",
	MainChannelSet = "eMainChannelSet",
	ChannelNameColorUpdated = "eChannelNameColorUpdated"
}

methods.__index = function (self, k)
	local fromMethods = rawget(methods, k)
	if fromMethods then return fromMethods end

    if lazyEventNames[k] and not rawget(self, k) then
        rawset(self, k, Instance.new("BindableEvent"))
    end
    local lazySignalEventName = lazySignalNames[k]
    if lazySignalEventName and not rawget(self, k) then
        if not rawget(self, lazySignalEventName) then
            rawset(self, lazySignalEventName, Instance.new("BindableEvent"))
        end
        rawset(self, k, rawget(self, lazySignalEventName).Event)
    end
    return rawget(self, k)
end

function methods:LazyFire(eventName, ...)
	local createdEvent = rawget(self, eventName)
	if createdEvent then
		createdEvent:Fire(...)
	end
end

function methods:SayMessage(message, channelName, extraData)
	if (self.ChatService:InternalDoProcessCommands(self.Name, message, channelName)) then return end
	if (not channelName) then return end

	local channel = self.Channels[channelName:lower()]
	if (not channel) then
		error("Speaker is not in channel \"" .. channelName .. "\"")
	end

	local messageObj = channel:InternalPostMessage(self, message, extraData)
	if (messageObj) then
		local success, err = pcall(function() self:LazyFire("eSaidMessage", messageObj, channelName) end)
		if not success and err then
			print("Error saying message: " ..err)
		end
	end

	return messageObj
end

function methods:JoinChannel(channelName)
	if (self.Channels[channelName:lower()]) then
		warn("Speaker is already in channel \"" .. channelName .. "\"")
		return
	end

	local channel = self.ChatService:GetChannel(channelName)
	if (not channel) then
		error("Channel \"" .. channelName .. "\" does not exist!")
	end

	self.Channels[channelName:lower()] = channel
	channel:InternalAddSpeaker(self)
	local success, err = pcall(function()
		self.eChannelJoined:Fire(channel.Name, channel:GetWelcomeMessageForSpeaker(self))
	end)
	if not success and err then
		print("Error joining channel: " ..err)
	end
end

function methods:LeaveChannel(channelName)
	if (not self.Channels[channelName:lower()]) then
		warn("Speaker is not in channel \"" .. channelName .. "\"")
		return
	end

	local channel = self.Channels[channelName:lower()]

	self.Channels[channelName:lower()] = nil
	channel:InternalRemoveSpeaker(self)
	local success, err = pcall(function()
		self:LazyFire("eChannelLeft", channel.Name)
		if self.PlayerObj then
			self.EventFolder.OnChannelLeft:FireClient(self.PlayerObj, channel.Name)
		end
	end)
	if not success and err then
		print("Error leaving channel: " ..err)
	end
end

function methods:IsInChannel(channelName)
	return (self.Channels[channelName:lower()] ~= nil)
end

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

function methods:SendMessage(message, channelName, fromSpeaker, extraData)
	local channel = self.Channels[channelName:lower()]
	if (channel) then
		channel:SendMessageToSpeaker(message, self.Name, fromSpeaker, extraData)

	else
		warn(string.format("Speaker '%s' is not in channel '%s' and cannot receive a message in it.", self.Name, channelName))

	end
end

function methods:SendSystemMessage(message, channelName, extraData)
	local channel = self.Channels[channelName:lower()]
	if (channel) then
		channel:SendSystemMessageToSpeaker(message, self.Name, extraData)

	else
		warn(string.format("Speaker '%s' is not in channel '%s' and cannot receive a system message in it.", self.Name, channelName))

	end
end

function methods:GetPlayer()
	return self.PlayerObj
end

function methods:SetExtraData(key, value)
	self.ExtraData[key] = value
	self:LazyFire("eExtraDataUpdated", key, value)
end

function methods:GetExtraData(key)
	return self.ExtraData[key]
end

function methods:SetMainChannel(channelName)
	local success, err = pcall(function()
		self:LazyFire("eMainChannelSet", channelName)
		if self.PlayerObj then
			self.EventFolder.OnMainChannelSet:FireClient(self.PlayerObj, channelName)
		end
	end)
	if not success and err then
		print("Error setting main channel: " ..err)
	end
end
