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

-- We don't support late literals unless it's really needed by some third party
-- code.

local context = context
local lpdf    = lpdf

local pdfreserveobject = lpdf.reserveobject
local pdfcompresslevel = lpdf.compresslevel
local pdfobject        = lpdf.object
local pdfpagereference = lpdf.pagereference
local pdfgetxformname  = lpdf.getxformname
local pdfminorversion  = lpdf.minorversion
local pdfmajorversion  = lpdf.majorversion

local tokenscanners    = tokens.scanners
local scanword         = tokenscanners.word
local scankeyword      = tokenscanners.keyword
local scanstring       = tokenscanners.string
local scaninteger      = tokenscanners.integer
local scanwhd          = tokenscanners.whd

local values           = tokens.values
local dimension_value  <const> = values.dimension
local cardinal_value   <const> = values.cardinal
local integer_value    <const> = values.integer

local immediate_code   <const> = tex.flagcodes.immediate

local trace            = false  trackers.register("backend.primitives", function(v) trace = v end)
local report           = logs.reporter("backend")

local nodepool         = nodes.pool
local newliteral       = nodepool.literal
local newsave          = nodepool.save
local newrestore       = nodepool.restore
local newsetmatrix     = nodepool.setmatrix

local implement        = interfaces.implement
local constants        = interfaces.constants

-- literals

local function pdf_literal()
    context(newliteral(scanword() or "origin",scanstring()))
end

-- objects

local lastobjnum = 0

local function pdf_obj(prefix)
    if scankeyword("reserveobjnum") then
        lastobjnum = pdfreserveobject()
        if trace then
            report("\\pdfobj reserveobjnum: object %i",lastobjnum)
        end
    else
        local immediate    = prefix and (prefix & immediate_code) ~= 0 -- was just "true"
        local objnum       = scankeyword("useobjnum") and scaninteger() or pdfreserveobject()
        local uncompress   = scankeyword("uncompressed") or pdfcompresslevel() == 0
        local streamobject = scankeyword("stream")
        local attributes   = scankeyword("attr") and scanstring() or nil
        local fileobject   = scankeyword("file")
        local content      = scanstring()
        local object = streamobject and {
            type          = "stream",
            objnum        = objnum,
            immediate     = immediate,
            attr          = attributes,
            compresslevel = uncompress and 0 or nil,
        } or {
            type          = "raw",
            objnum        = objnum,
            immediate     = immediate,
        }
        if fileobject then
            object.file = content
         -- object.filename = content
        else
            object.string = content
        end
        pdfobject(object)
        lastobjnum = objnum
        if trace then
            report("\\pdfobj: object %i",lastobjnum)
        end
    end
end

local function pdf_lastobj()
    if trace then
        report("\\lastobj: object %i",lastobjnum)
    end
    return cardinal_value, lastobjnum
end

local function pdf_pagereference()
    return cardinal_value, pdfpagereference()
end

local function pdf_refobj()
    local objnum = scaninteger()
    if trace then
        report("\\refobj: object %i (todo)",objnum)
    end
end

-- annotations

local lastobjnum = 0

local function pdf_annot()
    if scankeyword("reserveobjnum") then
        lastobjnum = pdfreserveobject()
        if trace then
            report("\\pdfannot reserveobjnum: object %i",lastobjnum)
        end
    else
        local width  = false
        local height = false
        local depth  = false
        local data   = false
        local object = false
        local attr   = false
        --
        if scankeyword("useobjnum") then
            object = scancount()
            report("\\pdfannot useobjectnum is not (yet) supported")
        end
        local width, height, depth = scanwhd()
        if scankeyword("attr") then
            attr = scanstring()
        end
        data = scanstring()
        context(backends.nodeinjections.annotation(width or 0,height or 0,depth or 0,data or ""))
    end
end

local function pdf_dest()
    local name   = false
    local zoom   = false
    local view   = false
    local width  = false
    local height = false
    local depth  = false
    if scankeyword("num") then
        report("\\pdfdest num is not (yet) supported")
    elseif scankeyword("name") then
        name = scanstring()
    end
    if scankeyword("xyz") then
        view = "xyz"
        if scankeyword("zoom") then
            report("\\pdfdest zoom is ignored")
            zoom = scancount() -- will be divided by 1000 in the backend
        end
    elseif scankeyword("fitbh") then
        view = "fitbh"
    elseif scankeyword("fitbv") then
        view = "fitbv"
    elseif scankeyword("fitb") then
        view = "fitb"
    elseif scankeyword("fith") then
        view = "fith"
    elseif scankeyword("fitv") then
        view = "fitv"
    elseif scankeyword("fitr") then
        view = "fitr"
        width, height, depth = scanwhd()
    elseif scankeyword("fit") then
        view = "fit"
    end
    context(backends.nodeinjections.destination(width or 0,height or 0,depth or 0,{ name or "" },view or "fit"))
