local m=require(script.Parent.RemoteEventClient)local q=require(script.Parent.RemoteFunctionClient)local x={}x.__index=x function x._new(L,E)assert(not E:getClient(L),string.format("\037\115 \105\115 \097\108\114\101\097\100\121 \097 \099\108\105\101\110\116",tostring(L)))local A=setmetatable({},x)A._server=E A.id=L A.connected=true A._remoteEvents={}A._remoteFunctions={}A._server._clients[L]=A for q in pairs(A._server._remoteEvents)do m._new(q,A._server,A)end for m in pairs(A._server._remoteFunctions)do q._new(m,A._server,A)end A._server.clientConnected:fire(A)return A end function x.getRemoteEvent(q,m)assert(q._remoteEvents[m],string.format("\037\115 \105\115 \110\111\116 \097 \118\097\108\105\100 \082\101\109\111\116\101\069\118\101\110\116",m))return q._remoteEvents[m]end function x.getRemoteFunction(q,m)assert(q._remoteFunctions[m],string.format("\037\115 \105\115 \110\111\116 \097 \118\097\108\105\100 \082\101\109\111\116\101\070\117\110\099\116\105\111\110",m))return q._remoteFunctions[m]end function x.disconnect(m)m.connected=false m._server.clientDisconnecting:fire(m)for m,q in pairs(m._remoteEvents)do q:destroy()end for m,q in pairs(m._remoteFunctions)do q:destroy()end m._server._clients[m.id]=nil end function x.mapRemoteEvents(q,m)local x={}if m then for q,L in q._remoteEvents do local E,A=m(q,L)x[E]=A end else for m,q in q._remoteEvents do x[m]=q end end return x end function x.mapRemoteFunctions(q,m)local x={}if m then for q,L in q._remoteFunctions do local E,A=m(q,L)x[E]=A end else for m,q in q._remoteFunctions do x[m]=q end end return x end function x.destroy(m)m:disconnect()m.destroyed=true end return x
local RemoteEventClient = require(script.Parent.RemoteEventClient)
local RemoteFunctionClient = require(script.Parent.RemoteFunctionClient)

--[=[
    Client class

    @class Client
]=]
local Client = {}
Client.__index = Client

--[=[
    Constructs a new Client object

    @param id string
    @param server Server
    @return Client

    @private
]=]
function Client._new(id, server)
    assert(not server:getClient(id), string.format("%s is already a client", tostring(id)))

    local self = setmetatable({}, Client)

    self._server = server
    
    --[=[
        Stores the id of the client passed in the constructor

        @prop id string
        @within Client
        @readonly
    ]=]
    self.id = id

    --[=[
        Tells whether the client object is connected or not
        
        @prop connected bool
        @within Client
        @readonly
    ]=]
    self.connected = true

    self._remoteEvents = {}
    self._remoteFunctions = {}

    self._server._clients[id] = self

    for name in pairs(self._server._remoteEvents) do
        RemoteEventClient._new(name, self._server, self)
    end

    for name in pairs(self._server._remoteFunctions) do
        RemoteFunctionClient._new(name, self._server, self)
    end

    self._server.clientConnected:fire(self)

    return self
end

--[=[
    Gets the RemoteEventClient if it exists, returns nil otherwise

    @param name string
    @return RemoteEventClient

    @error "%s is not a valid RemoteEvent"
]=]
function Client:getRemoteEvent(name)
    assert(self._remoteEvents[name], string.format("%s is not a valid RemoteEvent", name))
    return self._remoteEvents[name]
end

--[=[
    Gets the RemoteFunctionClient if it exists, returns nil otherwise

    @param name string
    @return RemoteFunctionClient

    @error "%s is not a valid RemoteFunction"
]=]
function Client:getRemoteFunction(name)
    assert(self._remoteFunctions[name], string.format("%s is not a valid RemoteFunction", name))
    return self._remoteFunctions[name]
end

--[=[
    Disconnects the client from the server
]=]
function Client:disconnect()
    self.connected = false

    self._server.clientDisconnecting:fire(self)

    for _, event in pairs(self._remoteEvents) do
        event:destroy()
    end

    for _, func in pairs(self._remoteFunctions) do
        func:destroy()
    end

    self._server._clients[self.id] = nil
end

--[=[
    Returns a table that maps the remoteEvent name and object with the passed function

    @param fn function
    @return table
]=]
function Client:mapRemoteEvents(fn)
    local map = {}
    
    if fn then
        for name, client in self._remoteEvents do
            local key, value = fn(name, client)
            map[key] = value
        end
    else
        for name, client in self._remoteEvents do
            map[name] = client
        end
    end

    return map
end

--[=[
    Returns a table that maps the remoteFunction name and object with the passed function

    @param fn function
    @return table
]=]
function Client:mapRemoteFunctions(fn)
    local map = {}
    
    if fn then
        for name, client in self._remoteFunctions do
            local key, value = fn(name, client)
            map[key] = value
        end
    else
        for name, client in self._remoteFunctions do
            map[name] = client
        end
    end

    return map
end

--[=[
    Alias for disconnect but sets destroyed field to true
]=]
function Client:destroy()
    self:disconnect()
    self.destroyed = true
end

return Client