--- Hotfix helper which hotfixes modified modules.
-- Using lfs to detect files' modification.

local M = {}

local lfs = require("lfs")
local hotfix = require("hotfix.hotfix")
local skynet = require("skynet")

-- Map file path to file time to detect modification.
local path_to_time = {}

-- global_objects which must not hotfix.
local global_objects = {
    arg,
    assert,
    collectgarbage,
    coroutine,
    debug,
    dofile,
    error,
    getmetatable,
    io,
    ipairs,
    load,
    loadfile,
    math,
    next,
    os,
    package,
    pairs,
    pcall,
    print,
    rawequal,
    rawget,
    rawlen,
    rawset,
    require,
    select,
    setmetatable,
    string,
    table,
    tonumber,
    tostring,
    type,
    utf8,
    xpcall,
    lfs,
    skynet, -- skynet 模块不能够热更
}

--- Check modules and hotfix.
local hotfix_module_names = require("hotfix.helper.hotfix_module_names")

local function tcontains(t, value)
    for _, v in pairs(t) do
        if (v == value) then
            return true
        end
    end
    return false
end

function M.add(module_name)
    if not tcontains(hotfix_module_names, module_name) then
        -- 保证不重复
        table.insert(hotfix_module_names, module_name)
    end
end

function M.check()
    for _, module_name in pairs(hotfix_module_names) do
        -- skynet.error("hotfix module_name:", module_name)

        local path, err = package.searchpath(module_name, package.path)
        -- Skip non-exist module.
        if not path then
            skynet.error(string.format("No such module: %s. %s", module_name, err))
            goto continue
        end

        local file_time = lfs.attributes(path, "modification")
        if file_time == path_to_time[path] then
            goto continue
        end

        skynet.error(string.format("Hot fix module %s (%s)", module_name, path))
        path_to_time[path] = file_time
        hotfix.hotfix_module(module_name)
        ::continue::
    end -- for
end -- check()

function M.init()
    hotfix.log_debug = function(s)
        skynet.error(s)
    end
    hotfix.add_protect(global_objects)
end

return M
