local createEventLoop = require("/apis/eventloop")

local LOCAL_MANIFEST_PATH = "/trapos/manifest.json"
local SESSION_END_SETTING = "trapos.on_session_end"
local STALE_STARTUP_FILES = { "/startup/servers.lua", "/startup/motd.lua" }

local function readLocalManifest()
	if not fs.exists(LOCAL_MANIFEST_PATH) then
		return nil
	end
	local f = fs.open(LOCAL_MANIFEST_PATH, "r")
	if not f then
		return nil
	end
	local data = f.readAll()
	f.close()
	if not data or data == "" then
		return nil
	end
	return textutils.unserializeJSON(data)
end

local function init()
	shell.setPath(shell.path() .. ":/programs")
	for _, path in ipairs(STALE_STARTUP_FILES) do
		if fs.exists(path) then
			fs.delete(path)
		end
	end
end

local function sessionEndAction()
	local action = settings.get(SESSION_END_SETTING)
	if action == "reboot" or action == "relaunch" then
		return action
	end
	return "shutdown"
end

init()

shell.run("/programs/motd.lua")

if periphemu then
	periphemu.create("top", "modem")
	periphemu.create("left", "speaker")
end

local function reportBootEventLoopError(eventName, err)
	local message = "boot eventloop handler error (" .. tostring(eventName) .. "): " .. tostring(err)
	local printErrorFn = _G.printError
	if type(printErrorFn) == "function" then
		printErrorFn(message)
	else
		print(message)
	end
end

_G.bootEventLoop = createEventLoop({ onError = reportBootEventLoopError })

local shellExited = false
local action = "shutdown"

local function shellFn()
	os.sleep(0.1)
	repeat
		shell.run("shell")
		action = sessionEndAction()
	until action ~= "relaunch"
	shellExited = true
end

local function eventLoopFn()
	_G.bootEventLoop.runLoop(true)
end

local manifest = readLocalManifest()
local DAEMONS = (manifest and manifest.autostart) or {}

if #DAEMONS > 0 then
	print("\nStarting daemons...")
	for _, daemonName in ipairs(DAEMONS) do
		print("\t\t" .. daemonName)
		local ok, err = pcall(shell.run, daemonName)
		if not ok then
			print("daemon '" .. daemonName .. "' failed to start: " .. tostring(err))
		end
	end
end

parallel.waitForAny(shellFn, eventLoopFn)

if shellExited then
	if action == "reboot" then
		os.reboot()
	else
		os.shutdown()
	end
end
