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

-- This module provides a (multipass) container for arbitrary data. It replaces the
-- twopass data mechanism.

local tonumber = tonumber

local context           = context
local ctx_latelua       = context.latelua

local trace_pagestates  = false  trackers.register("job.pagestates", function(v) trace_pagestates = v end)

local report_pagestate  = logs.reporter("pagestate")

local allocate          = utilities.storage.allocate

local texgetcount       = tex.getcount
local texsetcount       = tex.setcount

local new_latelua       = nodes.pool.latelua

local implement         = interfaces.implement
local getnamespace      = interfaces.getnamespace

local c_realpageno      <const> = tex.iscount("realpageno")
local c_realpagestateno <const> = tex.iscount("realpagestateno")

local collected = allocate()
local tobesaved = allocate()

local pagestates = {
    collected = collected,
    tobesaved = tobesaved,
}

job.pagestates = pagestates

local function initializer()
    collected = pagestates.collected
    tobesaved = pagestates.tobesaved
end

job.register("job.pagestates.collected", tobesaved, initializer, nil)

table.setmetatableindex(tobesaved, "table")

local function setstate(settings)
    local name = settings.name
    local tag  = settings.tag
    local list = tobesaved[name]
    if not tag then
        tag = #list + 1
    else
        tag = tonumber(tag) or tag -- autonumber saves keys
    end
    local realpage = texgetcount(c_realpageno)
    local data = realpage
    list[tag] = data
    if trace_pagestates then
        report_pagestate("action %a, name %a, tag %a, preset %a","set",name,tag,realpage)
    end
    return name, tag, data
end

local function extend(name,tag)
    local realpage = texgetcount(c_realpageno)
    if trace_pagestates then
        report_pagestate("action %a, name %a, tag %a, preset %a","synchronize",name,tag,realpage)
    end
    tobesaved[name][tag] = realpage
end

local function realpage(name,tag,default)
    local t = collected[name]
    if t then
        t = t[tag] or t[tonumber(tag)]
        if t then
            return tonumber(t or default)
        elseif trace_pagestates then
            report_pagestate("error: unknown dataset, name %a, tag %a",name,tag)
        end
    elseif trace_pagestates then
        report_pagestate("error: unknown dataset, name %a, tag %a",name) -- nil
    end
    return default
end

local function realpageorder(name,tag)
    local t = collected[name]
    if t then
        local p = t[tag]
        if p then
            local n = 1
            for i=tag-1,1,-1 do
                if t[i] == p then
                    n = n  +1
                end
            end
            return n
        end
    end
    return 0
end

pagestates.setstate      = setstate
pagestates.extend        = extend
pagestates.realpage      = realpage
pagestates.realpageorder = realpageorder

function pagestates.countervalue(name)
    return name and texgetcount(getnamespace("pagestatecounter") .. name) or 0
end

local function setpagestate(settings)
    local name, tag = setstate(settings)
 -- context(new_latelua(function() extend(name,tag) end))
    ctx_latelua(function() extend(name,tag) end) -- better a table and kind
end

local function setpagestaterealpageno(name,tag)
    local t = collected[name]
    t = t and (t[tag] or t[tonumber(tag)])
    texsetcount("realpagestateno",t or texgetcount(c_realpageno))
end

implement {
    name      = "setpagestate",
    actions   = setpagestate,
    arguments = {
        {
            { "name", "argument" },
            { "tag" },
            { "delay" },
        }
    }
}

implement {
    name      = "pagestaterealpage",
    actions   = { realpage, context },
    arguments = "2 strings",
}

implement {
    name      = "setpagestaterealpageno",
    actions   = setpagestaterealpageno,
    arguments = "2 strings",
}

implement {
    name      = "pagestaterealpageorder",
    actions   = { realpageorder, context },
    arguments = { "string", "integer" }
}
