if not modules then modules = { } end modules ['good-gen'] = {
    version   = 1.000,
    comment   = "companion to font-lib.mkiv",
    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
    copyright = "PRAGMA ADE / ConTeXt Development Team",
    license   = "see context related readme files"
}

-- depends on ctx

local type, next = type, next
local lower = string.lower
local filesuffix, replacesuffix = file.suffix, file.replacesuffix
local fonts = fonts

----- trace_goodies  = false  trackers.register("fonts.goodies", function(v) trace_goodies = v end)
----- report_goodies = logs.reporter("fonts","goodies")

local allocate       = utilities.storage.allocate
local texsp          = tex.sp
local fontgoodies    = fonts.goodies or { }
local findfile       = resolvers.findfile


local typefaces      = fonts.typefaces or { }
fonts.typefaces      = typefaces

-- the following takes care of explicit file specifications
--
-- files = {
--     name = "antykwapoltawskiego",
--     list = {
--         ["AntPoltLtCond-Regular.otf"] = {
--          -- name   = "antykwapoltawskiego",
--             style  = "regular",
--             weight = "light",
--             width  = "condensed",
--         },
--     },
-- }

-- files

local function initialize(goodies)
    local files = goodies.files
    if files then
        fonts.names.register(files)
    end
end

fontgoodies.register("files", initialize)

-- some day we will have a define command and then we can also do some
-- proper tracing
--
-- fonts.typefaces["antykwapoltawskiego-condensed"] = {
--     shortcut     = "rm",
--     shape        = "serif",
--     fontname     = "antykwapoltawskiego",
--     normalweight = "light",
--     boldweight   = "medium",
--     width        = "condensed",
--     size         = "default",
--     features     = "default",
-- }

local function initialize(goodies)
    local typefaces = goodies.typefaces
    if typefaces then
        local ft = fonts.typefaces
        for k, v in next, typefaces do
            ft[k] = v
        end
    end
end

fontgoodies.register("typefaces", initialize)

local compositions = { }

function fontgoodies.getcompositions(tfmdata)
    return compositions[file.nameonly(tfmdata.properties.filename or "")]
end

local function initialize(goodies)
    local gc = goodies.compositions
    if gc then
        for k, v in next, gc do
            compositions[k] = v
        end
    end
end

fontgoodies.register("compositions", initialize)

-- extra treatments (on top of defaults): \loadfontgoodies[mytreatments]

local treatmentdata = fonts.treatments.data

local function initialize(goodies)
    local treatments = goodies.treatments
    if treatments then
        for name, data in next, treatments do
            treatmentdata[name] = data -- always wins
        end
    end
end

fontgoodies.register("treatments", initialize)

local filenames       = fontgoodies.filenames or allocate()
fontgoodies.filenames = filenames

local filedata        = filenames.data or allocate()
filenames.data        = filedata

local function initialize(goodies) -- design sizes are registered global
    local fn = goodies.filenames
    if fn then
        for usedname, alternativenames in next, fn do
            filedata[usedname] = alternativenames
        end
    end
end

fontgoodies.register("filenames", initialize)

function fontgoodies.filenames.resolve(name)
    local fd = filedata[name]
    if fd and findfile(name) == "" then
        for i=1,#fd do
            local fn = fd[i]
            if findfile(fn) ~= "" then
                return fn
            end
        end
    elseif filesuffix(name) == "any" then
        -- This is a bit weird place but it's a kind of fallback option in case
        -- we can't resolve due to a name conflict.
        local sequence = fonts.readers.sequence
        for i=1,#sequence do
            local fn = replacesuffix(name,sequence[i])
            if findfile(fn) ~= "" then
                return fn
            end
        end
    else
        -- no lookup, just use the regular mechanism
    end
    return name
end

local designsizes       = fontgoodies.designsizes or allocate()
fontgoodies.designsizes = designsizes

local designdata        = designsizes.data or allocate()
designsizes.data        = designdata

local function initialize(goodies) -- design sizes are registered global
    local gd = goodies.designsizes
    if gd then
        for name, data in next, gd do
            local ranges = { }
            for size, file in next, data do
                if size ~= "default" then
                    ranges[#ranges+1] =  { texsp(size), file } -- also lower(file)
                end
            end
            table.sort(ranges,function(a,b) return a[1] < b[1] end)
            designdata[lower(name)] = { -- overloads, doesn't merge!
                default = data.default,
                ranges  = ranges,
            }
        end
    end
end

fontgoodies.register("designsizes", initialize)

function fontgoodies.designsizes.register(name,size,specification)
    local d = designdata[name]
    if not d then
        d = {
            ranges  = { },
            default = nil, -- so we have no default set
        }
        designdata[name] = d
    end
    if size == "default" then
        d.default = specification
    else
        if type(size) == "string" then
            size = texsp(size) -- hm
        end
        local ranges = d.ranges
        ranges[#ranges+1] = { size, specification }
    end
end

function fontgoodies.designsizes.filename(name,spec,size) -- returns nil of no match
    local data = designdata[lower(name)]
    if data then
        if not spec or spec == "" or spec == "default" then
            return data.default
        elseif spec == "auto" then
            local ranges = data.ranges
            if ranges then
                for i=1,#ranges do
                    local r = ranges[i]
                    if r[1] >= size then -- todo: rounding so maybe size - 100
                        return r[2]
                    end
                end
            end
            return data.default or (ranges and ranges[#ranges][2])
        end
    end
end
