%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Module:    ZzTeX Notes Facilities
%
% Synopsis:  This module defines various blocks that produce "notes", such
%            as footnotes.
%
% Author:    Paul C. Anagnostopoulos
% Created:   28 September 1989
%
% Copyright 1989--2020 by Paul C. Anagnostopoulos
% under The MIT License (opensource.org/licenses/MIT)
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

%                       Footnotes
%                       ---------


\defineblock{\footnote}{\endfootnote}{\true}{}

% The footnote parameters are used at two different times: when the 
% \footnote macro appears, and when the page is output.

% The \referencing parameter takes the following values:
%   0:  Produce neither a reference nor an intro number.
%   1:  Produce an intro number, but no reference.
%   2:  Produce both a reference and an intro number.

%~block footnote
% \aboveskip = glue                     % Space b/b above first footnote line.
% \setflag \abutting = flag             % True if note abutts previous one.
% \bodyfont = {...}                     % Font for footnote text.
% \def \comptextformat {...}            % Composite number text formatter.
% \internoteskip = glue                 % Extra space between footnotes.
% \leftindent = glue                    % Left indentation.
% \height = dimen                       % Maximum height on page.
% \interlinepenalty = penalty           % Penalty between footnote lines.
% \def \noteintroformat {...}           % Footnote intro formatter.
% \def \noterefformat {...}             % Footnote reference formatter.
% \parindent = dimen                    % Paragraph indent.
% \parrag = dimen                       % Paragraph raggedness.
% \parskip = glue                       % Paragraph skip.
% \referencing = integer                % How the footnote is referenced.
% \rightindent = glue                   % Right indentation.
% \rulecolor = {...}                    % Color of rule.
% \rulewidth = dimen                    % Width of rule.
% \ruleheight = dimen                   % Height of rule.
% \ruleshift = dimen                    % Horizontal shift of rule.
% \ruleskip = dimen                     % Space b/b below rule.
% \def \spilloverride {...}             % Override parameters on spillover.
% \textcolor = {...}                    % Color of text.
%~end

\defineskip{\internoteskip}{0pt}
\definecount{\referencing}{0}

\defineinsert{\zfninsert}


\def \footnote {%                                       {text}
  \blockcantbein{\footnote}{\footnote}%
  \beginblockscope{footnote}%
  \global\increment \footnotedepth
  \setflag \abutting = \false                           %~default with
  \referencing = 2                                      %~default with
  \interlinepenalty = \breakworse                       %~default hard
  \rulecolor = {black}%                                 %~default soft
  \ruleshift = 0pt                                      %~default soft
  \def \spilloverride {}%                               %~default soft
  \textcolor = {black}%                                 %~default soft
  \processdesign{\footnote}{}%
  \if \posp{\referencing}%
    \global\increment \footnotenumber
    \setcomptext{\footnotecomptext}%
  \else
    \footnotecomptext = {???}%
  \fi
  \settaginfo{\the\footnotecomptext}{???}%
  \if \andp{\hmodep}{\eqlp{\referencing}{2}}%
    {\edef \zsf {\spacefactor=\the\spacefactor}%
     \/%
     \if \DVIWindoinuse \colorspecial{ifview color push rgb 1 0 1}\fi
     \noterefformat
     \if \DVIWindoinuse \colorspecial{ifview color pop}\fi
     \zsf}%
  \fi
  \footnoteinsert}

\def \footnoteinsert {%
  \the\bodyfont
  \global\count\zfninsert = 1000
  \global\dimen\zfninsert = \height
  \global\skip\zfninsert = \aboveskip
  \global\advance \skip\zfninsert by -\internoteskip
  \global\advance \skip\zfninsert by -\ht\strutbox      % of footnote text.
  \insert \zfninsert \bgroup
    \zpushvcontext
    \color{\the\textcolor}%
    \setindentation{\leftindent}{\rightindent}%
    \setparrag{\parrag}%
    \parfillskip = \normalparfillskip
    \spaceskip = 0pt \xspaceskip = 0pt
    \splittopskip = \ht\strutbox
    \advance \splittopskip by \internoteskip
    \splitmaxdepth = \dp\strutbox
    \floatingpenalty = 20000\relax      % Reference on same page as note.
    \if \posp{\referencing}%
      \noteintroformat
    \else
      \indent
    \fi
    \vbox to \splittopskip{}%           % Strut in first line.
    \bgroup
      \aftergroup\endfootnote
      \let \znext}                      % Eat open brace of footnote text.
                                        % Absorb footnote text.
                                        % \bgroup matches close brace.

\def \endfootnote {%
    \if \hmodep \strut \fi              % Strut in last line.
    \endgraf
    \unskip
    \endcolor
    \zpopvcontext
  \egroup % \insert
  \global\decrement \footnotedepth
  \endblockscope{footnote}}

