#include "loader.h"

const char* EA::Lua::LOADER =

"--  Things that are loading are tables with seven keys\n"
"-- name			The file name of the thing we're loading\n"
"-- dependents		An array of things that depend on this (could be callbacks or other things that are loading)\n"
"-- reqMap			A set of things we depend on (keys are file names, values are indices 1 .. n)\n"
"-- reqList			An array of fulfilled dependencies\n"
"-- reqError		A corresponding list of errors loading dependencies\n"
"-- file			Our own file (function) to be executed to load the module)\n"
"-- loaded			true if we're already loaded\n"
"local loading = {}\n"
"\n"
"-- things that are loaded are just libraries, which could really be anything at all\n"
"local loaded = setmetatable({}, { __mode = 'v' })\n"
"\n"
"local update\n"
"\n"
"update = function(data)\n"
"	local file = data.file\n"
"	local reqMap = data.reqMap\n"
"\n"
"	-- not loaded and we have a file and we have our dependency map\n"
"	if not data.loaded and file and reqMap then\n"
"		local reqList = data.reqList\n"
"		local errors = {}\n"
"\n"
"		if type(reqMap) == \"table\" then\n"
"			local reqError = data.reqError\n"
"			for _, v in pairs(reqMap) do\n"
"				if not reqList[v] then\n"
"					local error = reqError[v]\n"
"					if error then\n"
"						table.insert(errors, error)\n"
"					else\n"
"						return\n"
"					end\n"
"				end\n"
"			end\n"
"		else\n"
"			table.insert(errors, reqMap)\n"
"		end\n"
"\n"
"		if type(file) == \"string\" then\n"
"			table.insert(errors, file)\n"
"		end\n"
"\n"
"		local name = data.name\n"
"\n"
"		if not next(errors) then\n"
"			local status, result = pcall(file, unpack(reqList))\n"
"\n"
"			if status then\n"
"				if result ~= nil then\n"
"					data.loaded = true\n"
"\n"
"					loaded[name] = result\n"
"					loading[name] = nil\n"
"\n"
"					for _, v in ipairs(data.dependents) do\n"
"						if type(v) == \"table\" then\n"
"							v.reqList[v.reqMap[name]] = result\n"
"							update(v)\n"
"						else\n"
"							v(result)\n"
"						end\n"
"					end\n"
"\n"
"					return\n"
"				else\n"
"					table.insert(errors, data.name..\" returned nil\")\n"
"				end\n"
"			else\n"
"				table.insert(errors, result)\n"
"			end\n"
"		end\n"
"\n"
"		loading[name] = nil\n"
"\n"
"		local message = table.concat(errors, \"\\n\")\n"
"\n"
"		for _, v in ipairs(data.dependents) do\n"
"			if type(v) == \"table\" then\n"
"				v.reqError[v.reqMap[name]] = message\n"
"				update(v)\n"
"			else\n"
"				v(nil, message)\n"
"			end\n"
"		end\n"
"	end\n"
"end\n"
"\n"
"local depend\n"
"\n"
"depend = function(dependent, name)\n"
"	local data = loading[name]\n"
"\n"
"	if data then\n"
"		table.insert(data.dependents, dependent)\n"
"	else\n"
"		data =\n"
"		{\n"
"			name = name,\n"
"			dependents = { dependent },\n"
"			reqMap = nil,\n"
"			reqList = {},\n"
"			reqError = {},\n"
"			file = nil,\n"
"			loaded = nil\n"
"		}\n"
"\n"
"		loading[name] = data\n"
"\n"
"		local lreqName = string.gsub(name, \"%.lua$\", \".lreq\")\n"
"		if fileexists(lreqName) then\n"
"			json.load(\n"
"				function(reqs, error)\n"
"					if reqs then\n"
"						local map = {}\n"
"\n"
"						local path = getpath(name)\n"
"\n"
"						for i, v in ipairs(reqs) do\n"
"							local reqName = appendpath(path, v)\n"
"							map[reqName] = i\n"
"\n"
"							local req = loaded[reqName]\n"
"\n"
"							if req then\n"
"								data.reqList[i] = req\n"
"							else\n"
"								depend(data, reqName)\n"
"							end\n"
"						end\n"
"\n"
"						data.reqMap = map\n"
"					else\n"
"						data.reqMap = lreqName..\" \"..error\n"
"					end\n"
"\n"
"					return update(data)\n"
"				end,\n"
"				lreqName\n"
"				)\n"
"		else\n"
"			data.reqMap = {} -- no reqs\n"
"		end\n"
"\n"
"		return loadfileasync(\n"
"			function(file, error)\n"
"				data.file = file or error\n"
"\n"
"				return update(data)\n"
"			end,\n"
"			name)\n"
"	end\n"
"end\n"
"\n"
"return function(callback, name)\n"
"\n"
"	local prefix = string.sub(name, 1, 1)\n"
"	if prefix == \"/\" or prefix == \"\\\\\" then\n"
"		name = string.sub(name, 2)\n"
"	end\n"
"\n"
"	local data = loaded[name]\n"
"\n"
"	if data then\n"
"		return callback(data)\n"
"	else\n"
"		return depend(callback, name)\n"
"	end\n"
"end\n"
;
