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

if not fontloader then fontloader = fontforge end

dofile(resolvers.find_file("font-otp.lua","tex"))
dofile(resolvers.find_file("font-syn.lua","tex"))
dofile(resolvers.find_file("font-mis.lua","tex"))

scripts       = scripts       or { }
scripts.fonts = scripts.fonts or { }

function fonts.names.simple()
    local simpleversion = 1.001
    local simplelist = { "ttf", "otf", "ttc", "dfont" }
    local name = "luatex-fonts-names.lua"
    fonts.names.filters.list = simplelist
    fonts.names.version = simpleversion -- this number is the same as in font-dum.lua
    logs.report("fontnames","generating font database for 'luatex-fonts' version %s",fonts.names.version)
    fonts.names.identify(true)
    local data = fonts.names.data
    if data then
        local simplemappings = { }
        local simplified = {
            mappings = simplemappings,
            version = simpleversion,
        }
        local specifications = data.specifications
        for i=1,#simplelist do
            local format = simplelist[i]
            for tag, index in next, data.mappings[format] do
                local s = specifications[index]
                simplemappings[tag] = { s.rawname, s.filename, s.subfont }
            end
        end
        logs.report("fontnames","saving names in '%s'",name)
        io.savedata(name,table.serialize(simplified,true))
        local data = io.loaddata(resolvers.find_file("font-dum.lua","tex"))
        local dummy = string.match(data,"fonts%.names%.version%s*=%s*([%d%.]+)")
        if tonumber(dummy) ~= simpleversion then
            logs.report("fontnames","warning: version number %s in 'font-dum' does not match database version number %s",dummy or "?",simpleversion)
        end
    elseif lfs.isfile(name) then
        os.remove(name)
    end
end

function scripts.fonts.reload()
    if environment.argument("simple") then
        fonts.names.simple()
    else
        fonts.names.load(true)
    end
end

local function subfont(sf)
    if sf then
        return string.format("index: % 2s", sf)
    else
        return ""
    end
end

local function fontweight(fw)
    if fw then
        return string.format("conflict: %s", fw)
    else
        return ""
    end
end

local function showfeatures(tag,specification)
    logs.simple("mapping : %s",tag)
    logs.simple("fontname: %s",specification.fontname)
    logs.simple("fullname: %s",specification.fullname)
    logs.simple("filename: %s",specification.filename)
    logs.simple("family  : %s",specification.familyname or "<nofamily>")
    logs.simple("weight  : %s",specification.weight or "<noweight>")
    logs.simple("style   : %s",specification.style or "<nostyle>")
    logs.simple("width   : %s",specification.width or "<nowidth>")
    logs.simple("variant : %s",specification.variant or "<novariant>")
    logs.simple("subfont : %s",subfont(specification.subfont))
    logs.simple("fweight : %s",fontweight(specification.fontweight))
    -- maybe more
    local features = fonts.get_features(specification.filename,specification.format)
    if features then
        for what, v in table.sortedhash(features) do
            local data = features[what]
            if data and next(data) then
                logs.simple()
                logs.simple("%s features:",what)
                logs.simple()
                logs.simple("feature  script   languages")
                logs.simple()
                for f,ff in table.sortedhash(data) do
                    local done = false
                    for s, ss in table.sortedhash(ff) do
                        if s == "*"  then s       = "all" end
                        if ss  ["*"] then ss["*"] = nil ss.all = true end
                        if done then
                            f = ""
                        else
                            done = true
                        end
                        logs.simple("% -8s % -8s % -8s",f,s,table.concat(table.sortedkeys(ss), " "))
                    end
                end
            end
        end
    else
        logs.simple()
        logs.simple("no features")
        logs.simple()
    end
    logs.reportline()
end

local function reloadbase(reload)
    if reload then
        logs.simple("fontnames, reloading font database")
        names.load(true)
        logs.simple("fontnames, done\n\n")
    end
end

local function list_specifications(t,info)
    if t then
        local s = table.sortedkeys(t)
        if info then
            for k=1,#s do
                local v = s[k]
                showfeatures(v,t[v])
            end
        else
            for k=1,#s do
                local v = s[k]
                local entry = t[v]
                s[k] = {
                    entry.familyname  or "<nofamily>",
                    entry.weight      or "<noweight>",
                    entry.style       or "<nostyle>",
                    entry.width       or "<nowidth>",
                    entry.variant     or "<novariant>",
                    entry.fontname,
                    entry.filename,
                    subfont(entry.subfont),
                    fontweight(entry.fontweight),
                }
                e[k] = entry
            end
            table.formatcolumns(s)
            for k=1,#s do
                local v = s[k]
                texio.write_nl(v)
            end
        end
    end
end

local function list_matches(t,info)
    if t then
        local s, w = table.sortedkeys(t), { 0, 0, 0 }
        if info then
            for k=1,#s do
                local v = s[k]
                showfeatures(v,t[v])
            end
        else
            for k=1,#s do
                local v = s[k]
                local entry = t[v]
                s[k] = {
                    v,
                    entry.fontname,
                    entry.filename,
                    subfont(entry.subfont)
                }
            end
            table.formatcolumns(s)
            for k=1,#s do
                texio.write_nl(s[k])
            end
        end
    end