% This macro is invoked by the output routine to format footnotes.

\def \zfootnoteformat #1{%                              {body-depth}
  \beginblockscope{footnote}%
  \ruleshift = 0pt
  \def \spilloverride {}%
  % We used to do the \processdesign here, but that does a \processwith
  % that can end up processing some other block's pending \with. Oops.
  \footnotedesign \relax                % \processdesign{\footnote}{}
  \if \notp{\emptydefp{\spilloverride}}%
    \setbox \zboxa = \vtop{\unvcopy \zfninsert}%
    \if \dimzerop{\ht\zboxa}\spilloverride \fi
  \fi
  \vskip \skip\zfninsert
  \vskip -#1\relax
  \if \andp{\dimposp{\ruleheight}}{\dimposp{\rulewidth}}%
    \the\bodyfont
    \tdimena = \ruleskip
    \advance \tdimena by -\ht\strutbox
    \advance \tdimena by -\internoteskip
    \vskip -\tdimena
    \vskip -\ruleheight
    \nointerlineskip
    \noindent \hspace{\ruleshift}%
    \color{\the\rulecolor}\rule{height \ruleheight depth 0pt width \rulewidth}%
    \endcolor\par
    \vskip \tdimena
  \fi
  \unvbox \zfninsert
  \endblockscope{footnote}}

%                       Endnote
%                       -------


\defineblock{\endnote}{\endendnote}{\true}{}

% The endnote parameters are used at two different times: when the 
% \endnote command appears, and when the \endnotes command is used
% to typeset the notes.

%~block endnote
% \setflag \abutting = flag             % True if note abutts previous one.
% \def \comptextformat {...}            % Composite number text formatter.
% \endnoteclass = integer               % Class of endnote.
% \def \noterefformat {...}             % Footnote reference formatter.
% \referencing = integer                % How the endnote is referenced.
%~end

\definecount{\endnoteclass}{0}
\definetoks{\zendtoks}


\def \endnote {%                                        {text}
  \blockcantbein{\endnote}{\endnote}%
  \beginblockscope{endnote}%
  \global\increment \endnotedepth
  \setflag \abutting = \false                           %~default with
  \endnoteclass = 0                                     %~default with
  \referencing = 2                                      %~default with
  \processdesign{\endnote}{}%
  \global\increment \endnotenumber
  \setcomptext{\endnotecomptext}%
  \if \andp{\hmodep}{\eqlp{\referencing}{2}}%
    {\edef \zsf {\spacefactor = \the\spacefactor}%
     \/%
     \if \DVIWindoinuse \colorspecial{ifview color push rgb 1 0 1}\fi
     \noterefformat
     \if \DVIWindoinuse \colorspecial{ifview color pop}\fi
     \zsf}%
  \fi
  \afterassignment \endendnote
  \zendtoks =}

\def \endendnote {%
  \edef \zendtext {\the\zendtoks}%
  \edef \znext {\noexpand\xref{end}{\noexpand\folio}{\the\endnotecomptext}
                              {\expandafter\zdefof \meaning\zendtext\zmark}
                              {\the\divisionname,\the\endnoteclass}}%
  \znext
  \global\decrement \endnotedepth
  \endblockscope{endnote}}

%                       Endnotes
%                       --------


\defineblock{\endnotes}{\endendnotes}{\false}{}

%~block endnotes
% \setflag \abutting = flag             % True if note abutts previous one.
% \def \comptextformat {...}            % Composite number text formatter.
% \endnoteclass = integer               % Class of endnote.
% \def \noterefformat {...}             % Footnote reference formatter.
% \referencing = integer                % How the endnote is referenced.
%~end

\definecount{\endnotepage}{0}
\definetoks{\zenddivlist}
\definetoks{\zenddiv}
\definecount{\zendclass}{0}

\def \endnotes #1{%                             {division-list}
  \blockcantbein{\endnotes}{\endnotes}%
  \blockmustbein{\endnotes}{\list}%
  \beginblockscope{endnotes}%
  \global\increment \endnotesdepth
  \endnoteclass = 0                                     %~default with
  \processdesign{\endnote}{}%                           % Use endnote block's design.
  \global\increment \endnotesnumber
  \zenddivlist = {#1}%
  \zxloadcomp{\xrefloadendmode}%
  \endendnotes}

\def \endendnotes {%
  \endgraf
  \fakepar
  \setlist \zendadjlist = {}%
  \global\decrement \endnotesdepth
  \endblockscope{endnotes}}

% This macro is called for each endnote entry in the cross-reference file.

\long\def \xrefend #1#2#3#4{%
  \ifnum \xrefmode=\xrefloadendmode
    \xrefendb{#1}{#2}{#3}{#4}%
  \fi}

