local CLASSES = {}
local CLASS_METATABLES = {}
local CLASS_PARENTS = {}
local INSTANCE_METATABLES = {}
local WEAK_INSTANCE_METATABLES = {}

local function getWeakInstanceMetaTable(classTable)
	if not WEAK_INSTANCE_METATABLES[classTable] then
		WEAK_INSTANCE_METATABLES[classTable] = {__index=classTable, __mode = "v"}
	end
	return WEAK_INSTANCE_METATABLES[classTable]
end

function getClassName(classTable)
	return CLASSES[classTable]
end

function getClassNameOf(instance)
	local mt = getmetatable(instance)
	if mt then
		return CLASSES[rawget(mt, "__index")]
	end
end

function getClassTable(className)
	return CLASSES[className]
end

function getClassTableOf(instance)
	local mt = getmetatable(instance)
	if mt then
		return mt.__index
	end
end

function getInstanceMetaTable(classTable)
	return INSTANCE_METATABLES[classTable]
end

function isOfClass(classtable, classname)
	if getClassName(classtable) == classname then
		return true
	end
	if classtable.super then
		return isOfClass(classtable.super(), classname)
	end
	return false
end

function isInstanceOfClass(instance, classname)
	local classtable = getClassTableOf(instance)
	if classtable then
		return isOfClass(classtable, classname)
	end
	return false
end

function custom(className, mt)
	if CLASSES[className] then
		print("Class "..className.. " already defined")
		return CLASSES[className]
	else
		local classTable = {}
		if not INSTANCE_METATABLES[classTable] then
			INSTANCE_METATABLES[classTable] = mt
		end

		CLASSES[className] = classTable
		CLASSES[classTable] = className
		return classTable
	end
end

function class(className)
	if CLASSES[className] then
		print("Class "..className.. " already defined")
		return CLASSES[className]
	else
		local classTable = {}
		if not INSTANCE_METATABLES[classTable] then
			INSTANCE_METATABLES[classTable] = {__index=classTable}
		end
		CLASSES[className] = classTable
		CLASSES[classTable] = className
		return classTable
	end
end

function inherited(className, parentClassTable)
	if not parentClassTable then
		print(tostring(className).. " cannot inherit nil")
	end
	local classTable = class(className)
	if not CLASS_METATABLES[classTable] then
		CLASS_METATABLES[classTable] = {__index=parentClassTable}
		classTable.super = function()
			return parentClassTable
		end
	end
	return setmetatable(classTable, CLASS_METATABLES[classTable])
end

function weakInstance(classTable, ...)
	local a = setmetatable(classTable.super and weakInstance(classTable.super(),...) or {}, getWeakInstanceMetaTable(classTable))
	if classTable.onNew then
		classTable.onNew(a, ...)
	end
	debug.reportCreated(a)
	return a
end

function instance(classTable, ...)
	if _enableReplays then debugFunc = getClassName(classTable) or " " end
	local a = setmetatable(classTable.super and instance(classTable.super(),...) or {}, INSTANCE_METATABLES[classTable])
	if classTable.onNew then
		classTable.onNew(a, ...)
	end
	debug.reportCreated(a)
	return a
end

function premade(classTable, baseTable, ...)
	local a = setmetatable(classTable.super and premade(classTable.super(), baseTable, ...) or baseTable or {}, INSTANCE_METATABLES[classTable])
	if classTable.onNew then
		classTable.onNew(a, ...)
	end
	debug.reportCreated(a)
	return a
end

function debuginstance(classTable, ...)
	if _enableReplays then debugFunc = getClassName(classTable) or " " end
	local a = setmetatable(classTable.super and instance(classTable.super(),...) or {}, {__index=function(t,k) return rawget(t, "_t") and rawget(t, "_t")[k] or classTable[k] end, __newindex = function(t,k,v) if not rawget(t, "_t") then rawset(t, "_t", {}) end; if k == "dx" and t[k] ~= 0 and v == 0 then printtable(string.split(debug.traceback(), "C:" )) end; rawget(t, "_t")[k] = v; end})
	if classTable.onNew then
		classTable.onNew(a, ...)
	end
	debug.reportCreated(a)
	return a
end

