strc-ref.mkvi / last modification: 2020-01-30 14:16
%D \module
%D   [       file=strc-ref,
%D        version=2008.10.20,
%D          title=\CONTEXT\ Structure Macros,
%D       subtitle=Cross Referencing,
%D         author=Hans Hagen,
%D           date=\currentdate,
%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.

% todo: (1) configure references, (2) rendering => with presets
%
% \defineconversionset[default][Character,number,Romannumerals,Character][number]
% \defineseparatorset [default][.,.,--][.]
% \setuphead[subsection][sectionstopper=),sectionsegments=4:4]
% \setupreferencestructureprefix[default][prefixsegments=2:4]
% \setupreferencestructureprefix[figure][default][prefixsegments=3:4]
% \chapter {One}
% \section {One}
% \subsection[sec:test]{Two}
% See \in[sec:test] and \in[fig:xx] and \in[fig:yy]
% \placefigure[here][fig:xx]{}{}
% \placefigure[here][fig:yy]{}{}

\writestatus{loading}{ConTeXt Structure Macros / Cross Referencing}

\registerctxluafile{strc-rsc}{}
\registerctxluafile{strc-ref}{}
\registerctxluafile{node-ref}{optimize}

\unprotect

% todo : unknown/illegal reference no arg
% todo : +n pages check on 'samepage' (contrastcolor)
% todo : multiple text in reference

% Makes more sense to build action data first, especially now
% openaction etc are supported.
%
% \definespecial\doexecuteactionchain w h
% \definespecial\dosetgotolocation
% \definespecial\dosetexecuteJScode
% ...

%D This module deals with referencing. In \CONTEXT\ referencing is one of the core
%D features, although at a first glance probably nobody will notice. This is good,
%D because referencing should be as hidden as possible.
%D
%D Before we start implementing functionality we provide a way to set up this
%D mechanism.
%D
%D \showsetup{setupreferencing}
%D
%D In interactive documents verbose references don't always make sense (what is a
%D page number in an unnumbered document). By setting the \type{interaction}
%D variable, one can influences the way interactive references are set.

\let\referenceprefix\empty

\installcorenamespace{referencing}

\installdirectcommandhandler \??referencing {referencing} % \??referencing

\newif\ifreferencing \referencingtrue

\appendtoks
    \edef\p_state{\referencingparameter\c!state}%
    \ifx\p_state\v!start
      \referencingtrue
    \else
      \referencingfalse
    \fi
\to \everysetupreferencing

%D In paper documents, referencing comes down to cross referencing, but in
%D their interactive counterparts, is also involves navigation. Many features
%D implemented here are therefore closely related to navigation.
%D
%D Many \CONTEXT\ commands can optionally be fed with a reference. Such a
%D reference, when called upon, returns the number of a figure, table, chapter
%D etc, a piece of text, or a pagenumber.
%D
%D There are three ways of defining a reference:
%D
%D \starttyping
%D \pagereference[here]
%D \textreference[here]{some text}
%D \stoptyping
%D
%D the third alternative combines them in:
%D
%D \starttyping
%D \reference[here]{some text}
%D \stoptyping

\unexpanded\def\textreference {\dosingleargument\strc_references_text_reference} % no need for \dosingle
\unexpanded\def\pagereference {\dosingleargument\strc_references_page_reference} % as they're mandate and
\unexpanded\def\reference     {\dosingleargument\strc_references_full_reference} % never forgotten
\unexpanded\def\setreference  {\dodoubleargument\strc_references_set_reference } %

% maybe: \let\reference\textreference

\unexpanded\def\showreferences
  {\enabletrackers[nodes.references.show,nodes.destinations.show]}

%D These are implemented in a low level form as:

