if not modules then modules = { } end modules ['file-mod'] = {
    version   = 1.001,
    comment   = "companion to file-mod.mkvi",
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files"
}

-- This module will be redone! For instance, the prefixes will move to data-* as
-- they are sort of generic along with home:// etc/.
--
-- It is more convenient to manipulate filenames (paths) in Lua than in TeX. The
-- methods below have counterparts at the TeX end.

local format, find, concat, tonumber = string.format, string.find, table.concat, tonumber
local sortedhash = table.sortedhash
local basename = file.basename

local trace_modules     = false  trackers  .register("modules.loading",          function(v) trace_modules     = v end)
local permit_unprefixed = false  directives.register("modules.permitunprefixed", function(v) permit_unprefixed = v end)

local report            = logs.reporter("modules")

local commands          = commands
local context           = context
local implement         = interfaces.implement

local findbyscheme      = resolvers.finders.byscheme -- use different one
local iterator          = utilities.parsers.iterator

-- modules can have a specific suffix or can specify one

local prefixes = {
    "m", -- module, extends functionality
    "p", -- private code
    "s", -- styles
    "x", -- xml specific modules
 -- "v", -- an old internal one for examples
    "t", -- third party extensions
}

-- the order might change and how about cld

local suffixes = CONTEXTLMTXMODE > 0 and
{
    "mklx", -- preprocessed mkiv lmtx files
    "mkxl", -- mkiv lmtx files
    "mkvi", -- preprocessed mkiv files
    "mkiv", -- mkiv files
    "tex",  -- normally source code files
    "cld",  -- context lua documents (often stand alone)
    "lua",  -- lua files
}
    or
{
    "mkvi",
    "mkiv",
    "tex",
    "cld",
    "lua",
}

-- This controls embedded overloads. Maybe at some point we will limit this to files in the
-- tree but on the other hand we don't need to be that strict. It is just an extra level
-- of protection.

-- todo: tex.getrunstatevalues
--
-- enforced : when state != production
--
-- 0 : initializing
-- 1 : updating
-- 2 : production

local pushrunstate, poprunstate  do

    local runstatecodes = tex.runstatecodes
    local runstate      = tex.getrunstate()
    local setrunstate   = tex.setrunstate

    local initializing <const> = runstatecodes.initializing
    local updating     <const> = runstatecodes.updating
    ----- production   <const> = runstatecodes.production

    if runstate == initializing then

        pushrunstate = function() end
        poprunstate  = function() end

    else

        local level = 0

        pushrunstate = function()
            level = level + 1
            if level == 1 then
                setrunstate(updating)
            end
        end

        poprunstate = function()
            if level == 1 then
                setrunstate(runstate)
            end
            if level > 0 then
                level = level - 1
            end
        end

    end

    luatex.pushrunstate = pushrunstate
    luatex.poprunstate  = poprunstate

    tex.setrunstate     = function() end

    implement { name = "pushrunstate", public = true, protected = true, actions = pushrunstate }
    implement { name = "poprunstate",  public = true, protected = true, actions = poprunstate  }

end

-- Till here.

local modstatus = { }
local missing   = false

local function usemodule(name,hasscheme)
    local foundname
    if hasscheme then
        -- no auto suffix as http will return a home page or error page
        -- so we only add one if missing
        local fullname = file.addsuffix(name,"tex")
        if trace_modules then
            report("checking url %a",fullname)
        end
        foundname = resolvers.findtexfile(fullname) or ""
    elseif file.suffix(name) ~= "" then
        if trace_modules then
            report("checking file %a",name)
        end
        foundname = findbyscheme("any",name) or ""
    else
        for i=1,#suffixes do
            local fullname = file.addsuffix(name,suffixes[i])
            if trace_modules then
                report("checking file %a",fullname)
            end
            foundname = findbyscheme("any",fullname) or ""
            if foundname ~= "" then
                break
            end
        end
    end
    if foundname ~= "" then
        if trace_modules then
            report("loading file %a",foundname)
        end
-- token.expandmacro("pushrunstate")
-- token.expandmacro("startreadingfile")
        context.pushrunstate()
        context.startreadingfile()
        resolvers.jobs.usefile(foundname,true) -- once, notext
     -- context.input(foundname)
        context.stopreadingfile()
        context.poprunstate()
-- token.expandmacro("stopreadingfile")
-- token.expandmacro("poprunstate")
        return true
    else
        return false
    end
end

