function Enum.createEnum(Q,I)assert(typeof(Q)=="\115\116\114\105\110\103","\098\097\100 \097\114\103\117\109\101\110\116 \035\049 - \101\110\117\109\115 \109\117\115\116 \098\101 \099\114\101\097\116\101\100 \117\115\105\110\103 \097 \115\116\114\105\110\103 \110\097\109\101\033")assert(typeof(I)=="\116\097\098\108\101","\098\097\100 \097\114\103\117\109\101\110\116 \035\050 - \101\110\117\109\115 \109\117\115\116 \098\101 \099\114\101\097\116\101\100 \117\115\105\110\103 \097 \116\097\098\108\101\033")assert(not enums[Q],("\101\110\117\109 \'\037\115\' \097\108\114\101\097\100\121 \101\120\105\115\116\115\033"):format(Q))local v={}local X={}local M={}local O={}local r={getName=function(Q)Q=tostring(Q)local v=M[Q]if not v then v=O[Q]end if v then return I[v][1]end end,getValue=function(Q)Q=tostring(Q)local v=X[Q]if not v then v=O[Q]end if v then return I[v][2]end end;getProperty=function(Q)Q=tostring(Q)local v=X[Q]if not v then v=M[Q]end if v then return I[v][3]end end}for Q,I in pairs(I)do assert(typeof(I)=="\116\097\098\108\101",("\098\097\100 \097\114\103\117\109\101\110\116 \035\050\046\037\115 - \100\101\116\097\105\108\115 \109\117\115\116 \111\110\108\121 \098\101 \099\111\109\112\114\105\115\101\100 \111\102 \116\097\098\108\101\115\033"):format(Q))local A=I[1]assert(typeof(A)=="\115\116\114\105\110\103",("\098\097\100 \097\114\103\117\109\101\110\116 \035\050\046\037\115\046\049 - \100\101\116\097\105\108 \110\097\109\101 \109\117\115\116 \098\101 \097 \115\116\114\105\110\103\033"):format(Q))assert(typeof(not X[A]),("\098\097\100 \097\114\103\117\109\101\110\116 \035\050\046\037\115\046\049 - \116\104\101 \100\101\116\097\105\108 \110\097\109\101 \'\037\115\' \097\108\114\101\097\100\121 \101\120\105\115\116\115\033"):format(Q,A))assert(typeof(not r[A]),("\098\097\100 \097\114\103\117\109\101\110\116 \035\050\046\037\115\046\049 - \116\104\097\116 \110\097\109\101 \105\115 \114\101\115\101\114\118\101\100\046"):format(Q,A))X[tostring(A)]=Q local d=I[2]local W=tostring(d)assert(typeof(not M[W]),("\098\097\100 \097\114\103\117\109\101\110\116 \035\050\046\037\115\046\050 - \116\104\101 \100\101\116\097\105\108 \118\097\108\117\101 \'\037\115\' \097\108\114\101\097\100\121 \101\120\105\115\116\115\033"):format(Q,W))M[W]=Q local n=I[3]if n then assert(typeof(not O[n]),("\098\097\100 \097\114\103\117\109\101\110\116 \035\050\046\037\115\046\051 - \116\104\101 \100\101\116\097\105\108 \112\114\111\112\101\114\116\121 \'\037\115\' \097\108\114\101\097\100\121 \101\120\105\115\116\115\033"):format(Q,tostring(n)))O[tostring(n)]=Q end v[A]=d setmetatable(v,{__index=function(Q,I)return r[I]end})end enums[Q]=v return v end function Enum.getEnums()return enums end

function Enum.createEnum(enumName, details)
	assert(typeof(enumName) == "string", "bad argument #1 - enums must be created using a string name!")
	assert(typeof(details) == "table", "bad argument #2 - enums must be created using a table!")
	assert(not enums[enumName], ("enum '%s' already exists!"):format(enumName))
	
	local enum = {}
	local usedNames = {}
	local usedValues = {}
	local usedProperties = {}
	local enumMetaFunctions = {
		getName = function(valueOrProperty)
			valueOrProperty = tostring(valueOrProperty)
			local index = usedValues[valueOrProperty]
			if not index then
				index = usedProperties[valueOrProperty]
			end
			if index then
				return details[index][1]
			end
		end,
		getValue = function(nameOrProperty)
			nameOrProperty = tostring(nameOrProperty)
			local index = usedNames[nameOrProperty]
			if not index then
				index = usedProperties[nameOrProperty]
			end
			if index then
				return details[index][2]
			end
		end,
		getProperty = function(nameOrValue)
			nameOrValue = tostring(nameOrValue)
			local index = usedNames[nameOrValue]
			if not index then
				index = usedValues[nameOrValue]
			end
			if index then
				return details[index][3]
			end
		end
	}
	for i, detail in pairs(details) do
		assert(typeof(detail) == "table", ("bad argument #2.%s - details must only be comprised of tables!"):format(i))
		local name = detail[1]
		assert(typeof(name) == "string", ("bad argument #2.%s.1 - detail name must be a string!"):format(i))
		assert(typeof(not usedNames[name]), ("bad argument #2.%s.1 - the detail name '%s' already exists!"):format(i, name))
		assert(typeof(not enumMetaFunctions[name]), ("bad argument #2.%s.1 - that name is reserved."):format(i, name))
		usedNames[tostring(name)] = i
		local value = detail[2]
		local valueString = tostring(value)
		--assert(typeof(value) == "number" and math.ceil(value)/value == 1, ("bad argument #2.%s.2 - detail value must be an integer!"):format(i))
		assert(typeof(not usedValues[valueString]), ("bad argument #2.%s.2 - the detail value '%s' already exists!"):format(i, valueString))
		usedValues[valueString] = i
		local property = detail[3]
		if property then
			assert(typeof(not usedProperties[property]), ("bad argument #2.%s.3 - the detail property '%s' already exists!"):format(i, tostring(property)))
			usedProperties[tostring(property)] = i
		end
		enum[name] = value
		setmetatable(enum, {
			__index = function(_, index)
				return(enumMetaFunctions[index])
			end
		})
	end
	
	enums[enumName] = enum
	return enum
end

function Enum.getEnums()
	return enums
end