\unexpanded\def\strc_references_text_reference          [#labels]{\strc_references_set_named_reference\s!text{#labels}{}}
\unexpanded\def\strc_references_page_reference          [#labels]{\strc_references_set_named_reference\s!page{#labels}{}{}}
\unexpanded\def\strc_references_full_reference          [#labels]{\strc_references_set_named_reference\s!full{#labels}{}}
\unexpanded\def\strc_references_set_reference[#labels][#settings]{\strc_references_set_named_reference\s!user{#labels}{#settings}{}}

\unexpanded\def\dosetdirectpagereference#1{\strc_references_set_named_reference\s!page{#1}{}{}} % low level, maybe use _

\unexpanded\def\usereferenceparameter#1% faster local variant
  {\edef\m_strc_references_asked{#1\c!reference}%
   \ifx\m_strc_references_asked\empty\else
     \dosetdirectpagereference\m_strc_references_asked
   \fi}

%D Actually there is not much difference between a text and a full reference, but
%D it's the concept that counts. The low level implementation is:

\newcount\lastreferenceattribute
\newcount\lastdestinationattribute

\def\strc_references_finish#prefix#reference#internal%
  {\normalexpanded{\clf_deferredenhancereference{#prefix}{#reference}}}

\let\dofinishreference\strc_references_finish % used at lua end

%D This is somewhat tricky: we want to keep the reference with the following word but
%D that word should also hyphenate. We need to find a better way.

% 0 = nothing
% 1 = bind to following word

\setnewconstant\c_strc_references_bind_state\plusone

\def\strc_references_inject_before
  {}

\def\strc_references_inject_after
  {\ifcase\c_strc_references_bind_state
     % nothing
   \or
     \prewordbreak % to be tested: \removeunwantedspaces\permithyphenation
   \fi}


\unexpanded\def\strc_references_set_named_reference
  {\ifreferencing
      \expandafter\strc_references_set_named_reference_indeed
   \else
      \expandafter\gobblefourarguments
   \fi}

\newbox\b_strc_destination_nodes

\unexpanded\def\strc_references_flush_destination_nodes
  {\ifvoid\b_strc_destination_nodes \else
     \unhbox\b_strc_destination_nodes
   \fi}

\def\strc_references_placeholder
  {\ifx\dotaggedplaceholder\empty\else
     \attribute\destinationattribute\lastdestinationattribute
     \dotaggedplaceholder
   \fi}

\unexpanded\def\strc_references_destination_point_yes
  {\strc_references_inject_before % new
   \dostarttagged\t!reference\empty
   \dontleavehmode\hbox attr \destinationattribute\lastdestinationattribute\bgroup
     \strc_references_flush_destination_nodes
     \strc_references_placeholder
     \egroup
   \dostoptagged
   \strc_references_inject_after}

\unexpanded\def\strc_references_destination_point_nop
  {\strc_references_inject_before % new
   \dostarttagged\t!reference\empty
   \dontleavehmode\hbox \bgroup
     \strc_references_flush_destination_nodes
     \strc_references_placeholder
   \egroup
   \dostoptagged
   \strc_references_inject_after}

\unexpanded\def\strc_references_start_destination_nodes % messy but we need the delay
  {\setbox\b_strc_destination_nodes\hbox\bgroup}        % also sets lastdestinationattribute

\unexpanded\def\strc_references_stop_destination_nodes
  {\normalexpanded{\egroup\lastdestinationattribute\the\lastdestinationattribute\relax}}

\unexpanded\def\strc_references_set_named_reference_indeed#kind#labels#userdata#text% labels userdata text -> todo: userdata
  {\ifreferencing
     % we could have a more efficient one for page references but for the moment
     % we don't care too much
     \edef\currentreferencekind     {#kind}%
     \edef\currentreferencelabels   {#labels}%
     \edef\currentreferenceuserdata {#userdata}%
     \edef\currentreferenceexpansion{\referencingparameter\c!expansion}% {\referenceparameter\c!expansion}
     \ifx\currentreferencelabels\empty
       \lastdestinationattribute\attributeunsetvalue
     \else
       \ifx\currentreferenceexpansion\s!xml
         \xmlstartraw
           \xdef\currentreferencedata{#text}% data, no text else conflict
         \xmlstopraw
         \glet\currentreferencecoding\s!xml
       \else
         \ifx\currentreferenceexpansion\v!yes
           \xdef\currentreferencedata{#text}%
         \else
           \xdef\currentreferencedata{\detokenize{#text}}%
         \fi
         \glet\currentreferencecoding\s!tex
       \fi
       % beware, the structures.references.set writes a
       \setnextinternalreference
       \strc_references_start_destination_nodes
       \clf_setdestinationattribute
            {%
                references {%
                    internal  \locationcount
                  % block     {\currentsectionblock}%
                    view      {\interactionparameter\c!focus}%
                \ifx\referenceprefix\empty\else
                    prefix    {\referenceprefix}%
                \fi
                    reference {\currentreferencelabels}%
                }%
                metadata {%
                    kind     {\currentreferencekind}%
            \ifx\currentreferencekind\s!page\else
                \ifx\currentreferencecoding\s!xml
                    xmlroot  {\xmldocument}%
                \fi
                    catcodes \catcodetable
            \fi
                }%
            \ifx\currentreferencedata\empty\else
                entries {%
                    text {\currentreferencedata}%
                }%
            \fi
            \ifx\currentreferenceuserdata\empty\else
                userdata {\detokenize{#userdata}}%
            \fi
            }%
       \relax
       \strc_references_stop_destination_nodes
     \fi
   \else
     \setbox\b_strc_destination_nodes\emptyhbox
     \lastdestinationattribute\attributeunsetvalue
   \fi
   % will become obsolete:
   \xdef\currentdestinationattribute{\number\lastdestinationattribute}%
   % will become an option:
   \ifnum\lastdestinationattribute>\zerocount
     \strc_references_destination_point_yes
   \else\ifvoid\b_strc_destination_nodes\else
     \strc_references_destination_point_nop
   \fi\fi}

\def\strc_references_set_page_only_destination_attribute#labels% could in fact be fully expandable
  {\ifreferencing
     \edef\currentreferencelabels{#labels}%
     \ifx\currentreferencelabels\empty
       \setbox\b_strc_destination_nodes\emptyhbox
       \lastdestinationattribute\attributeunsetvalue
     \else
       \strc_references_start_destination_nodes
       \setnextinternalreference
       \clf_setdestinationattribute
            {%
                references {%
                    internal  \locationcount
                 %  block     {\currentsectionblock}%
                    view      {\interactionparameter\c!focus}%
                \ifx\referenceprefix\empty\else
                    prefix    {\referenceprefix}%
                \fi
                    reference {\currentreferencelabels}%
                }%
                metadata {%
                    kind {page}%
                }%
            }%
       \relax
       \strc_references_stop_destination_nodes
     \fi
   \else
     \setbox\b_strc_destination_nodes\emptyhbox
     \lastdestinationattribute\attributeunsetvalue
   \fi}

\unexpanded\def\strc_references_direct_full_user#user#labels#text%
  {\ifreferencing
     \strc_references_start_destination_nodes
     \setnextinternalreference
     \edef\m_strc_references_user{#user}%
     \edef\m_strc_references_text{#text}%
     \clf_setdestinationattribute
        {%
            references {%
                internal  \locationcount
              % block     {\currentsectionblock}%
                view      {\interactionparameter\c!focus}%
            \ifx\referenceprefix\empty\else
                prefix    {\referenceprefix}%
            \fi
                reference {#labels}%
            }%
            metadata {%
                kind {\s!full}%
            }%
        \ifx\m_strc_references_text\empty \else
            entries {%
                text {\m_strc_references_text}%
            }%
        \fi
        \ifx\m_strc_references_user\empty \else
            userdata {\m_strc_references_user}% \detokenize\expandafter{\normalexpanded{...}}
        \fi
        }%
     \relax
     \strc_references_stop_destination_nodes
   \else
     \setbox\b_strc_destination_nodes\emptyhbox
     \lastdestinationattribute\attributeunsetvalue
   \fi
   % will become obsolete:
   \xdef\currentdestinationattribute{\number\lastdestinationattribute}%
   % will become an option:
   \ifnum\lastdestinationattribute>\zerocount
     \strc_references_destination_point_yes
   \else\ifvoid\b_strc_destination_nodes\else
     \strc_references_destination_point_nop
   \fi\fi}

\unexpanded\def\strc_references_direct_full
  {\strc_references_direct_full_user\empty}

\let\dodirectfullreference\strc_references_direct_full % for at lua end (no longer)

\def\strc_references_set_page_only_destination_box_attribute#cs#labels%
  {\strc_references_set_page_only_destination_attribute{#labels}%
   \ifnum\lastdestinationattribute>\zerocount
     \edef#cs{attr \destinationattribute\number\lastdestinationattribute}%
   \else
     \let#cs\empty
   \fi}

%D It's about time to clean up references .. stable enough now.

\unexpanded\def\boxreference[#1]%
  {\begingroup
   \dowithnextbox
    {\strc_references_set_page_only_destination_attribute{#1}%
     \hpack % \hbox
       \ifnum\lastdestinationattribute=\attributeunsetvalue\else attr \destinationattribute \lastdestinationattribute \fi
       {\box\b_strc_destination_nodes\box\nextbox}%
     \endgroup}}

\unexpanded\def\hboxreference[#1]{\boxreference[#1]\hbox}
\unexpanded\def\vboxreference[#1]{\boxreference[#1]\vbox}

% \ifx\currentdestinationattribute\empty
%   \begingroup\attribute\destinationattribute\currentdestinationattribute\emptyhbox\endgroup % todo
% \fi

\def\defaultreferencepage#text{[[[#text]]]}
\def\defaultreferencetext#text{[[[#text]]]}

%D For internal usage:

\def\strc_references_set_simple_reference#label%
  {\iflocation
     \strc_references_start_destination_nodes
     \setnextinternalreference
     \clf_setdestinationattribute
        {%
            references {%
                view      {\interactionparameter\c!focus}%
            \ifx\referenceprefix\empty\else
                prefix    {\referenceprefix}%
            \fi
                reference {#label}%
                internal  \locationcount
            }%
            metadata {%
                kind {\s!page}%
            }%
        }%
     \relax
     \strc_references_stop_destination_nodes
     \xdef\currentdestinationattribute{\number\lastdestinationattribute}%
   \else
     \setbox\b_strc_destination_nodes\emptyhbox
     \xdef\currentdestinationattribute{\number\attributeunsetvalue}%
   \fi}

\def\strc_references_set_simple_internal_reference#label% no prefix
  {\iflocation
     \strc_references_start_destination_nodes
     \setnextinternalreference
     \clf_setdestinationattribute
        {%
            references {%
                view      {\interactionparameter\c!focus}%
                reference {#label}%
                internal  \locationcount
            }%
            metadata {%
                kind {\s!page}%
            }%
        }%
     \relax
     \strc_references_stop_destination_nodes
     \xdef\currentdestinationattribute{\number\lastdestinationattribute}%
   \else
     \setbox\b_strc_destination_nodes\emptyhbox
     \xdef\currentdestinationattribute{\number\attributeunsetvalue}%
   \fi}

\def\strc_references_get_simple_reference#label%
  {\iflocation
     \clf_injectreference
        {\referenceprefix}%
        {#label}%
        {%
            height \ht\strutbox
            depth  \dp\strutbox
            \extrareferencearguments
        }%
     \relax
     \xdef\currentreferenceattribute{\number\lastreferenceattribute}%
   \else
     \xdef\currentreferenceattribute{\number\attributeunsetvalue}%
   \fi}

%D \macros
%D   {contentreference}
%D
%D \starttyping
%D \setupinteraction
%D   [state=start,
%D    focus=standard]
%D
%D \setupheader
%D   [state=stop]
%D
%D  See page \goto{page 2}[page2] \page
%D
%D  \contentreference
%D    [page2]
%D    [offset=1cm,toffset=2cm,frame=on]
%D    {\externalfigure[cow.pdf][factor=fit]}
%D
%D \stoptyping

\unexpanded\def\contentreference
  {\hbox\bgroup
   \dodoubleempty\strc_references_content_pickup}

\def\strc_references_content_pickup
  {\ifsecondargument
     \expandafter\strc_references_content_pickup_yes
   \else
     \expandafter\strc_references_content_pickup_nop
   \fi}

\def\strc_references_content_pickup_yes[#1][#2]%
 {\dowithnextbox{\strc_references_content_yes_finish{#1}{#2}}\hbox}

\def\strc_references_content_pickup_nop[#1][#2]%
 {\dowithnextbox{\strc_references_content_nop_finish{#1}{#2}}\hbox}

\def\strc_references_content_yes_finish#1#2%
  {\scratchwidth \wd\nextbox
   \scratchheight\ht\nextbox
   \scratchdepth \dp\nextbox
   \setbox\nextbox\hpack
     {\framed[\c!frame=\v!off,#2]{\box\nextbox}}%
   \strc_references_set_simple_reference{#1}%
   \setbox\nextbox\hpack attr \destinationattribute \currentdestinationattribute % \hpack ?
     {\strc_references_flush_destination_nodes
      \box\nextbox}%
   \setbox\nextbox\hpack{\box\nextbox}%
   \wd\nextbox\scratchwidth
   \ht\nextbox\scratchheight
   \dp\nextbox\scratchdepth
   \box\nextbox
   \egroup}

\def\strc_references_content_nop_finish#1#2%
  {\strc_references_set_simple_reference{#1}%
   \hpack attr \destinationattribute \currentdestinationattribute % \hpack ?
     {\strc_references_flush_destination_nodes
      \box\nextbox}%
   \egroup}

%D \macros
%D   {everyreference}
%D
%D For rather tricky purposes, one can assign sanitizing macros to \type
%D {\everyreference} (no longer that relevant).

\newevery \everyreference \relax

%D This is really needed, since for instance Polish has a different alphabet and
%D needs accented entries in registers.

\appendtoks
    \cleanupfeatures
\to \everyreference

%D We did not yet discuss prefixing. Especially in interactive documents, it's not
%D always easy to keep track of duplicate references. The prefix mechanism, which we
%D will describe later on, solves this problem. By (automatically) adding a prefix
%D one keeps references local, but the global ones in view. To enable this feature,
%D we explictly split the prefix from the reference.

\let\referenceprefix\empty

%D For a long time the only way to access an external file was to use the file
%D prefix (\type {somefile::}. However, when you split up a document, redefining the
%D references may be such a pain, that another approach is feasible. By setting the
%D \type {autofile} variable to \type {yes} or \type {page}, you can access the
%D reference directly.
%D
%D \starttabulate[||||]
%D \NC filename::tag \NC page(filename::pnum) \NC tag     \NC\NR
%D \NC   $\star$     \NC                      \NC         \NC\NR
%D \NC   $\star$     \NC $\star$              \NC $\star$ \NC\NR
%D \NC               \NC $\star$              \NC         \NC\NR
%D \stoptabulate

\unexpanded\def\usereferences[#filename]{} % obsolete

%D As mentioned we will also use the cross reference mechanism for navigational
%D purposes. The main reason for this is that we want to treat both categories
%D alike:
%D
%D \starttyping
%D \goto{go back}[PreviousJump]
%D \goto{colofon}[colofon page]
%D \stoptyping
%D
%D Here \type{PreviousJump} is handled by the viewer, while the
%D \type{colofon page} reference is, apart from hyperlinking, a
%D rather normal reference.
%D
%D We already saw that cross refences are written to and read from a file. The pure
%D navigational ones don't need to be written to file, but both for fast processing
%D and transparant integration, they are saved internally as a sort of reference. We
%D can easily distinguish such system references from real cross reference ones by
%D their tag.
%D
%D We also use the odd/even characteristic to determine the page state.

\let\currentrealreference      \empty
\let\currentpagereference      \empty
\let\currenttextreference      \empty
\let\currentreferenceorder     \empty
\let\currentsubtextreference   \empty
\let\currentsubsubtextreference\empty

\newcount\referencehastexstate % set in backend

% referencepagestate:
%
% 0 = no page ref, 1=same page, 2=before, 3=after

%D Cross references appear as numbers (figure~1.1, chapter~2) or pagenumbers
%D (page~2, page 3--2), and are called with \type {\in} and \type {\at}. In
%D interactive documents we also have \type {\goto}, \type {\button} and alike.
%D These are more versatile and look like:
%D
%D \starttyping
%D \goto[reference]
%D \goto[outer reference::]
%D \goto[outer reference::inner reference]
%D \goto[operation(argument)]
%D \goto[operation(action{argument,argument})]
%D \goto[action]
%D \goto[action{argument}]
%D \stoptyping
%D
%D The first one is a normal reference, the second and third are references to a
%D file or \URL. The brace delimited references for instance refer to a \JAVASCRIPT.
%D The last example shows that we can pass arguments to the actions.
%D
%D Now we've come to the testing step. As we can see below, this macro does bit more
%D than testing: it also resolves the reference. This means that whenever we test
%D for the existance of a reference at an outer level, we have all the relevant
%D properties of that reference avaliable inside the true branche~(\type {#2}).
%D
%D The prefix has to do with localizing references. When a prefix is set, looking
%D for a reference comes to looking for the prefixed one, and when not found,
%D looking for the non prefixed one. Consider for instance the prefix set to \type
%D {sidetrack}.
%D
%D \starttyping
%D \pagereference[important]
%D \pagereference[unimportant]
%D \setupreferencing[prefix=sidetrack]
%D \pagereference[important]
%D \stoptyping
%D
%D results in saving (writing) the references
%D
%D \starttyping
%D ...{}{important}
%D ...{}{unimportant}
%D ...{sidetrack}{important}...
%D \stoptyping
%D
%D Now when we call for \type{unimportant}, we will indeed get the pagenumber
%D associated to this reference. But when we call for \type{important}, while the
%D prefix is still set, we will get the pagenumber bound to the prefixed one.
%D
%D {\em Some day, when processing time and memory are no longer
%D performance factors, we will introduce multi||level
%D prefixes.}
%D
%D Before we start analyzing, I introduce a general definition macro. Consider:
%D
%D \starttyping
%D \goto{do}[JS(My_Script{"test",123}),titlepage]
%D \stoptyping
%D
%D This can also be achieved by:
%D
%D \starttyping
%D \definereference[startup][JS(My_Script{"test",123}),titlepage]
%D \goto{do}[startup]
%D \stoptyping
%D
%D Now is this is a handy feature or not?
%D
%D \showsetup{definereference}
%D
%D We can trace references by setting the next switch to true.

\unexpanded\def\definereference
  {\dodoubleempty\strc_references_define_reference}

\def\strc_references_define_reference[#name][#specification]%
  {\clf_definereference{\referenceprefix}{#name}{\detokenize{#specification}}}

\unexpanded\def\resetreference[#name]%
  {\clf_resetreference{\referenceprefix}{#name}}

\def\setpagereference#name#specification% hm,. low level ?
  {\clf_definereference{}{#name}{\v!page(\detokenize{#specification}}} % is detokenize needed here?

%D Chained references are defined as:
%D
%D \starttyping
%D \goto{somewhere}[JS(somescript),nextpage,JS(anotherscript)]
%D \stoptyping
%D
%D Actually supporting chains is up to the special driver. Here we only provide the
%D hooks.

%D \macros
%D   {highlighthyperlinks}
%D
%D The next switch can be used to make user hyperlinks are not highlighted when
%D clicked on.

\newconditional\highlighthyperlinks \settrue\highlighthyperlinks

%D \macros
%D   {gotonewwindow}
%D
%D To make the {\em goto previous jump} feature more convenient when using more than
%D one file, it makes sense to force the viewer to open a new window for each file
%D opened.

\newconditional\gotonewwindow \setfalse\gotonewwindow

\def\expandtexincurrentreference % will happen in lua some time
  {\ifcase\referencehastexstate\else\clf_expandcurrentreference\fi}

\def\expandreferenceoperation#tag#content{\clf_setreferenceoperation#tag{#content}}
\def\expandreferencearguments#tag#content{\clf_setreferencearguments#tag{#content}}

\def\doifelsereferencefound#label#yes#nop%
  {\clf_doifelsereference{\referenceprefix}{#label}{\extrareferencearguments}%
     {\expandtexincurrentreference
      #yes}%
     {#nop}}

\let\doifreferencefoundelse \doifelsereferencefound

%D The tester only splits the reference in components but does not look into them.
%D The following macro does a preroll and determines for instance the current real
%D reference pagenumber. The \type {\currentrealreference} macro does the same so
%D unless one wants to use the pagestate the next macro seldom needs to be called.
%D
%D The inner case is simple. Only two cases have to be taken
%D care of:
%D
%D \starttyping
%D \goto{some text}[reference]
%D \goto{some text}[prefix:reference]
%D \stoptyping
%D
%D References to other files however are treated strict or tolerant, depending on
%D their loading and availability:
%D
%D \starttyping
%D \useexternaldocument[somefile][filename][a nice description]
%D
%D \goto{checked   reference}[somefile::reference]
%D \goto{unchecked reference}[somefile::]
%D \goto{unchecked reference}[anotherfile::reference]
%D \stoptyping
%D
%D An unknown reference is reported on the screen, in the log file and, when
%D enabled, in the left margin of the text.

\let\unknownreference\gobbleoneargument

%D When a reference is not found, we typeset a placeholder (two glyphs are often
%D enough to represent the reference text).

\def\dummyreference{{\tttf ??}}
\def\emptyreference{{\tttf !!}}

%D To prevent repetitive messages concerning a reference being defined, we set such
%D an unknown reference to an empty one after the first encounter.
%D
%D Apart from cross references supplied by the user, \CONTEXT\ generates cross
%D references itself. Most of them are not saved as a reference, but stored with
%D their source, for instance a list or an index entry. Such automatically
%D generated, for the user invisible, references are called {\em internal
%D references}. The user supplied ones are labeled as {\em external references}.
%D
%D A second important characteristic is that when we want to support different
%D backends (viewers), we need to support named destinations as well as page
%D numbers. I invite readers to take a glance at the special driver modules to
%D understand the fine points of this. As a result we will deal with {\em locations}
%D as well as {\em real page numbers}. We explictly call this pagenumber a real one,
%D because it is independant of the page numbering scheme used in the document.
%D
%D One of the reasons for \CONTEXT\ being the first \TEX\ base macropackage to
%D support sophisticated interactive \PDF\ files, lays in the mere fact that real
%D page numbers are available in most two pass data, like references, list data and
%D index entries.
%D
%D We will speak of \type {thisis...} when we are marking a location, and
%D \type {goto...} when we point to such a location. The latter one can be seen as a
%D hyperlink to the former one. In the next macros one we use constructs like:
%D
%D \starttyping
%D \dostart...
%D \dostop...
%D \stoptyping
%D
%D The flag \type {\iflocation} signals if we're in interactive mode.

\ifdefined\buttonheight \else \newdimen\buttonheight \fi
\ifdefined\buttonwidth  \else \newdimen\buttonwidth  \fi

%D Internal references can best be set using the next few macros. Setting such
%D references to unique values is completely up to the macros that call them.
%D
%D \starttyping
%D \thisissomeinternal{tag}{identifier}
%D \gotosomeinternal  {tag}{identifier}{pagenumber}{text}
%D \stoptyping
%D
%D We could do this in \LUA\ \unknown

\newif   \iflocation
\newcount\locationcount
\newcount\locationorder
\newbox  \locationbox

\def\nextinternalreference     {\the\locationcount}
\def\nextinternalorderreference{\the\locationorder}

\def\setnextinternalreference
  {\global\advance\locationcount\plusone}

\def\setnextinternalreferences#kind#name% plural
  {\clf_setnextinternalreference{#kind}{#name}}

\def\getinternalorderreference#kind#name%
  {\clf_currentreferenceorder{#kind}{#name}}

\def\thisissomeinternal#kind#name% only for old time sake, will go away
  {\begingroup
   \clf_setinternalreference
     reference {#kind:#name}% no view
   \relax
   \hpack attr \destinationattribute\lastdestinationattribute{}%
   \endgroup}

\installcorenamespace{savedinternalreference}

\letvalue{\??savedinternalreference\s!default}\!!zerocount

\unexpanded\def\storeinternalreference#1#2%
  {\setxvalue{\??savedinternalreference\currentstructurename}{\number#2}}

\newconditional\preferpagereferences

\def\gotosomeinternal#kind#name#target#text%
  {\ifconditional\preferpagereferences
     \directgoto{#text}[page(#target)]%
   \else
     \directgoto{#text}[#kind:#name]%
   \fi}

\def\gotonextinternal#text#target%
  {\directgoto{#text}[internal(#target)]}

%D In this module we define three system references: one for handling navigational,
%D viewer specific, commands, another for jumping to special pages, like the first
%D or last one, and a third reference for linking tree like lists, like tables of
%D contents. The latter two adapt themselves to the current state.
%D
%D An example of an action is:
%D
%D \starttyping
%D \goto{some action}[PreviousJump]
%D \stoptyping
%D
%D as well as:
%D
%D \starttyping
%D \goto{some text}[\v!action(PreviousJump]
%D \stoptyping
%D
%D One can also activate an automatic prefix mechanism. By setting the
%D \type {\prefix} variable to \type {+}, the prefix is incremented, when set to
%D \type {-} or empty, the prefix is reset. Other values become the prefix.

\newcount\prefixcounter

\newconditional\autocrossfilereferences

\appendtoks
    \edef\p_autofile{\referencingparameter\c!autofile}%
    \ifx\p_autofile\v!yes
      \settrue \autocrossfilereferences
    \else
      \setfalse\autocrossfilereferences
    \fi
\to \everysetupreferencing

\appendtoks
    \edef\p_export{\referencingparameter\c!export}%
    \ifx\p_export\v!yes
      \clf_exportreferences
    \fi
\to \everygoodbye

\unexpanded\def\setupglobalreferenceprefix[#prefix]%
  {\xdef\referenceprefix{#prefix}}

\unexpanded\def\globalpushreferenceprefix#prefix%
  {\xdef\referenceprefix{\clf_pushreferenceprefix{#prefix}}}

\unexpanded\def\globalpopreferenceprefix
  {\xdef\referenceprefix{\clf_popreferenceprefix}}

\unexpanded\def\pushreferenceprefix#prefix%
  {\edef\referenceprefix{\clf_pushreferenceprefix{#prefix}}}

\unexpanded\def\popreferenceprefix
  {\edef\referenceprefix{\clf_popreferenceprefix}}

\def\m_strc_references_prefix_yes{+}
\def\m_strc_references_prefix_nop{-}

\unexpanded\def\setupreferenceprefix[#prefix]%
  {\edef\p_prefix{#prefix}%
   \ifx\p_prefix\empty
     \let\referenceprefix\empty
   \else\ifx\p_prefix\m_strc_references_prefix_yes
     \letreferencingparameter\c!prefix\s!unknown
     \global\advance\prefixcounter\plusone
     \edef\referenceprefix{\the\prefixcounter}%
   \else\ifx\p_prefix\m_strc_references_prefix_nop
     \letreferencingparameter\c!prefix\s!unknown
     \let\referenceprefix\empty
   \else\ifx\p_prefix\s!unknown
     % forget about it
   \else
     \let\referenceprefix\p_prefix
   \fi\fi\fi\fi}

\appendtoks
    \setupreferenceprefix[\referencingparameter\c!prefix]
\to \everysetupreferencing

%D We can typeset a reference using \type {\in}, \type {\at} and \type {\about} and
%D goto specific locations using \type {\goto}. The last one does not make that much
%D sense in a paper document. To complicate things, \PLAIN\ \TEX\ also implements an
%D \type {\in} but fortunately that one only makes sense in math mode.
%D
%D Typesetting the reference is a bit more complicated than one would at first sight
%D expect. This is due to the fact that we distinguish three (five) alternative
%D calls:
%D
%D \placefigure
%D   [here][three calls]
%D   {Three alternatives reference calls.}
%D   {\startcombination[1*3]
%D      {\framed{\type{ \in }}} {a}
%D      {\framed{\type{ \at }}} {b}
%D      {\framed{\type{\goto}}} {c}
%D    \stopcombination}
%D
%D \startbuffer
%D \in figure[fig:three calls]
%D \in{figure}[fig:three calls]
%D \in figure a[fig:three calls]
%D \in{figure}{a}[fig:three calls]
%D figure~\in[fig:three calls]
%D \stopbuffer
%D
%D \typebuffer
%D
%D This turns up as:
%D
%D \startlines
%D \getbuffer
%D \stoplines
%D
%D The dual \type {{}} results in a split reference. In a document meant for paper,
%D one is tempted to use the last (most straightforward) alternative. When a
%D document is also meant voor electronic distribution, the former alternatives have
%D preference, because everything between the \type {\in} and~\type {[} becomes
%D active (and when asked for, typeset in a different color and typeface).

\appendtoks
    \ifdefined\in    \let\normalmathin   \in    \unexpanded\def\in   {\mathortext\normalmathin   \strc_references_in   } \else \let\in   \strc_references_in    \fi
    \ifdefined\at    \let\normalmathat   \at    \unexpanded\def\at   {\mathortext\normalmathat   \strc_references_at   } \else \let\at   \strc_references_at    \fi
    \ifdefined\about \let\normalmathabout\about \unexpanded\def\about{\mathortext\normalmathabout\strc_references_about} \else \let\about\strc_references_about \fi
    \ifdefined\from  \let\normalmathfrom \from  \unexpanded\def\from {\mathortext\normalmathfrom \strc_references_from } \else \let\from \strc_references_from  \fi
    \ifdefined\over  \let\normalmathover \over  \unexpanded\def\over {\mathortext\normalmathover \strc_references_about} \else \let\over \strc_references_about \fi
\to \everydump

           \def\filterreference  #key{\clf_filterreference{#key}} % no checking, expanded
\unexpanded\def\getreferenceentry#key{\clf_filterreference{#key}} % no checking, unexpanded

\def\currentreferencenumber  {\clf_filterreference{number}}
\def\currentreferencepage    {\clf_filterreference{page}}
\def\currentreferencetitle   {\clf_filterreference{title}}
\def\currentreferencetext    {\clf_filterreference{text}}
\def\currentreferencedefault {\clf_filterreference{default}}
\def\currentreferencerealpage{\clf_filterreference{realpage}}

%D The most straightforward way of retrieving references is using \type {\ref}.

\unexpanded\def\getreference % checking, unexpanded
  {\dodoubleargument\strc_references_get_reference}

\def\strc_references_get_reference[#key][#label]% #key = number page title text default realpage ...
  {\ifsecondargument
     \doifelsereferencefound{#label}{\clf_filterreference{#key}}\dummyreference
   \else
     \dummyreference
   \fi}

\let\ref\getreference

%D Special cases:

\unexpanded\def\strc_references_about[#label]%
  {\dontleavehmode
   \begingroup
   \let\crlf\space
   \let\\\space
   \postponenotes % might go
   \referencingparameter\c!left
   \doifelsereferencefound{#label}
     {\goto{\limitatetext\currentreferencetitle{\referencingparameter\c!width}\unknown}[#label]}% not so efficient (dup lookup)
     {}% todo
   \flushnotes % might go
   \referencingparameter\c!right
   \endgroup}

%D The previously discussed setup macro lets us specify the representation of
%D references. A symbol reference does not show the specific data, like the number
%D of a figure, but shows one of: \hbox {$^\goforwardcharacter$
%D $^\gobackwardcharacter$ $^\gonowherecharacter$}, depending on the direction to
%D go.
%D
%D \starttyping
%D ... \somewhere{backward text}{forward text}[someref] ...
%D ... \atpage[someref] ...
%D \stoptyping

% standard      detail
%
% 0 = unknown   unknown
% 1 = same      on same page
% 2 = before    preceding page
% 3 = after     following page
%
% 4 = above     above on same page
% 5 = below     below on same page

% todo: optimize for use in pagebody
% todo: maybe make it optional

% \setuppagenumbering[alternative=doublesided]
% \setupreferencing  [doublesided=no] % yes is default
%
% \somewhere{backward}{foreward}[label]
% \someplace{preceding}{backward}{current}{foreward}{following}[label]
% \atpage[#label]
% \doifcheckedpagestate{label}{preceding}{backward}{current}{foreward}{following}{otherwise}
%
% \dorecurse {20} {
%     \placefigure[here][fig:#1]{}{\externalfigure[dummy]}
%     \dorecurse {20} {
%         ##1: \atpage[fig:##1] /
%         \doifcheckedpagestate
%             {fig:##1}
%             {preceding}{backward}{current}{foreward}{following}
%             {otherwise}
%     }
% }

\newcount      \nofreferencestates
\newconditional\pagestatespread

\appendtoks
    \doifelse{\referencingparameter\c!doublesided}\v!yes\settrue\setfalse\pagestatespread
\to \everysetupreferencing

\setupreferencing
  [\c!doublesided=\v!yes]

\def\referencepagestate
  {\numexpr\clf_referencepagestate
     {rst::\number\nofreferencestates}%
   \relax}

\def\referencepagedetail
   {\numexpr\clf_referencepagedetail
      {rst::\number\nofreferencestates}%
      true %
      \ifconditional\pagestatespread false\ifdoublesided true\else false\fi\fi
    \relax}

\def\referencerealpage
  {\clf_referencerealpage}

\def\referencecolumnnumber
  {\clf_referencecolumn}

% So we need : instead of \ but that's only lmtx:
%
% \def\referencecolumnnumber
%   {\numexpr\dimexpr\clf_referenceposx-\cutspace\relax:\dimexpr\makeupwidth/\nofcolumns\relax+\plusone\relax}
%
% Tacos patch of the older one, kept here as illustration
%
% \def\referencecolumnnumber
%   {\numexpr
%       \dimexpr\clf_referenceposx-\cutspace-\makeupwidth/(2*\nofcolumns)\relax
%      /\dimexpr                             \makeupwidth/   \nofcolumns \relax
%      +\plusone
%    \relax}


\unexpanded\def\tracedpagestate
  {{\blue\tttf(\ifcase\referencepagedetail unknown\or same\or previous\or next\or above\or below\else unknown\fi)}}

\unexpanded\def\markreferencepage
  {\dontleavehmode\begingroup
   \iftrialtypesetting
     % issue warning that not stable
   \else
     % needs checking ... but probably never in trialmode
     \global\advance\nofreferencestates\plusone
     \xypos{rst::\number\nofreferencestates}%
     % \tracedpagestate
   \fi
   \endgroup}

\unexpanded\def\doifcheckedpagestate#label% #preceding#backward#current#foreward#following#otherwise%
  {\doifelsereferencefound{#label}\strc_references_handle_page_state_yes\strc_references_handle_page_state_nop}

\let\strc_references_handle_page_state_nop\sixthofsixarguments

\def\strc_references_handle_page_state_yes
  {\markreferencepage
   \ifcase\referencepagedetail
     \expandafter\sixthofsixarguments \or
     \expandafter\thirdofsixarguments \or
     \expandafter\firstofsixarguments \or
     \expandafter\fifthofsixarguments \or
     \expandafter\secondofsixarguments\or
     \expandafter\fourthofsixarguments\else
     \expandafter\sixthofsixarguments \fi}

\unexpanded\def\referencesymbol
  {\hpack\bgroup
     \strut
     \markreferencepage
     \high
       {\setupsymbolset[\interactionparameter\c!symbolset]%
        \symbol[\ifcase\referencepagedetail\v!somewhere\or\v!nowhere\or\v!previous\or\v!next\or\v!previous\or\v!next\else\v!somewhere\fi]}%
   \egroup}

%D Hereafter the \type {\ignorespaces} binds the state node to next character (more likely
%D than a preceding one) and one can always add an explicit space.

\unexpanded\def\somewhere#backward#foreward#dummy[#label]% #dummy gobbles space around #foreward
  {\doifcheckedpagestate{#label}%
     {\goto{#backward}[#label]}%
     {\goto{#backward}[#label]}%
     {\ignorespaces}%
     {\goto{#foreward}[#label]}%
     {\goto{#foreward}[#label]}%
     {#label}}%

\unexpanded\def\someplace#preceding#backward#current#foreward#following#dummy[#label]% #dummy gobbles space around #foreward
  {\doifcheckedpagestate{#label}%
     {\doifelsenothing{#preceding}{\goto{#preceding}[#label]}\ignorespaces}%
     {\doifelsenothing {#backward}{\goto {#backward}[#label]}\ignorespaces}%
     {\doifelsenothing  {#current}{\goto  {#current}[#label]}\ignorespaces}%
     {\doifelsenothing {#foreward}{\goto {#foreward}[#label]}\ignorespaces}%
     {\doifelsenothing{#following}{\goto{#following}[#label]}\ignorespaces}%
     {#label}}

\unexpanded\def\atpage[#label]% todo
  {\doifcheckedpagestate{#label}%
     {\goto{\labeltext \v!precedingpage      }[#label]}%
     {\goto{\labeltext \v!hencefore          }[#label]}%
     {\ignorespaces}%
     {\goto{\labeltext \v!hereafter          }[#label]}%
     {\goto{\labeltext \v!followingpage      }[#label]}%
     {\goto{\labeltexts\v!page\dummyreference}[#label]}}

% Someone requested this but in retrospect didn't need it so we keep it as example.
% Beware: a node is injected which is why we add ignorespaces!
%
% \unexpanded\def\strc_references_conditional#action#text[#condition]#dummy[#label]%
%   {\doifcheckedpagestate{#label}%
%      {\doifelse{#condition}\v!precedingpage{#action{#text}[#label]}\ignorespaces}%
%      {\doifelse{#condition}\v!hencefore    {#action{#text}[#label]}\ignorespaces}%
%      {\doifelse{#condition}\v!current      {#action{#text}[#label]}\ignorespaces}%
%      {\doifelse{#condition}\v!hereafter    {#action{#text}[#label]}\ignorespaces}%
%      {\doifelse{#condition}\v!followingpage{#action{#text}[#label]}\ignorespaces}%
%      {#label}}
%
% \unexpanded\def\conditionalat   {\strc_references_conditional\at}
% \unexpanded\def\conditionalin   {\strc_references_conditional\in}
% \unexpanded\def\conditionalabout{\strc_references_conditional\about}

%D The other alternatives just conform their names: only the label, only the text, or the
%D label and the text.

% \dounknownreference -> \dummyreference

\def\symbolreference[#label]% for old times sake
  {\goto{\referencesymbol}[#label]}

% \referencecontentmode 0=all 1=label 2=text 3=symbol

\newtoks\leftreferencetoks
\newtoks\rightreferencetoks
\newtoks\defaultleftreferencetoks
\newtoks\defaultrightreferencetoks

%def\leftofreferencecontent {\nobreakspace} % we cannot do \definereferenceformat[at] .. so we need this
\let\rightofreferencecontent \empty
\let\leftofreference         \empty
\let\rightofreference        \empty

\unexpanded\def\leftofreferencecontent
  {\removeunwantedspaces
   \nonbreakablespace
   \ignorespaces}

\installcorenamespace{referencinginteraction}

\def\strc_references_interaction_all
  {\the\leftreferencetoks
   \doifelsesometoks\leftreferencetoks \leftofreferencecontent \donothing
   \leftofreference
   \doifelsesometoks\leftreferencetoks\onlynonbreakablespace\relax % new, replace space by nonbreakable if present
   \currentreferencecontent
   \rightofreference
   \doifelsesometoks\rightreferencetoks\rightofreferencecontent\donothing
   \the\rightreferencetoks}

\letvalue{\??referencinginteraction\v!all}\strc_references_interaction_all

\setvalue{\??referencinginteraction\v!label}%
  {\leftofreference
   \the\leftreferencetoks
   \the\rightreferencetoks
   \rightofreference}

\setvalue{\??referencinginteraction\v!text}%
  {\leftofreference
   \currentreferencecontent
   \rightofreference}

\setvalue{\??referencinginteraction\v!symbol}%
  {\referencesymbol}

\def\referencesequence
  {\ifcsname\??referencinginteraction\referencingparameter\c!interaction\endcsname
     \expandafter\lastnamedcs
   \else
     \expandafter\strc_references_interaction_all
   \fi}

\newtoks\everyresetinatreference

\appendtoks
    \glet\leftofreference \relax
    \glet\rightofreference\relax
\to \everyresetinatreference

\def\strc_references_start_goto
  {\dontleavehmode
   \begingroup}

\def\strc_references_stop_goto
  {\the\everyresetinatreference
   \endgroup}

\def\strc_references_pickup_goto
  {\dodoublegroupempty\strc_references_pickup_goto_indeed}

\def\strc_references_pickup_goto_indeed#left#right#dummy[#label]% #dummy gobbles spaces (really needed)
  {\leftreferencetoks
     \iffirstargument
       {#left}%
     \else
       \defaultleftreferencetoks
       \let\leftofreferencecontent\empty
     \fi
   \rightreferencetoks
     \ifsecondargument
       {#right}%
     \else
       \defaultrightreferencetoks
       \let\rightofreferencecontent\empty
     \fi
   % inefficient: double resolve
   \doifelsereferencefound{#label} % we need to resolve the text
     {\goto{\referencesequence}[#label]}
     {\let\currentreferencecontent\dummyreference
      \goto{\referencesequence}[#label]}%
   \strc_references_stop_goto}

\unexpanded\def\strc_references_in
  {\strc_references_start_goto
   \let\currentreferencecontent\currentreferencedefault
   \strc_references_pickup_goto}

\unexpanded\def\strc_references_at
  {\strc_references_start_goto
   \let\currentreferencecontent\currentreferencepage
   \strc_references_pickup_goto}

%D \macros
%D   {definereferenceformat}
%D
%D The next few macros were made for for David Arnold and Taco Hoekwater. They can
%D be used for predefining reference texts, and thereby stimulate efficiency.
%D
%D \starttyping
%D \definereferenceformat[informula]  [left=(,right=),text=formula]
%D \definereferenceformat[informulas] [left=(,right=),text=formulas]
%D \definereferenceformat[andformula] [left=(,right=),text=and]
%D \definereferenceformat[andformulas][left=(,right=),text=and]
%D
%D \informula [b] and \informula [for:c]
%D the \informula {formulas}[b] \informula {and} [for:c]
%D the \informulas {formulas}[b] \informula {and} [for:c]
%D the \informulas [b] \informula {en} [for:c]
%D the \informulas [b] \andformula [for:c]
%D \stoptyping
%D
%D Instead of a text, one can specify a label, which should be defined with \type
%D {\setuplabeltext}.
%D
%D Watch out: the second argument is somewhat special and mostly meant for a suffix
%D to a number:
%D
%D \startbuffer
%D \definereferenceformat [intesta] [left=(,right=),text=Whatever~]
%D \definereferenceformat [intestb] [left=(,right=),label=figure]
%D
%D \placeformula[x]\startformula a \stopformula
%D
%D \starttabulate[|||||]
%D \NC \in     [x] \NC \in     {left}[x] \NC \in     {}{right}[x] \NC \in     {left}{right}[x] \NC \NR
%D \NC \intesta[x] \NC \intesta{left}[x] \NC \intesta{}{right}[x] \NC \intesta{left}{right}[x] \NC \NR
%D \NC \intestb[x] \NC \intestb{left}[x] \NC \intestb{}{right}[x] \NC \intestb{left}{right}[x] \NC \NR
%D \stoptabulate
%D \stopbuffer
%D
%D \typebuffer \getbuffer

% to be done: interfaced

\installcorenamespace{referenceformat}

\installcommandhandler \??referenceformat {referenceformat} \??referenceformat

\appendtoks
    \setuevalue\currentreferenceformat{\strc_references_apply_format{\currentreferenceformat}}%
\to \everydefinereferenceformat

\setupreferenceformat
  [\c!left=,
   \c!right=,
   \c!text=,
   \c!label=,
   \c!autocase=\v!no,
   \c!style=,
   \c!type=default, % to be done: interfaced
   \c!setups=,
   \c!color=]

\unexpanded\def\strc_references_apply_format#name%
  {\strc_references_start_goto
   \edef\currentreferenceformat{#name}%
   \gdef\leftofreference               {\referenceformatparameter\c!left    }%
   \gdef\rightofreference              {\referenceformatparameter\c!right   }%
   \edef\currentreferenceformatlabel   {\referenceformatparameter\c!label   }%
   \edef\currentreferenceformattype    {\referenceformatparameter\c!type    }%
   \edef\currentreferenceformatsetups  {\referenceformatparameter\c!setups  }%
   \edef\currentreferenceformatautocase{\referenceformatparameter\c!autocase}%
   \usereferenceformatstyleandcolor\c!style\c!color
   \ifx\currentstyleparameter\empty \else
     \resetinteractionparameter\c!style
   \fi
   \ifx\currentcolorparameter\empty \else
     \resetinteractionparameter\c!contrastcolor
     \resetinteractionparameter\c!color
   \fi
   \ifx\currentreferenceformatlabel\autoreferencelabeltextflag
      \edef\currentreferenceformatlabel{\autoreferencelabeltext}%
   \fi
   \ifx\currentreferenceformatautocase\v!yes
     \setcharactercleaning[1]%
   \fi
   \ifx\currentreferenceformatlabel\empty
     \defaultleftreferencetoks {\referenceformatparameter\c!text}%
     \defaultrightreferencetoks\emptytoks
   \else
     \defaultleftreferencetoks {\leftlabeltext \currentreferenceformatlabel}%
     \defaultrightreferencetoks{\rightlabeltext\currentreferenceformatlabel}%
   \fi
   \ifx\currentreferenceformattype\empty
     \def\currentreferenceformattype{default}%
   \fi
   %
   \ifx\currentreferenceformatsetups\empty
     \def\currentreferencecontent{\filterreference\currentreferenceformattype}%
   \else
     \def\currentreferencecontent{\directsetup\currentreferenceformatsetups}%
   \fi
   %
   \let\leftofreferencecontent \empty
   \let\rightofreferencecontent\empty
   \strc_references_pickup_goto}

\def\autoreferencelabeltextflag{*} % a proper key like 'auto' or 'name' can clash with a label key

\unexpanded\def\autoreferencelabeltext
  {\clf_getcurrentreferencemetadata{name}}

% \starttext
%     \definereferenceformat[inxx]  [left=(,right=),text=txt]
%     \setupinteraction[state=start]
%     \chapter[one]{xx}
%     [\goto{state}[file(mk-last-state)]]
%     [\goto{state} [file(mk-last-state)]]
%     [\at{page} [one]]
%     [\at{page}[one]]
%     [\at{page}{okay}[one]]
%     [\inxx{a}{b}[one]]
% \stoptext

% \startsetups referenceformat:numberplustext
%     \filterreference{number}, \filterreference{title}
% \stopsetups
%
% \definereferenceformat[hellup][text=Hellup ,setups=referenceformat:numberplustext]

%D In interactive documents going to a specific location is not bound to cross
%D references. The \type {\goto} commands can be used to let users access another
%D part of the document. In this respect, interactive tables of contents and
%D registers can be considered goto's. Because in fact a \type {\goto} is just a
%D reference without reference specific data, the previous macros are implemented
%D using the goto functionality.
%D
%D \showsetup{goto}
%D
%D One important characteristic is that the first argument of \type {\goto} (and
%D therefore \type {\at} and \type {\in} is split at spaces. This means that,
%D although hyphenation is prevented, long references can cross line endings.

% \starttext
%     \setupinteraction[state=start]
%     [\goto{state}[file(mk-last-state)]]
%     [\goto{state} [file(mk-last-state)]]
% \stoptext

\newconditional\uselocationstrut \settrue\uselocationstrut

\def\extrareferencearguments
  {highlight \luaconditional\highlighthyperlinks\space
   newwindow \luaconditional\gotonewwindow\space
   layer     {\currentviewerlayer}}

\unexpanded\def\directgoto
  {\ifconditional\uselocationstrut
     \expandafter\strc_references_direct_goto
   \else
     \expandafter\strc_references_direct_goto_htdp
   \fi}

\unexpanded\def\goto
  {\ifconditional\uselocationstrut
     \expandafter\strc_references_goto
   \else
     \expandafter\strc_references_goto_htdp
   \fi}

% The unbox trick is needed in order to permit \par inside a reference. Otherwise
% the reference attribute migrates to the outer boxes.

\newcount\lastsavedreferenceattribute

\newbox\referencebox

\def\revivesavedreferenceattribute % sometimes handy as no test etc needed
  {\attribute\referenceattribute\lastsavedreferenceattribute}

\def\strc_references_direct_goto#content[#label]% no test for valid references
  {\dontleavehmode
   \begingroup
   \attribute\referenceattribute\attributeunsetvalue
   \global\lastsavedreferenceattribute\attributeunsetvalue
   \iflocation
     \clf_injectreference
        {\referenceprefix}%
        {#label}%
        {%
            height \ht\strutbox
            depth  \dp\strutbox
            \extrareferencearguments
        }%
     \relax
     \setlocationattributes
     \setstrut % can be option
     \global\lastsavedreferenceattribute\lastreferenceattribute
     \attribute\referenceattribute\lastreferenceattribute
     \dostarttagged\t!link\empty % not here
     #content%
     \dostoptagged
   \else
     #content%
   \fi
   \endgroup}

\def\strc_references_direct_goto_htdp#content[#label]% no test for valid references
  {\dontleavehmode
   \begingroup
   \global\lastsavedreferenceattribute\attributeunsetvalue
   \attribute\referenceattribute\attributeunsetvalue
   \iflocation
     \clf_injectreference
        {\referenceprefix}%
        {#label}%
        {%
            height \dimexpr\interactionparameter\c!height\relax
            depth  \dimexpr\interactionparameter\c!depth \relax
            \extrareferencearguments
        }%
     \relax
     \setlocationattributes
     \attribute\referenceattribute\lastreferenceattribute
     \global\lastsavedreferenceattribute\lastreferenceattribute
     \dostarttagged\t!link\empty
     #content%
     \dostoptagged
   \else
     #content%
   \fi
   \endgroup}

\def\strc_references_goto#content#dummy[#label]% #dummy gobbles spaces
  {\dontleavehmode
   \begingroup
  %\setbox\referencebox\hbox\bgroup % experiment, might change again to non \par support
   \global\lastsavedreferenceattribute\attributeunsetvalue
   \attribute\referenceattribute\attributeunsetvalue
   \iflocation
     \clf_doifelsereference{\referenceprefix}{#label}{\extrareferencearguments}%
       {\expandtexincurrentreference
        \clf_injectcurrentreferencehtdp
          \ht\strutbox
          \dp\strutbox
        \relax
        \setlocationattributes
        \setstrut % can be option
        \global\lastsavedreferenceattribute\lastreferenceattribute
        \attribute\referenceattribute\lastreferenceattribute
        \dostarttagged\t!link\empty
        #content%
        \dostoptagged}%
       {#content}%
   \else
     #content%
   \fi
  %\egroup\unhbox\referencebox}
   \endgroup}

\def\strc_references_goto_internal#content#dummy[#internal]% #dummy gobbles spaces
  {\dontleavehmode
   \begingroup
   \global\lastsavedreferenceattribute\attributeunsetvalue
   \attribute\referenceattribute\attributeunsetvalue
   \iflocation
     \setstrut % can be option
     \strc_references_get_simple_reference{#internal}%
     \global\lastsavedreferenceattribute\currentreferenceattribute
     \attribute\referenceattribute\currentreferenceattribute
     \setlocationattributes
     \dostarttagged\t!link\empty
     #content%
     \dostoptagged
   \else
     #content%
   \fi
   \endgroup}

\unexpanded\def\startgoto[#label]%
  {\dontleavehmode
   \begingroup
   \iflocation
     \clf_doifelsereference{\referenceprefix}{#label}{\extrareferencearguments}%
       {\expandafter\strc_references_start_goto_yes}%
       {\expandafter\strc_references_start_goto_nop}%
   \else
     \expandafter\strc_references_start_goto_nop
   \fi}

\unexpanded\def\strc_references_start_goto_nop
  {\let\stopgoto\strc_references_stop_goto_nop}

\unexpanded\def\strc_references_stop_goto_nop
  {\endgroup}

\unexpanded\def\strc_references_start_goto_yes
  {\expandtexincurrentreference
   \clf_injectcurrentreferencehtdp
     \ht\strutbox
     \dp\strutbox
   \relax
   \setlocationattributes
   \setstrut % can be option
   \global\lastsavedreferenceattribute\lastreferenceattribute
   \attribute\referenceattribute\lastreferenceattribute
   \dostarttagged\t!link\empty
   \let\stopgoto\strc_references_stop_goto_yes}

\unexpanded\def\strc_references_stop_goto_yes
  {\dostoptagged
   \endgroup}

\def\strc_references_goto_htdp#content#dummy[#label]% dummy gobbles spaces
  {\dontleavehmode
   \begingroup
   \global\lastsavedreferenceattribute\attributeunsetvalue
   \attribute\referenceattribute\attributeunsetvalue
   \iflocation
     \clf_doifelsereference{\referenceprefix}{#label}{\extrareferencearguments}%
       {\expandtexincurrentreference
        \clf_injectcurrentreferencehtdp
          \dimexpr\interactionparameter\c!height\relax
          \dimexpr\interactionparameter\c!depth \relax
        \relax
        \setlocationattributes
        \global\lastsavedreferenceattribute\lastreferenceattribute
        \attribute\referenceattribute\lastreferenceattribute
        \dostarttagged\t!link\empty
        #content%
        \dostoptagged}%
       {#content}%
   \else
     #content%
   \fi
   \endgroup}

\unexpanded\def\directgotobox#content[#label]% no test for valid references
  {\dontleavehmode
   \begingroup
   \global\lastsavedreferenceattribute\attributeunsetvalue
   \attribute\referenceattribute\attributeunsetvalue
   \iflocation
     \clf_injectreference
       {\referenceprefix}%
       {#label}%
       {\extrareferencearguments}%
     \relax
     \setlocationattributes
     \global\lastsavedreferenceattribute\lastreferenceattribute
     \dostarttagged\t!link\empty
     \hbox attr \referenceattribute \lastreferenceattribute {#content}%
     \dostoptagged
   \else
     #content%
   \fi
   \endgroup}

\unexpanded\def\directgotospecbox#resolver#content[#label]% no test for valid references
  {\dontleavehmode
   \begingroup
   \global\lastsavedreferenceattribute\attributeunsetvalue
   \attribute\referenceattribute\attributeunsetvalue
   \iflocation
     \clf_injectreference
       {\referenceprefix}%
       {#label}%
       {\extrareferencearguments}%
     \relax
     \setlocationcolorspec{#resolver}% no consequence for strut
     \global\lastsavedreferenceattribute\lastreferenceattribute
     \dostarttagged\t!link\empty
     \hbox attr \referenceattribute \lastreferenceattribute {#content}%
     \dostoptagged
   \else
     #content%
   \fi
   \endgroup}

\unexpanded\def\directgotodumbbox#content[#label]% no test for valid references
  {\dontleavehmode
   \begingroup
   \global\lastsavedreferenceattribute\attributeunsetvalue
   \attribute\referenceattribute\attributeunsetvalue
   \iflocation
     \clf_injectreference
       {\referenceprefix}%
       {#label}%
       {\extrareferencearguments}%
     \relax
     \global\lastsavedreferenceattribute\lastreferenceattribute
     \dostarttagged\t!link\empty
     \hbox attr \referenceattribute \lastreferenceattribute {#content}%
     \dostoptagged
   \else
     #content%
   \fi
   \endgroup}

\unexpanded\def\gotobox#content[#label]%
  {\dontleavehmode
   \begingroup
   \global\lastsavedreferenceattribute\attributeunsetvalue
   \attribute\referenceattribute\attributeunsetvalue
   \iflocation
     \clf_doifelsereference{\referenceprefix}{#label}{\extrareferencearguments}%
       {\expandtexincurrentreference
        \clf_injectcurrentreference
        \setlocationattributes
        \global\lastsavedreferenceattribute\lastreferenceattribute
        \dostarttagged\t!link\empty
        \hbox attr \referenceattribute \lastreferenceattribute {#content}%
        \dostoptagged}%
       {#content}%
   \else
     #content%
   \fi
   \endgroup}

\unexpanded\def\gotowdhtbox#width#height[#label]% fast variant for overlays
  {\dontleavehmode
   \begingroup
   \setbox\scratchbox\emptyhbox
   \wd\scratchbox#width%
   \ht\scratchbox#height%
   \global\lastsavedreferenceattribute\attributeunsetvalue
   \attribute\referenceattribute\attributeunsetvalue
   \clf_doifelsereference{\referenceprefix}{#label}{\extrareferencearguments}%
     {\clf_injectcurrentreference
      \global\lastsavedreferenceattribute\lastreferenceattribute
      \hpack attr \referenceattribute \lastreferenceattribute {\box\scratchbox}}
     {\box\scratchbox}%
   \endgroup}

%D An reference to another document can be specified as a file or as an \URL. Both
%D are handled by the same mechanism and can be issued by saying something like:
%D
%D \starttyping
%D \goto[dictionary::the letter a]
%D \stoptyping
%D
%D One can imagine that many references to such a dictionary are made, so in most
%D cases such a document reference in an indirect one.
%D
%D \showsetup{useexternaldocument}
%D
%D For example:
%D
%D \starttyping
%D \useexternaldocument
%D   [dictionary][engldict]
%D   [The Famous English Dictionary]
%D \stoptyping
%D
%D The next macro implements these relations, and also take care of loading the
%D document specific references.
%D
%D The \URL\ alternative takes four arguments:
%D
%D \showsetup{useURL}
%D
%D like:
%D
%D \starttyping
%D \useURL
%D   [dictionary][http://www.publisher.com/public][engldict]
%D   [The Famous English Dictionary]
%D \stoptyping
%D
%D Several specifications are possible:
%D
%D \starttyping
%D \useURL [id] [url] [file] [description]
%D \useURL [id] [url] [file]
%D \useURL [id] [url]
%D \stoptyping
%D
%D This time we don't load the references when no file is specified. This is logical
%D when one keeps in mind that a valid \URL\ can also be a mail address.

\unexpanded\def\useurl {\doquadrupleempty\strc_references_use_url }  % so that they can be used in expanded arguments
\unexpanded\def\usefile{\dotripleargument\strc_references_use_file}  % so that they can be used in expanded arguments

\let\useURL             \useurl
\let\useexternaldocument\usefile

\def\strc_references_use_url[#label][#url][#file][#description]%
  {\clf_useurl{#label}{\detokenize{#url}}{\detokenize{#file}}{\detokenize{#description}}}

\def\strc_references_use_file[#label][#file][#description]%
  {\clf_usefile{#label}{\detokenize{#file}}{\detokenize{#description}}}

\def\doifelseurldefined #label{\clf_doifelseurldefined {#label}}
\def\doifelsefiledefined#label{\clf_doifelsefiledefined{#label}}

\let\doifurldefinedelse \doifelseurldefined
\let\doiffiledefinedelse\doifelsefiledefined

%D \macros
%D   {url,setupurl}
%D
%D We also have: \type {\url} for directly calling the description. So we can say:
%D
%D \starttyping
%D \useURL [one] [http://www.test.nl]
%D \useURL [two] [http://www.test.nl] [] [Some Site]
%D
%D \url[one] or \from[two] or \goto{Whatever Site}[URL(two)]
%D \stoptyping
%D
%D An \URL\ can be set up with
%D
%D \showsetup{setupurl}

\installcorenamespace{url}

\installdirectcommandhandler \??url {url}

\setupurl
  [\c!style=\v!type,
   \c!color=]

\unexpanded\def\url[#label]% move \hyphenatedurl to lua end (is already lua)
  {\dontleavehmode
   \begingroup
   \useurlstyleandcolor\c!style\c!color
   \hyphenatedurl{\clf_geturl{#label}}%
   \endgroup}

%D This macro is hooked into a support macro, and thereby \URL's break ok, according
%D to the setting of a switch,
%D
%D \startbuffer
%D \useURL
%D   [test]
%D   [sentence_sentence~sentence//sentence:sentence.sentence]
%D \stopbuffer
%D
%D \typebuffer
%D
%D Such an \URL\ is, depending on the settings, hyphenated as:
%D
%D \getbuffer

%D When defining the external source of information, one can also specify a suitable
%D name (the last argument). This name can be called upon with:
%D
%D \showsetup{from}
%D
%D We keep this for compatibility reasons, hence the hackery.

\unexpanded\def\strc_references_from
  {\dosingleempty\strc_references_do_special_from}

\def\strc_references_do_special_from[#label]%
  {\dontleavehmode
   \goto{\clf_from{#label}}[fileorurl(#label)]}

\def\dofromurldescription#content% called at the lua end
  {#content}

\def\dofromurlliteral#content% called at the lua end
  {\useurlstyleandcolor\c!style\c!color
   \hyphenatedurl{#content}}

\let\dofromfiledescription\dofromurldescription
\let\dofromfileliteral    \dofromurlliteral     % maybe some day setupfile that inherits from url

%D We also support:
%D
%D \starttyping
%D \goto{some text}[file(identifier{location}]
%D \stoptyping
%D
%D which is completely equivalent with
%D
%D \starttyping
%D \goto{some text}[identifier::location]
%D \stoptyping

%D A special case of references are those to programs. These, very system dependant
%D references are implemented by abusing some of the previous macros.
%D
%D \showsetup{setupprograms}
%D \showsetup{defineprogram}
%D \showsetup{program} % changed functionality !
%D
%D The latter gives access to the description of the program,
%D being the last argument to the definition command.

% also lua, like urls and files

\installcorenamespace{programs}

\installdirectcommandhandler \??programs {programs}

\unexpanded\def\defineprogram
  {\dotripleargument\strc_references_define_program}

\def\strc_references_define_program[#name][#program][#description]%
  {\clf_defineprogram{#name}{#program}{#description}}

\unexpanded\def\program[#name]% incompatible, more consistent, hardy used anyway
  {\dontleavehmode
   \begingroup
   \useprogramsstyleandcolor\c!style\c!color
   \clf_getprogram{#name}%
   \endgroup}

%D As we can see, we directly use the special reference mechanism, which means that
%D
%D \starttyping
%D \goto{some text}[program(name{args})]
%D \stoptyping
%D
%D is valid.

%D The next macro provides access to the actual pagenumbers. When documenting and
%D sanitizing the original reference macros, I decided to keep the present meaning
%D as well as to make this meaning available as a special reference method. So now
%D one can use:
%D
%D \starttyping
%D \gotopage{some text}[location]
%D \gotopage{some text}[number]
%D \gotopage{some text}[file::number]
%D \stoptyping
%D
%D as well as:
%D
%D \starttyping
%D \goto{some text}[page(location)]
%D \goto{some text}[page(number)]
%D \goto{some text}[file::page(number)]
%D \stoptyping
%D
%D Here location is a keyword like \type{nextpage}.
%D
%D \showsetup{gotopage}

\unexpanded\def\definepage
  {\dodoubleargument\strc_references_define_page}

\def\strc_references_define_page[#name][#target]%
  {\definereference[#name][page(#target)]}

\def\gotopage#text[#target]%
  {\goto{#text}[\v!page(#target)]}

%D The previous definitions are somewhat obsolete so we don't use it here.

%D We can cross link documents by using:
%D
%D \showsetup{coupledocument}
%D
%D like:
%D
%D \starttyping
%D \coupledocument[print][somefile][chapter,section]
%D \stoptyping
%D
%D After which when applicable, we have available the references:
%D
%D \starttyping
%D \goto{print version}[print::chapter]
%D \stoptyping
%D
%D and alike. The title placement definition macros have a key \type {file}, which
%D is interpreted as the file to jump to, that is, when one clicks on the title.

\def\coupledocument
  {\doquadrupleempty\strc_references_couple_document}

\def\strc_references_couple_document[#name][#file][#sections][#description]%
  {\ifthirdargument
     % this will be done differently (when it's needed)
   \fi}

%D \macros
%D   {dotextprefix}
%D
%D In previous macros we used \type {\dotextprefix} to generate a space between
%D a label and a number.
%D
%D \starttyping
%D \dotextprefix{text}
%D \stoptyping
%D
%D Only when \type {text} is not empty, a space is inserted.

\unexpanded\def\dotextprefix#text%
  {\begingroup
   \setbox\scratchbox\hbox{#text}% to be solved some day
   \ifdim\wd\scratchbox>\zeropoint
     \unhbox\scratchbox
     \edef\p_separator{\referencingparameter\c!separator}%
     \ifx\p_separator\empty \else
        \removeunwantedspaces % remove is new
        \p_separator
     \fi
   \else
     \unhbox\scratchbox
   \fi
   \endgroup}

%D In the next settings we see some variables that were not used here and that
%D concern the way the pagenumbers refered to are typeset.

\setupreferencing
  [\c!state=\v!start,
   \c!autofile=\v!no,
   \v!part\c!number=\v!yes,
   \v!chapter\c!number=\v!no,
   \c!interaction=\v!all,
   \c!convertfile=\v!no,
  %\c!strut=\v!no, % some day an option
   \c!prefix=,
   \c!width=.75\makeupwidth,
   \c!left=\quotation\bgroup,
   \c!right=\egroup,
   \c!global=\v!no,
   \c!expansion=\v!no,
   \c!separator=\nonbreakablespace,
   \c!export=\v!no]

\setupprograms
  [\c!directory=,
   \c!style=\v!type,
   \c!color=]

\definereference [\v!CloseDocument    ] [action(close)]
\definereference [\v!ExitViewer       ] [action(exit)]
\definereference [\v!FirstPage        ] [action(first)]
\definereference [\v!LastPage         ] [action(last)]
\definereference [\v!NextJump         ] [action(forward)]
\definereference [\v!NextPage         ] [action(next)]
\definereference [\v!PauseMovie       ] [action(pausemovie)]
\definereference [\v!PauseSound       ] [action(pausesound)]
\definereference [\v!PauseRendering   ] [action(pauserendering)]
\definereference [\v!PreviousJump     ] [action(backward)]
\definereference [\v!PreviousPage     ] [action(previous)]
\definereference [\v!PrintDocument    ] [action(print)]
\definereference [\v!SaveForm         ] [action(exportform)]
\definereference [\v!LoadForm         ] [action(importform)]
\definereference [\v!ResetForm        ] [action(resetform)]
\definereference [\v!ResumeMovie      ] [action(resumemovie)]
\definereference [\v!ResumeSound      ] [action(resumesound)]
\definereference [\v!ResumeRendering  ] [action(resumerendering)]
\definereference [\v!SaveDocument     ] [action(save)]
\definereference [\v!SaveNamedDocument] [action(savenamed)]
\definereference [\v!OpenNamedDocument] [action(opennamed)]
\definereference [\v!SearchDocument   ] [action(search)]
\definereference [\v!SearchAgain      ] [action(searchagain)]
\definereference [\v!StartMovie       ] [action(startmovie)]
\definereference [\v!StartSound       ] [action(startsound)]
\definereference [\v!StartRendering   ] [action(startrendering)]
\definereference [\v!StopMovie        ] [action(stopmovie)]
\definereference [\v!StopSound        ] [action(stopsound)]
\definereference [\v!StopRendering    ] [action(stoprendering)]
\definereference [\v!SubmitForm       ] [action(submitform)]
\definereference [\v!ToggleViewer     ] [action(toggle)]
\definereference [\v!ViewerHelp       ] [action(help)]
\definereference [\v!HideField        ] [action(hide)]
\definereference [\v!ShowField        ] [action(show)]
\definereference [\v!GotoPage         ] [action(gotopage)]
\definereference [\v!Query            ] [action(query)]
\definereference [\v!QueryAgain       ] [action(queryagain)]
\definereference [\v!FitWidth         ] [action(fitwidth)]
\definereference [\v!FitHeight        ] [action(fitheight)]
\definereference [\v!ShowThumbs       ] [action(thumbnails)]
\definereference [\v!ShowBookmarks    ] [action(bookmarks)]

\definereference [\v!HideLayer        ] [action(hidelayer)]
\definereference [\v!VideLayer        ] [action(videlayer)]
\definereference [\v!ToggleLayer      ] [action(togglelayer)]

\definereference [\v!firstpage]       [page(firstpage)]
\definereference [\v!previouspage]    [page(previouspage)]
\definereference [\v!nextpage]        [page(nextpage)]
\definereference [\v!lastpage]        [page(lastpage)]
\definereference [\v!forward]         [page(forward)]
\definereference [\v!backward]        [page(backward)]
\definereference [\v!firstsubpage]    [page(firstsubpage)]
\definereference [\v!previoussubpage] [page(previoussubpage)]
\definereference [\v!nextsubpage]     [page(nextsubpage)]
\definereference [\v!lastsubpage]     [page(lastsubpage)]

% we can do this but only when later in resolve (else problems with \chapter[first]{...}
%
% \definereference [\v!first]           [page(firstpage)]
% \definereference [\v!previous]        [page(prevpage)]
% \definereference [\v!next]            [page(nextpage)]
% \definereference [\v!last]            [page(lastpage)]
% \definereference [\v!first\v!sub]     [page(firstsubpage)]
% \definereference [\v!previous\v!sub]  [page(prevsubpage)]
% \definereference [\v!next\v!sub]      [page(nextsubpage)]
% \definereference [\v!last\v!sub]      [page(lastsubpage)]

%D We cannot set up buttons (not yet, this one calls a menu macro):

%D New (and experimental):

% \starttext
%     \chapter{test}
%     \placefigure[here][xx:1]{}{\framed{one}} \placefigure[here][xx:2]{}{\framed{three}}
%     \placetable [here][xx:3]{}{\framed{two}} \placetable [here][xx:4]{}{\framed{four}}
%     \start
%         \in{fig}[xx:1] and \in{fig}[xx:2] \in{tab}[xx:3] and \in{tab}[xx:4]
%     \stop \blank \start
%         \setupreferencestructureprefix[default][prefix=no]
%         \in{fig}[xx:1] and \in{fig}[xx:2] \in{tab}[xx:3] and \in{tab}[xx:4]
%     \stop \blank \start
%         \setupreferencestructureprefix[float][default][prefix=no]
%         \in{fig}[xx:1] and \in{fig}[xx:2] \in{tab}[xx:3] and \in{tab}[xx:4]
%     \stop \blank \start
%         \setupreferencestructureprefix[figure][default][prefix=no]
%         \in{fig}[xx:1] and \in{fig}[xx:2] \in{tab}[xx:3] and \in{tab}[xx:4]
%     \stop \blank
% \stoptext

% todo: parameterhandler

\installcorenamespace{referencingprefix}

\def\getreferencestructureprefix#kind#name#category% name will change
  {{%
        prefix        {\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefix}%
        separatorset  {\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixseparatorset}%
        conversion    {\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixconversion}%
        conversionset {\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixconversionset}%
        starter       {\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixstarter}%
        stopper       {\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixstopper}%
        set           {\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixset}%
        segments      {\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixsegments}%
        connector     {\referencestructureprefixparameter{#kind}{#name}{#category}\c!prefixconnector}%
  }%
  {%
        separatorset  {\referencestructureprefixparameter{#kind}{#name}{#category}\c!numberseparatorset}%
        conversion    {\referencestructureprefixparameter{#kind}{#name}{#category}\c!numberconversion}%
        conversionset {\referencestructureprefixparameter{#kind}{#name}{#category}\c!numberconversionset}%
        starter       {\referencestructureprefixparameter{#kind}{#name}{#category}\c!numberstarter}%
        stopper       {\referencestructureprefixparameter{#kind}{#name}{#category}\c!numberstopper}%
        segments      {\referencestructureprefixparameter{#kind}{#name}{#category}\c!numbersegments}%
  }}

\unexpanded\def\setupreferencestructureprefix
  {\dotripleempty\strc_references_setup_reference_structure_prefix}

\def\strc_references_setup_reference_structure_prefix[#kind][#category][#settings]%
  {\ifthirdargument
     \getparameters[\??referencingprefix#kind:#category][#settings]%
   \else\ifsecondargument
     \getparameters[\??referencingprefix:#kind][#category]%
   \fi\fi}

\def\referencestructureprefixparameter#kind#name#category#parameter%
  {\ifcsname\??referencingprefix#name:#category#parameter\endcsname
     \lastnamedcs
   \else\ifcsname\??referencingprefix#kind:#category#parameter\endcsname
     \lastnamedcs
   \else\ifcsname\??referencingprefix:#category#parameter\endcsname
     \lastnamedcs
   \fi\fi\fi}

\def\currentreferencedefault % for some reason we need to explicitly expand
  {\normalexpanded{\noexpand\clf_filterdefaultreference
     {\s!default}%
     \noexpand\getreferencestructureprefix\clf_getcurrentprefixspec{\s!default}% returns #kind#name#category
   \relax}}

%D Not all support is visible by looking at the \TEX\ code; here is one of those:^
%D
%D \starttyping
%D \startinteractionmenu[right]
%D   \startbut [section(first   {chapter})]    first chapter \stopbut
%D   \startbut [section(previous{chapter})] previous chapter \stopbut
%D   \startbut [section(next    {chapter})]     next chapter \stopbut
%D   \startbut [section(last    {chapter})]     last chapter \stopbut
%D   \blank[2*big]
%D   \startbut [section(first   {section})]    first section \stopbut
%D   \startbut [section(previous{section})] previous section \stopbut
%D   \startbut [section(next    {section})]     next section \stopbut
%D   \startbut [section(last    {section})]     last section \stopbut
%D \stopinteractionmenu
%D \stoptyping

%D Relatively new:
%D
%D \starttyping
%D \chapter{The never ending story}
%D
%D \section{An ending story}
%D
%D \in{chapter}[match(complex bibliographies)]
%D \in{chapter}[match(never ending)]
%D \in{chapter}[match(ending)]
%D \in{chapter}[match(chapter:never ending)]
%D \in{chapter}[match(chapter:ending)]
%D \in{section}[match(section:ending)]
%D \in{figure}[match(float:mess)]
%D \in{figure}[match(figure:mess)]
%D \in{figure (not found)}[match(section:mess)]
%D \in{figure (not found)}[match(section:xxxx)]
%D \in{figure}[match(mess)]
%D
%D \placefigure{What a mess}{}
%D
%D \chapter{About complex bibliographies}
%D
%D \in{chapter}[match(complex bibliographies)]
%D \in{chapter}[match(never ending)]
%D \in{figure}[match(mess)]
%D \stoptyping

\protect \endinput

% tricky:
%
% \enabletrackers[nodes.references]
% \setupinteraction[state=start]
% \def\KnuthTest{\input knuth }
% \def\KnuthTest{\input tufte }
% \def\TufteTest{\input tufte }
% \defineoverlay[xxx][\overlaybutton{page(3)}]
% \setupbackgrounds[text][background=xxx]
% \starttext
% test {\red \KnuthTest} test \par
% \button{test}[page(1)] \par
% \goto{page 2 \TeX}[page(2)] \goto{page 2 \TeX}[page(2)] \goto{\TufteTest}[page(2)] test \page
% test \goto{page 3}[page(3)] \goto{\TufteTest\space\par\TufteTest}[page(4)] test \page
% \goto{page 1}[page(1)] \goto{\TufteTest\space test}[page(1)] \page
% \goto{page 1}[page(1)] \goto{\KnuthTest\space test}[page(1)] \page
% test \goto{page 1}[page(1)] {\goto{\KnuthTest\space test}[page(1)]} test
% \goto{page 1}[page(1)] \goto{\TufteTest}[page(1)] test \page
% \stoptext