function environment.usemodules(prefix,askedname,truename)
    local truename = truename or environment.truefilename(askedname) or askedname
    if truename and truename ~= "" then
        local hasprefix = prefix and prefix ~= ""
        local hashname = ((hasprefix and prefix) or "*") .. "-" .. truename
        local status = modstatus[hashname] or false -- yet unset
        if status == 0 then
            -- not found
        elseif status == 1 then
            status = status + 1
        else
            if trace_modules then
                report("locating, prefix %a, askedname %a, truename %a",prefix,askedname,truename)
            end
            local hasscheme = url.hasscheme(truename)
            if hasscheme then
                -- no prefix and suffix done
                if usemodule(truename,true) then
                    status = 1
                else
                    status = 0
                end
            elseif hasprefix then
                if usemodule(prefix .. "-" .. truename) then
                    status = 1
                else
                    status = 0
                end
            else
                for i=1,#prefixes do
                    -- todo: reconstruct name i.e. basename
                    local thename = prefixes[i] .. "-" .. truename
                    if thename == tex.jobname then
                        -- in case we process a module
                        status = 1
                        break
                    elseif usemodule(thename) then
                        status = 1
                        break
                    end
                end
                if status then
                    -- ok, don't change
                elseif find(truename,"-",1,true) and usemodule(truename) then
                    -- assume a user namespace
                    report("using user prefixed file %a",truename)
                    status = 1
                elseif permit_unprefixed and usemodule(truename) then
                    report("using unprefixed file %a",truename)
                    status = 1
                else
                    status = 0
                end
            end
        end
        if status == 0 then
            missing = true
            report("%a is not found",askedname)
        elseif status == 1 then
            report("%a is loaded",trace_modules and truename or askedname)
        else
            report("%a is already loaded",trace_modules and truename or askedname)
        end
        modstatus[hashname] = status
    end
end

statistics.register("loaded tex modules", function()
    if next(modstatus) then
        local t, f, nt, nf = { }, { }, 0, 0
        for k, v in sortedhash(modstatus) do
            local b = basename(k)
            if v == 0 then
                nf = nf + 1
                f[nf] = b
            else
                nt = nt + 1
                t[nt] = b
            end
        end
        if nf == 0 then
            return format("%s requested, all found (%s)",nt,concat(t," "))
        elseif nt == 0 then
            return format("%s requested, all missing (%s)",nf,concat(f," "))
        else
            return format("%s requested, %s found (%s), %s missing (%s)",nt+nf,nt,concat(t," "),nf,concat(f," "))
        end
    else
        return nil
    end
end)

logs.registerfinalactions(function()
    logs.startfilelogging(report,"used modules")
    for k, v in sortedhash(modstatus) do
        report(v == 0 and "  missing: %s" or "  loaded : %s",basename(k))
    end
    logs.stopfilelogging()
    if missing and logs.loggingerrors() then
        logs.starterrorlogging(report,"missing modules")
        for k, v in sortedhash(modstatus) do
            if v == 0 then
                report("%w%s",6,basename(k))
            end
        end
        logs.stoperrorlogging()
    end
end)

-- moved from syst-lua.lua:

local lpegmatch = lpeg.match
local splitter  = lpeg.tsplitter(lpeg.S(". "),tonumber)

function environment.comparedversion(one,two) -- one >= two
    if not two or two == "" then
        one, two = environment.version, one
    elseif one == "" then
        one = environment.version
    end
    one = lpegmatch(splitter,one)
    two = lpegmatch(splitter,two)
    one = (one[1] or 0) * 10000 + (one[2] or 0) * 100 + (one[3] or 0)
    two = (two[1] or 0) * 10000 + (two[2] or 0) * 100 + (two[3] or 0)
    if one < two then
        return -1
    elseif one > two then
        return 1
    else
        return 0
    end
end

environment.comparedversion = comparedversion


function environment.useluamodule(list)
    for filename in iterator(list) do
        environment.loadluafile(filename)
    end
end

implement {
    name      = "usemodules",
    actions   = environment.usemodules,
    arguments = "2 strings",
}

implement {
    name      = "doifelseolderversion",
    actions   = function(one,two) commands.doifelse(comparedversion(one,two) >= 0) end,
    arguments = "2 strings"
}

implement {
    name      = "useluamodule",
    actions   = environment.useluamodule,
    arguments = "string"
}

implement {
    name      = "loadluamodule",
    actions   = function(name) dofile(resolvers.findctxfile(name)) end, -- hack
    arguments = "string"
}