end

function scripts.fonts.list()

    local all     = environment.argument("all")
    local info    = environment.argument("info")
    local reload  = environment.argument("reload")
    local pattern = environment.argument("pattern")
    local filter  = environment.argument("filter")
    local given   = environment.files[1]

    reloadbase(reload)

    if environment.argument("name") then
        if pattern then
            --~ mtxrun --script font --list --name --pattern=*somename*
            list_matches(fonts.names.list(string.topattern(pattern,true),reload,all),info)
        elseif filter then
            logs.report("fontnames","not supported: --list --name --filter",name)
        elseif given then
            --~ mtxrun --script font --list --name somename
            list_matches(fonts.names.list(given,reload,all),info)
        else
            logs.report("fontnames","not supported: --list --name <no specification>",name)
        end
    elseif environment.argument("spec") then
        if pattern then
            --~ mtxrun --script font --list --spec --pattern=*somename*
            logs.report("fontnames","not supported: --list --spec --pattern",name)
        elseif filter then
            --~ mtxrun --script font --list --spec --filter="fontname=somename"
            list_specifications(fonts.names.getlookups(filter),info)
        elseif given then
            --~ mtxrun --script font --list --spec somename
            list_specifications(fonts.names.collectspec(given,reload,all),info)
        else
            logs.report("fontnames","not supported: --list --spec <no specification>",name)
        end
    elseif environment.argument("file") then
        if pattern then
            --~ mtxrun --script font --list --file --pattern=*somename*
            list_specifications(fonts.names.collectfiles(string.topattern(pattern,true),reload,all),info)
        elseif filter then
            logs.report("fontnames","not supported: --list --spec",name)
        elseif given then
            --~ mtxrun --script font --list --file somename
            list_specifications(fonts.names.collectfiles(given,reload,all),info)
        else
            logs.report("fontnames","not supported: --list --file <no specification>",name)
        end
    elseif pattern then
        --~ mtxrun --script font --list --pattern=*somename*
       list_matches(fonts.names.list(string.topattern(pattern,true),reload,all),info)
    elseif given then
        --~ mtxrun --script font --list somename
        list_matches(fonts.names.list(given,reload,all),info)
    else
        logs.report("fontnames","not supported: --list <no specification>",name)
    end

end

function scripts.fonts.save()
    local name = environment.files[1] or ""
    local sub  = environment.files[2] or ""
    local function save(savename,fontblob)
        if fontblob then
            savename = savename:lower() .. ".lua"
            logs.simple("fontsave, saving data in %s",savename)
            table.tofile(savename,fontloader.to_table(fontblob),"return")
            fontloader.close(fontblob)
        end
    end
    if name and name ~= "" then
        local filename = resolvers.find_file(name) -- maybe also search for opentype
        if filename and filename ~= "" then
            local suffix = file.extname(filename)
            if suffix == 'ttf' or suffix == 'otf' or suffix == 'ttc' or suffix == "dfont" then
                local fontinfo = fontloader.info(filename)
                if fontinfo then
                    logs.simple("font: %s located as %s",name,filename)
                    if fontinfo[1] then
                        for k=1,#fontinfo do
                            local v = fontinfo[k]
                            save(v.fontname,fontloader.open(filename,v.fullname))
                        end
                    else
                        save(fontinfo.fullname,fontloader.open(filename))
                    end
                else
                    logs.simple("font: %s cannot be read",filename)
                end
            else
                logs.simple("font: %s not saved",filename)
            end
        else
            logs.simple("font: %s not found",name)
        end
    else
        logs.simple("font: no name given")
    end
end

logs.extendbanner("ConTeXt Font Database Management 0.21",true)

messages.help = [[
--save                save open type font in raw table

--reload              generate new font database
--reload --simple     generate 'luatex-fonts-names.lua' (not for context!)

--list --name         list installed fonts, filter by name [--pattern]
--list --spec         list installed fonts, filter by spec [--filter]
--list --file         list installed fonts, filter by file [--pattern]

--pattern=str         filter files using pattern
--filter=list         key-value pairs
--all                 show all found instances
--info                give more details
--track=list          enable trackers

examples of searches:

mtxrun --script font --list somename (== --pattern=*somename*)

mtxrun --script font --list --name somename
mtxrun --script font --list --name --pattern=*somename*

mtxrun --script font --list --spec somename
mtxrun --script font --list --spec somename-bold-italic
mtxrun --script font --list --spec --pattern=*somename*
mtxrun --script font --list --spec --filter="fontname=somename"
mtxrun --script font --list --spec --filter="familyname=somename,weight=bold,style=italic,width=condensed"

mtxrun --script font --list --file somename
mtxrun --script font --list --file --pattern=*somename*
]]

local track = environment.argument("track")

if track then trackers.enable(track) end

if environment.argument("names") then
    environment.setargument("reload",true)
    environment.setargument("simple",true)
end

if environment.argument("list") then
    scripts.fonts.list()
elseif environment.argument("reload") then
    scripts.fonts.reload()
elseif environment.argument("save") then
    scripts.fonts.save()
else
    logs.help(messages.help)
end