\long\def \xrefendb #1#2#3#4{%          {page}{number}{text}{division,class}
  \def \znext ##1,##2,##3\zmark{%
    \zenddiv={##1}\zendclass=##2}%
  \znext #4,0,\zmark \relax
  \if \eqlp{\zendclass}{\endnoteclass}%
    \edef \znext {\noexpand\inclusionlist\noexpand\zendtest
                                         {\the\zenddiv}{\the\zenddivlist}}%
    \znext
    \if \zendtest
      \setbox \zboxa = \hbox{\zendclass=0#1}%
      \endnotepage = \if \dimzerop{\wd\zboxa}#1\else 0 \fi
      \let \xrefmode = \xrefrunmode
      \zchkendadj{#2}%
      \item{#2}#3\par
      \let \xrefmode = \xrefloadendmode
    \fi
  \fi}

% This macro allows the compositor to noninvasively adjust pages between
% endnotes.

\setlist \zendadjlist = {}

\long\def \endnotesadjustment #1#2{%                    {division.number}{commands}
  \append{{#1}{#2}}{\zendadjlist}}

\long\def \zchkendadj #1{%                              {number}
  \maplist{\zchkendadjb{#1}##1}{\zendadjlist}}

\long\def \zchkendadjb #1#2#3{%                 {number}{division.number}{commands}
  \stringeql{\znext}{\the\zenddiv.#1}{#2}%
  \if \znext #3\relax \fi}

%                       Margin Notes
%                       ------ -----


\defineblock{\marginnote}{\endmarginnote}{\true}{}

%~block marginnote Type
% \def \beginformat {...}               % Beginning of text formatter.
% \bodyfont = {...}                     % Font for note text.
% \def \comptextformat {...}            % Composite number text formatter.
% \def \endformat {...}                 % End of text formatter.
% \leftindent = glue                    % Left indentation.
% \margingutter = dimen                 % Gutter for note in right margin.
% \def \noteintroformat {...}           % Note intro formatter.
% \def \noterefformat {...}             % Note reference formatter.
% \parindent = dimen                    % Paragraph indent.
% \parrag = dimen                       % Paragraph raggedness.
% \parskip = glue                       % Paragraph skip.
% \position = {...}                     % Position (see below).
% \referencing = integer                % How the margin note is referenced.
% \rightindent = glue                   % Right indentation.
% \textcolor = {...}                    % Color of text.
% \vshift = dimen                       % Vertical shift for note.
% \width = dimen                        % Width of text in box.
%~end

\definedimen{\margingutter}{0pt}
\definecount{\marginnotepage}{0}

\definecount{\zdivmncounter}{0}
\definedimen{\zmnshift}{0pt}
\definetoks{\zmntoks}
\definebox{\zmnbox}
\definedimen{\zmnprevdepth}{0pt}


\def \marginnote #1{%                                   {type}
  \blockcantbein{\marginnote}{\marginnote}%
  \beginblockscope{marginnote}%
  \global\increment \marginnotedepth
  \global\increment \zdivmncounter
  \whichpage{\marginnotepage}{zM:\the\divisionname-\the\zdivmncounter}%
  \def \beginformat {}%                                 %~default soft
  \def \endformat {}%                                   %~default soft
  \leftindent = 0pt                                     %~default soft
  \referencing = 0                                      %~default soft
  \rightindent = 0pt                                    %~default soft
  \textcolor = {black}%                                 %~default soft
  \vshift = 0pt                                         %~default soft
  \processdesign{\marginnote}{#1}%
  \zparsemnpos{\the\position}%
  \if \posp{\referencing}%
    \global\increment \marginnotenumber
    \setcomptext{\marginnotecomptext}%
  \else
    \marginnotecomptext = {???}%
  \fi
  \settaginfo{\the\marginnotecomptext}{???}%
  \if \andp{\hmodep}{\eqlp{\referencing}{2}}%
    {\edef \zsf {\spacefactor=\the\spacefactor}%
     \/%
     \if \DVIWindoinuse \colorspecial{ifview color push rgb 1 0 1}\fi
     \noterefformat
     \if \DVIWindoinuse \colorspecial{ifview color pop}\fi
     \zsf}%
  \fi
  \afterassignment \endmarginnote
  \zmntoks =}

\def \endmarginnote {%
  \setbox \zmnbox = \vtop{%
    \zpushvcontext
    \color{\the\textcolor}%
    \the\bodyfont
    \setindentation{\leftindent}{\rightindent}%
    \settextwidth{\width}
    \setparrag{\parrag}%
    \beginformat
    \if \posp{\referencing}\noteintroformat \fi
    \the\zmntoks
    \endgraf
    \endformat
    \endcolor
    \zpopvcontext}%
  \marginnoteformat
  \global\decrement \marginnotedepth
  \endblockscope{marginnote}}

\def \marginnoteformat {%
  \if \vmodep
    \zmnprevdepth = \prevdepth
    \nointerlineskip
  \else
    \vadjust
  \fi
  \bgroup
    \moveright \zmnshift \vtop to 0pt{%
      \vskip \vshift
      \box \zmnbox
      \vss
      \tagpageonly{\uniquetag{zM}{\the\zdivmncounter}}}%
  \egroup
  \if \vmodep \prevdepth = \zmnprevdepth \fi}

% This macro sets up variables that specify the position of a margin note
% according to the \position design parameter:
%
%   \ifevenpage         Use next position only on even page.
%   \ifoddpage          Use next position only on odd page.
%   \leftmargin         Shift note to left margin.
%   \outsidemargin      Shift note to outside margin.
%   \rightmargin        Shift note to right margin.

\definecount{\zmnhpos}{0}

\def \zparsemnpos #1{%                                 {options...}
  \global\zmnhpos = 0
  {\def \ifevenpage   ##1{\if \evenp{\marginnotepage}##1\fi}%
   \def \ifoddpage    ##1{\if \oddp{\marginnotepage}##1\fi}%
   \def \leftmargin   {\global\zmnhpos=1\relax}%
   \def \outsidemargin{\ifevenpage{\leftmargin}\ifoddpage{\rightmargin}}%
   \def \rightmargin  {\global\zmnhpos=2\relax}%
   #1\relax}%
  \ifcase \zmnhpos
    \error{nomnpos}
          {No horizontal position has been specified for a margin note}%
  \or
    \if \evenp{\marginnotepage}%
      \zmnshift = -\evenlefttextmargin
    \else
      \zmnshift = -\oddlefttextmargin
    \fi
  \or
    \calculate \zmnshift = {\textmeasure,+,\margingutter}%
  \fi}

% This macro is invoked at the beginning of each division.

\def \zmndivinit {%
  \global\zdivmncounter = 0\relax}

%                       Proof Notes
%                       ----- -----


\defineblock{\proofnote}{\endproofnote}{\true}{}

%~block proofnote
% \bodyfont = {...}                     % Font for note text.
% \evenshift = dimen                    % Horizontal shift for even pages.
% \oddshift = dimen                     % Horizontal shift for odd pages.
% \textcolor = {...}                    % Color of note.
% \vshift = dimen                       % Vertical shift for note.
% \width = dimen                        % Width of note.
%~end

\definedimen{\evenshift}{0pt}
\definedimen{\oddshift}{0pt}

\definecount{\zdivpncounter}{0}
\definecount{\zpnpage}{0}


\def \proofnote {%                                      {text}
  \blockcantbein{\proofnote}{\proofnote}%
  \beginblockscope{proofnote}%
  \global\increment \proofnotedepth
  \global\increment \zdivpncounter
  \whichpage{\zpnpage}{zP:\the\divisionname-\the\zdivpncounter}%
  \parindent = 0pt
  \parskip = 2pt
  \textcolor = {black}%                                 %~default soft
  \vshift = 0pt                                         %~default soft
  \processdesign{\proofnote}{}%
  \afterassignment \endproofnote
  \zmntoks =}

\def \endproofnote {%
  \zcalcpnshift
  \setbox \zmnbox = \vtop{%
    \zpushvcontext
    \color{\the\textcolor}%
    \the\bodyfont
    \settextwidth{\width}
    \setparrag{.4\width}%
    \def \endpartext {}%                % Prevent end-of-paragraph text.
    \the\zmntoks
    \endgraf
    \endcolor
    \zpopvcontext}%
  \proofnoteformat
  \long\edef \znext {\noexpand\todo{.Proof note: \the\zmntoks}}%
  \znext
  \global\decrement \proofnotedepth
  \endblockscope{proofnote}}

\def \proofnoteformat {%
  \if \vmodep
    \zmnprevdepth = \prevdepth
    \nointerlineskip
  \else
    \vadjust
  \fi
  \bgroup
    \moveright \zmnshift \vtop to 0pt{%
      \vskip -\parskip
      \vskip \vshift
      \box \zmnbox
      \vss
      \tagpageonly{\uniquetag{zP}{\the\zdivpncounter}}}%
  \egroup
  \if \vmodep \prevdepth = \zmnprevdepth \fi}

\def \zcalcpnshift {%
  \if \evenp{\zpnpage}%
    \if \negp{\evenshift}%
      \zmnshift = \evenshift
    \else
      \calculate \zmnshift = {\textmeasure,+,\evenshift}%
    \fi
  \else
    \if \negp{\oddshift}%
      \zmnshift = \oddshift
    \else
      \calculate \zmnshift = {\textmeasure,+,\oddshift}%
    \fi
  \fi}

% This macro is invoked at the beginning of each division.

\def \zpndivinit {%
  \global\zdivpncounter = 0\relax}