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

-- This is a rather experimental feature and the code will probably
-- change.

local type, tonumber = type, tonumber
local format, gsub = string.format, string.gsub
local formatters = string.formatters

----- lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns

local trace_links    = false  trackers.register("figures.links", function(v) trace_links = v end)
local report_link    = logs.reporter("backend","merging")

local backends       = backends
local lpdf           = lpdf
local context        = context

local variables      = interfaces.variables
local codeinjections = backends.pdf.codeinjections
----- urlescaper     = lpegpatterns.urlescaper
----- utftohigh      = lpegpatterns.utftohigh
local escapetex      = characters.filters.utf.private.escape

local layerspec = { -- predefining saves time
    "epdflinks"
}

local function makenamespace(filename)
    return format("lpdf-epa-%s-",file.removesuffix(file.basename(filename)))
end

local function add_link(x,y,w,h,destination,what)
    x = x .. "bp"
    y = y .. "bp"
    w = w .. "bp"
    h = h .. "bp"
    if trace_links then
        report_link("destination %a, type %a, dx %s, dy %s, wd %s, ht %s",destination,what,x,y,w,h)
    end
    local locationspec = { -- predefining saves time
        x      = x,
        y      = y,
        preset = "leftbottom",
    }
    local buttonspec = {
        width  = w,
        height = h,
        offset = variables.overlay,
        frame  = trace_links and variables.on or variables.off,
    }
    context.setlayer (
        layerspec,
        locationspec,
        function() context.button ( buttonspec, "", { destination } ) end
     -- context.nested.button(buttonspec, "", { destination }) -- time this
    )
end

local function link_goto(x,y,w,h,document,annotation,pagedata,namespace)
    local a = annotation.A
    if a then
        local destination = a.D -- [ 18 0 R /Fit ]
        local what = "page"
        if type(destination) == "string" then
            local destinations = document.destinations
            local wanted = destinations[destination]
            destination = wanted and wanted.D
            if destination then what = "named" end
        end
        local pagedata = destination and destination[1]
        if pagedata then
            local destinationpage = pagedata.number
            if destinationpage then
                add_link(x,y,w,h,namespace .. destinationpage,what)
            end
        end
    end
end

local function link_uri(x,y,w,h,document,annotation)
    local url = annotation.A.URI
    if url then
     -- url = lpegmatch(urlescaper,url)
     -- url = lpegmatch(utftohigh,url)
        url = escapetex(url)
        add_link(x,y,w,h,formatters["url(%s)"](url),"url")
    end
end

local function link_file(x,y,w,h,document,annotation)
    local a = annotation.A
    if a then
        local filename = a.F
        if filename then
            filename = escapetex(filename)
            local destination = a.D
            if not destination then
                add_link(x,y,w,h,formatters["file(%s)"](filename),"file")
            elseif type(destination) == "string" then
                add_link(x,y,w,h,formatters["%s::%s"](filename,destination),"file (named)")
            else
                destination = destination[1] -- array
                if tonumber(destination) then
                    add_link(x,y,w,h,formatters["%s::page(%s)"](filename,destination),"file (page)")
                else
                    add_link(x,y,w,h,formatters["file(%s)"](filename),"file")
                end
            end
        end
    end
end

function codeinjections.mergereferences(specification)
    if figures and not specification then
        specification = figures and figures.current()
        specification = specification and specification.status
    end
    if specification then
        local fullname = specification.fullname
        local document = lpdf.epdf.load(fullname)
        if document then
            local pagenumber  = specification.page    or 1
            local xscale      = specification.yscale  or 1
            local yscale      = specification.yscale  or 1
            local size        = specification.size    or "crop" -- todo
            local pagedata    = document.pages[pagenumber]
            local annotations = pagedata and pagedata.Annots
            if annotations and annotations.n > 0 then
                local namespace = format("lpdf-epa-%s-",file.removesuffix(file.basename(fullname)))
                local reference = namespace .. pagenumber
                local mediabox = pagedata.MediaBox
                local llx, lly, urx, ury = mediabox[1], mediabox[2], mediabox[3], mediabox[4]
                local width, height = xscale * (urx - llx), yscale * (ury - lly) -- \\overlaywidth, \\overlayheight
                context.definelayer( { "epdflinks" }, { height = height.."bp" , width = width.."bp" })
                for i=1,annotations.n do
                    local annotation = annotations[i]
                    if annotation then
                        local subtype = annotation.Subtype
                        local rectangle = annotation.Rect
                        local a_llx, a_lly, a_urx, a_ury = rectangle[1], rectangle[2], rectangle[3], rectangle[4]
                        local x, y = xscale * (a_llx -   llx), yscale * (a_lly -   lly)
                        local w, h = xscale * (a_urx - a_llx), yscale * (a_ury - a_lly)
                        if subtype  == "Link" then
                            local a = annotation.A
                            if a then
                                local linktype = a.S
                                if linktype == "GoTo" then
                                    link_goto(x,y,w,h,document,annotation,pagedata,namespace)
                                elseif linktype == "GoToR" then
                                    link_file(x,y,w,h,document,annotation)
                                elseif linktype == "URI" then
                                    link_uri(x,y,w,h,document,annotation)
                                elseif trace_links then
                                    report_link("unsupported link annotation %a",linktype)
                                end
                            else
                                report_link("mising link annotation")
                            end
                        elseif trace_links then
                            report_link("unsupported annotation %a",subtype)
                        end
                    elseif trace_links then
                        report_link("broken annotation, index %a",i)
                    end
                end
                context.flushlayer { "epdflinks" }
             -- context("\\gdef\\figurereference{%s}",reference) -- global
                context.setgvalue("figurereference",reference) -- global
                if trace_links then
                    report_link("setting figure reference to %a",reference)
                end
                specification.reference = reference
                return namespace
            end
        end
    end
    return ""-- no namespace, empty, not nil
end

function codeinjections.mergeviewerlayers(specification)
    -- todo: parse included page for layers
    if true then
        return
    end
    if not specification then
        specification = figures and figures.current()
        specification = specification and specification.status
    end
    if specification then
        local fullname = specification.fullname
        local document = lpdf.epdf.load(fullname)
        if document then
            local namespace = format("lpdf:epa:%s:",file.removesuffix(file.basename(fullname)))
            local layers = document.layers
            if layers then
                for i=1,layers.n do
                    local layer = layers[i]
                    if layer then
                        local tag = namespace .. gsub(layer," ",":")
                        local title = tag
                        if trace_links then
                            report_link("using layer %a",tag)
                        end
                        attributes.viewerlayers.define { -- also does some cleaning
                            tag       = tag, -- todo: #3A or so
                            title     = title,
                            visible   = variables.start,
                            editable  = variables.yes,
                            printable = variables.yes,
                        }
                        codeinjections.useviewerlayer(tag)
                    elseif trace_links then
                        report_link("broken layer, index %a",i)
                    end
                end
            end
        end
    end
end

