local serial = require "serialization"

local rc = {}
rc.paths = "/boot/service\n/pkg/service"
rc.pids = {}
local service = {}
local cfg = {}
cfg.enabled = {"getty","minitel"}

local function loadConfig()
 local f = io.open("/boot/cfg/rc.cfg","rb")
 if not f then return false end
 cfg = serial.unserialize(f:read("*a")) or {}
 f:close()
 cfg.enabled = cfg.enabled or {}
 return true
end
local function saveConfig()
 local f = io.open("/boot/cfg/rc.cfg","wb")
 if not f then return false end
 f:write(serial.serialize(cfg))
 f:close()
 return true
end

function rc.load(name,force) -- string boolean -- table -- Attempts to load service *name*, and if *force* is true, replaces the current instance.
 if not package.loaded[name] or force then
  for d in rc.paths:gmatch("[^\n]+") do
   if fs.exists(d.."/"..name..".lua") then
    service[name] = runfile(d.."/"..name..".lua")
   end
  end
 end
 if service[name] then
  return service[name]
 end
 return false, "unable to load service "..name
end

--[[
function rc.load(name,force) -- string boolean -- table -- Attempts to load service *name*, and if *force* is true, replaces the current instance.
 if force then
  rc.stop(name)
  service[name] = nil
 end
 if service[name] then return true end
 service[name] = setmetatable({},{__index=_G})
 local f
 f = io.open("/boot/service/"..name..".lua","rb")
 if not f then
  pcall(require,"pkgfs")
  f = io.open("/pkg/service/"..name..".lua","rb")
 end
 local res = load(f:read("*a"),name,"t",service[name])()
 f:close()
 return res
end
]]

function rc.stop(name,...) -- string -- boolean string -- Stops service *name*, supplying *...* to the stop function. Returns false and a reason if this fails.
 if not service[name] then return false, "service not found" end
 if service[name].stop then
  service[name].stop(...)
  coroutine.yield()
 end
 if rc.pids[name] then
  os.kill(rc.pids[name])
 end
 rc.pids[name] = nil
end

function rc.start(name,...) -- string -- boolean string -- Stops service *name*, supplying *...* to the stop function. Returns false and a reason if this fails.
 rc.load(name)
 if not service[name] then return false, "service not found" end
 local rv = {service[name].start(...)}
 if type(rv[1]) == "number" then
  rc.pids[name] = rv[1]
 end
end

function rc.restart(name) -- string -- -- Restarts service *name* using rc.stop and rc.start.
 rc.stop(name)
 rc.start(name)
end

function rc.enable(name) -- string -- -- Enables service *name* being started on startup.
 for k,v in pairs(cfg.enabled) do
  if v == name then return false end
 end
 cfg.enabled[#cfg.enabled+1] = name
 saveConfig()
end
function rc.disable(name) -- string -- -- Disables service *name* being started on startup.
 local disabled = false
 for k,v in pairs(cfg.enabled) do
  if v == name then table.remove(cfg.enabled,k) disabled = true break end
 end
 saveConfig()
 return disabled
end

loadConfig()

_G.service = service
rc.cfg = cfg

return rc