%D \module
%D   [       file=strc-mar,
%D        version=2008.10.20,
%D          title=\CONTEXT\ Structure Macros,
%D       subtitle=Markings,
%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.

\writestatus{loading}{ConTeXt Structure Macros / Markings}

\registerctxluafile{strc-mar}{1.001}

\unprotect

%D Synchronizing marks is a rather tricky and messy business. When
%D setting a mark, a node is added to the list in order for to \TEX\
%D be able to figure out the 3 current marks when a page is made
%D (last mark on previous page, first on current page, last on
%D current page; in \LUATEX\ we might at one point have the first on
%D the next page as well).
%D
%D Resetting a mark is not easy. An empty one will not erase the last
%D one on the previous page for instance. In \LUATEX\ we can clear a
%D marks state register with \type {\clearmarks} but since this is an
%D immediate operation it might have unwanted side effects when \TEX\
%D has collected several pages of text and finishing off these pages
%D uses marks.
%D
%D In \MKIV\ we provide an alternative model that permits some more
%D control over the way marks are used. It is not entirely compatible
%D with \MKII\ or previous \MKIV\ implementations but in practice this
%D is not a real problem. It's also easier now to extend this mechanism.

% if global has side effects we will need to nil it selectively
% and optionally enable it in for instance postponed content

\definesystemattribute [marks] [global]

\installcorenamespace{marking}

\installcommandhandler \??marking {marking} \??marking

\newconditional\inhibitgetmarking % will become private
\newconditional\inhibitsetmarking % will become private

\newtoks       \everymarking

\unexpanded\def\relatemarking     {\dodoubleempty   \strc_markings_relate     }
\unexpanded\def\setmarking        {\dosingleargument\strc_markings_set        } \let\marking\setmarking
\unexpanded\def\resetmarking      {\dosingleargument\strc_markings_reset      }
\unexpanded\def\synchronizemarking{\dotripleargument\strc_markings_synchronize}

\appendtoks
    \clf_definemarking{\currentmarking}{\currentmarkingparent}%
\to \everydefinemarking

\def\strc_markings_relate[#1][#2]%
  {\clf_relatemarking{#1}{#2}}

\def\strc_markings_set[#1]#2%
  {\ifconditional\inhibitsetmarking
     % nothing
   \else
     \doifelse{\namedmarkingparameter{#1}\c!expansion}\v!yes
       {\clf_setmarking{#1}{#2}}
       {\clf_setmarking{#1}{\detokenize{#2}}}%
   \fi}

\def\strc_markings_reset[#1]%
  {\clf_resetmarking{#1}}

\def\strc_markings_synchronize[#1][#2][#3]% #1=class #2=boxnumber (some day also name) #3=options, maybe second argument table
  {\ifvoid#2\else\clf_synchronizemarking{#1}#2{#3}\fi}

\def\doifelsemarking#1% no \noexpanded
  {\clf_doifelsemarking{#1}}

\let\doifmarkingelse \doifelsemarking

% \appendtoks
%     \strc_markings_synchronize[\v!page][\normalpagebox][\v!keep]% keep if no marks
% \to \everybeforepagebody

% defaults

\setupmarking
  [\c!expansion=\v!no,
   \c!separator=\space\emdash\space,
   \c!filtercommand=\firstofoneargument,
   \c!state=\v!start]

% fetching, regular interface

\unexpanded\def\getmarking
  {\ifconditional\inhibitgetmarking
     \expandafter\dotripleargument\expandafter\strc_markings_get_nop
   \else
     \expandafter\dotripleargument\expandafter\strc_markings_get_yes
   \fi}

\def\strc_markings_get_nop[#1][#2][#3]%
  {}

\def\strc_markings_get_yes[#1][#2][#3]%
  {\doif{\namedmarkingparameter{#1}\c!state}\v!start
     {\begingroup
      \setsystemmode\v!marking
      \the\everymarking
      \ifthirdargument
        \clf_getmarking{#1}{#2}{#3}%
      \else
        \clf_getmarking{#1}{\v!page}{#2}%
      \fi
      \endgroup}}

% the fetchers are fully expandable: [name][method]

\def\fetchonemark[#1]#2[#3]{\ifconditional\inhibitgetmarking\else\clf_fetchonemark {#1}{\v!page}{#2}\fi}
\def\fetchtwomarks     [#1]{\ifconditional\inhibitgetmarking\else\clf_fetchtwomarks{#1}{\v!page}\fi}
\def\fetchallmarks     [#1]{\ifconditional\inhibitgetmarking\else\clf_fetchallmarks{#1}{\v!page}\fi}

\let\fetchmark\fetchonemark

% also fully expandable but here we have: [name][range][method]

\def\fetchonemarking[#1]#2[#3]#4[#5]{\ifconditional\inhibitgetmarking\else\clf_fetchonemark {#1}{#3}{#5}\fi}
\def\fetchtwomarkings     [#1]#2[#3]{\ifconditional\inhibitgetmarking\else\clf_fetchtwomarks{#1}{#3}\fi}
\def\fetchallmarkings     [#1]#2[#3]{\ifconditional\inhibitgetmarking\else\clf_fetchallmarks{#1}{#3}\fi}

\let\fetchmarking\fetchonemarking

\def\markingseparator#1{\namedmarkingparameter{#1}\c!separator}
\def\markingcommand  #1{\namedmarkingparameter{#1}\c!filtercommand}

%D Experimental:
%D
%D \starttyping
%D \definemarking[boxmark]
%D
%D \setbox0\ruledvbox{
%D     \marking[boxmark]{tufte} \input tufte \par
%D     \marking[boxmark]{ward}  \input ward  \par
%D }
%D
%D \synchronizemarking[zerobox][0] \box0
%D
%D marks: (\getmarking[boxmark][zerobox][first],\getmarking[boxmark][zerobox][last])
%D \stoptyping

\protect \endinput