end

-- management

local function pdf_save()
    context(newsave())
end

local function pdf_restore()
    context(newrestore())
end

local function pdf_setmatrix()
    context(newsetmatrix(scanstring()))
end

-- extras

-- extensions: literal dest annot save restore setmatrix obj refobj colorstack
-- startlink endlink startthread endthread thread outline glyphtounicode fontattr
-- mapfile mapline includechars catalog info names trailer

local extensions = {
    literal   = pdf_literal,
    obj       = pdf_obj,
    refobj    = pdf_refobj,
    dest      = pdf_dest,
    annot     = pdf_annot,
    save      = pdf_save,
    restore   = pdf_restore,
    setmatrix = pdf_setmatrix,
}

local function pdf_extension()
    local w = scanword(false)
    if w then
        local e = extensions[w]
        if e then
            e()
        else
            report("\\pdfextension: unsupported %a",w)
        end
    end
end

-- feedbacks: colorstackinit creationdate fontname fontobjnum fontsize lastannot
-- lastlink lastobj pageref retval revision version xformname

local feedbacks = {
    lastobj   = pdf_lastobj,
    pageref   = pdf_pagereference,
    xformname = function() context(pdfgetxformname ()) end,
}

local function pdf_feedback()
    local w = scanword(false)
    if w then
        local f = feedbacks[w]
        if f then
            return f()
        else
            report("\\pdffeedback: unsupported %a",w)
        end
    end
end

-- variables: (integers:) compresslevel decimaldigits gamma gentounicode
-- ignoreunknownimages imageaddfilename imageapplygamma imagegamma imagehicolor
-- imageresolution inclusioncopyfonts inclusionerrorlevel majorversion minorversion
-- objcompresslevel omitcharset omitcidset pagebox pkfixeddpi pkresolution
-- recompress suppressoptionalinfo uniqueresname (dimensions:) destmargin horigin
-- linkmargin threadmargin vorigin xformmargin (tokenlists:) pageattr pageresources
-- pagesattr pkmode trailerid xformattr xformresources

local variables = {
    minorversion = function() context(pdfminorversion()) end,
    majorversion = function() context(pdfmajorversion()) end,
}

local function pdf_variable()
    local w = scanword(false)
    if w then
        local f = variables[w]
        if f then
            f()
        else
            report("\\pdfvariable: unsupported %a",w)
        end
    else
        print("missing variable")
    end
end

-- kept (also because tikz needs including the pdftex primitives):

implement { name = "pdfextension", actions = pdf_extension, public = true, untraced = true } -- , protected = true }
implement { name = "pdffeedback",  actions = pdf_feedback,  public = true, usage = "value", untraced = true } -- expandable / todo : value
implement { name = "pdfvariable",  actions = pdf_variable,  public = true, untraced = true } -- expandable / todo : value
implement { name = "pdfliteral",   actions = pdf_literal,   public = true, untraced = true, protected = true }
implement { name = "pdfobj",       actions = pdf_obj,       public = true, usage = "value", protected = true }
implement { name = "pdflastobj",   actions = pdf_lastobj,   public = true, usage = "value", protected = true }
implement { name = "pdfrefobj",    actions = pdf_refobj,    public = true, untraced = true, protected = true }

--------- { name = "pdfannot",     actions = pdf_annot }
--------- { name = "pdfdest",      actions = pdf_dest }
--------- { name = "pdfsave",      actions = pdf_save }
--------- { name = "pdfrestore",   actions = pdf_restore }
--------- { name = "pdfsetmatrix", actions = pdf_setmatrix }

-- implement {
--     name      = "pdfstrcmp",
--     arguments = "2 strings",
--     usage     = "value",
--     public    = true,
--     actions   = function(a,b) return integer_value, (a < b and -1) or (a > b and 1) or 0 end
-- }
