local ____exports = {}
local ____types = require("functions.types")
local isTable = ____types.isTable
local ____utils = require("functions.utils")
local assertDefined = ____utils.assertDefined
--- Helper function to get the constructor from an instantiated TypeScriptToLua class, which is
-- located on the metatable.
-- 
-- Returns undefined if passed a non-table or if the provided table does not have a metatable.
function ____exports.getTSTLClassConstructor(self, object)
    if not isTable(nil, object) then
        return nil
    end
    local metatable = getmetatable(object)
    if metatable == nil then
        return nil
    end
    return metatable.constructor
end
--- Helper function to get the name of a TypeScriptToLua class from the instantiated class object.
-- 
-- TSTL classes are Lua tables created with the `__TS__Class` Lua function from the TSTL lualib.
-- Their name is contained within "constructor.name" metatable key.
-- 
-- For example, a `Map` class is has a name of "Map".
-- 
-- Returns undefined if passed a non-table or if the provided table does not have a metatable.
function ____exports.getTSTLClassName(self, object)
    local constructor = ____exports.getTSTLClassConstructor(nil, object)
    if constructor == nil then
        return nil
    end
    return constructor.name
end
--- Helper function to determine if a given object is a `DefaultMap` from `isaacscript-common`.
-- 
-- It is not reliable to use the `instanceof` operator to determine this because each Lua module has
-- their own copies of the entire lualib and thus their own instantiated version of a `DefaultMap`.
function ____exports.isDefaultMap(self, object)
    local className = ____exports.getTSTLClassName(nil, object)
    return className == "DefaultMap"
end
--- Helper function to check if a given table is a class table created by TypeScriptToLua.
function ____exports.isTSTLClass(self, object)
    local tstlClassName = ____exports.getTSTLClassName(nil, object)
    return tstlClassName ~= nil
end
--- Helper function to determine if a given object is a TypeScriptToLua `Map`.
-- 
-- It is not reliable to use the `instanceof` operator to determine this because each Lua module
-- might have their own copy of the entire lualib and thus their own instantiated version of a
-- `Map`.
function ____exports.isTSTLMap(self, object)
    local className = ____exports.getTSTLClassName(nil, object)
    return className == "Map"
end
--- Helper function to determine if a given object is a TypeScriptToLua `Set`.
-- 
-- It is not reliable to use the `instanceof` operator to determine this because each Lua module
-- might have their own copy of the entire lualib and thus their own instantiated version of a
-- `Set`.
function ____exports.isTSTLSet(self, object)
    local className = ____exports.getTSTLClassName(nil, object)
    return className == "Set"
end
--- Initializes a new TypeScriptToLua class in the situation where you do not know what kind of class
-- it is. This function requires that you provide an instantiated class of the same type, as it will
-- use the class constructor that is present on the other object's metatable to initialize the new
-- class.
function ____exports.newTSTLClass(self, oldClass)
    local constructor = ____exports.getTSTLClassConstructor(nil, oldClass)
    assertDefined(nil, constructor, "Failed to instantiate a new TypeScriptToLua class since the provided old class does not have a metatable/constructor.")
    local newClass = {}
    local newClassMetatable = setmetatable(newClass, constructor.prototype)
    newClassMetatable:____constructor()
    return newClass
end
return ____exports
