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

local type, rawget = type, rawget
local formatters = string.formatters

local fonts             = fonts
local helpers           = fonts.helpers
local fontdata          = fonts.hashes.identifiers

local setmetatableindex = table.setmetatableindex

-- if we run out of space we can think of another range but by sharing we can
-- use these privates for mechanisms like alignments-on-character and such

local currentprivate    = fonts.privateoffsets.textextrabase
local maximumprivate    = currentprivate + 0xFFF

local extraprivates     = utilities.storage.allocate()
local sharedprivates    = utilities.storage.allocate()

helpers.extraprivates   = extraprivates
helpers.sharedprivates  = sharedprivates

function fonts.helpers.addextraprivate(name,f)
    extraprivates[#extraprivates+1] = { name, f }
end

setmetatableindex(sharedprivates,function(t,k)
    local v = currentprivate
    if currentprivate < maximumprivate then
        currentprivate = currentprivate + 1
    else
        -- reuse last slot, todo: warning
    end
    t[k] = v
    return v
end)

function helpers.addprivate(tfmdata,name,characterdata)
    local properties = tfmdata.properties
    local characters = tfmdata.characters
    local privates   = properties.privates
    if not privates then
        privates = { }
        properties.privates = privates
    end
    if not name then
        name = formatters["anonymous_private_0x%05X"](currentprivate)
    end
    local usedprivate = sharedprivates[name]
    privates[name] = usedprivate
    characters[usedprivate] = characterdata
    return usedprivate
end

function helpers.getprivates(tfmdata)
    if type(tfmdata) == "number" then
        tfmdata = fontdata[tfmdata]
    end
    local properties = tfmdata.properties
    return properties and properties.privates
end

function helpers.hasprivate(tfmdata,name)
    if type(tfmdata) == "number" then
        tfmdata = fontdata[tfmdata]
    end
    local properties = tfmdata.properties
    local privates = properties and properties.privates
    return privates and privates[name] or false
end

function helpers.privateslot(name)
    return rawget(sharedprivates,name)
end

function helpers.newprivateslot(name)
    return sharedprivates[name]
end

function helpers.isprivate(unicode)
    if unicode < 0xD7FF or (unicode > 0xDFFF and unicode <= 0xFFFF) then
        return false
    elseif unicode >= 0x00E000 and unicode <= 0x00F8FF then
        return true
    elseif unicode >= 0x0F0000 and unicode <= 0x0FFFFF then
        return true
    elseif unicode >= 0x100000 and unicode <= 0x10FFFF then
        return true
    elseif unicode >= 0x00D800 and unicode <= 0x00DFFF then
        return true
    else
        return false
    end
end

do

    local context = context
    local utfchar = utf.char

    interfaces.implement {
        name      = "privatecharacter",
        public    = true,
     -- protected = true,
        arguments = "string",
        actions   = function(name)
            local c = sharedprivates[name]
            if c then
                context(utfchar(c))
            end
        end
    }

    interfaces.implement {
        name      = "privatecharactercode",
        public    = true,
     -- protected = true,
        arguments = "string",
        actions   = function(name)
            local c = sharedprivates[name]
            if c then
                context(c) -- serialized, not a number
            end
        end
    }

end
