"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.newTSTLClass = exports.isTSTLSet = exports.isTSTLMap = exports.isTSTLClass = exports.isDefaultMap = exports.getTSTLClassName = exports.getTSTLClassConstructor = void 0;
const types_1 = require("./types");
const utils_1 = require("./utils");
/**
 * 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 getTSTLClassConstructor(object) {
    if (!(0, types_1.isTable)(object)) {
        return undefined;
    }
    const metatable = getmetatable(object);
    if (metatable === undefined) {
        return undefined;
    }
    return metatable.constructor;
}
exports.getTSTLClassConstructor = getTSTLClassConstructor;
/**
 * 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 getTSTLClassName(object) {
    const constructor = getTSTLClassConstructor(object);
    if (constructor === undefined) {
        return undefined;
    }
    return constructor.name;
}
exports.getTSTLClassName = getTSTLClassName;
/**
 * 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 has
 * their own copies of the entire lualib and thus their own instantiated version of a `Map`.
 */
function isDefaultMap(object) {
    const className = getTSTLClassName(object);
    return className === "DefaultMap";
}
exports.isDefaultMap = isDefaultMap;
/** Helper function to check if a given table is a class table created by TypeScriptToLua. */
function isTSTLClass(object) {
    const tstlClassName = getTSTLClassName(object);
    return tstlClassName !== undefined;
}
exports.isTSTLClass = isTSTLClass;
/**
 * 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 isTSTLMap(object) {
    const className = getTSTLClassName(object);
    return className === "Map";
}
exports.isTSTLMap = isTSTLMap;
/**
 * 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 isTSTLSet(object) {
    const className = getTSTLClassName(object);
    return className === "Set";
}
exports.isTSTLSet = isTSTLSet;
/**
 * 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 newTSTLClass(oldClass) {
    const constructor = getTSTLClassConstructor(oldClass);
    (0, utils_1.assertDefined)(constructor, "Failed to instantiate a new TypeScriptToLua class since the provided old class does not have a metatable/constructor.");
    // We re-implement some of the logic from the transpiled "__TS__New" function.
    const newClass = new LuaMap();
    const newClassMetatable = setmetatable(newClass, constructor.prototype);
    newClassMetatable.____constructor();
    return newClass;
}
exports.newTSTLClass = newTSTLClass;
