%D \module
%D   [       file=spac-par,
%D        version=2009.10.16, % 1997.03.31, was core-spa.tex
%D          title=\CONTEXT\ Spacing Macros,
%D       subtitle=Paragraphs,
%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 Spacing Macros / Paragraphs}

\unprotect

%D The dreadful sequence \type {\bgroup} \unknown\ \type {\carryoverpar} \unknown\
%D \type {\egroup} is needed when for instance sidefloats are used in combination
%D with something that starts with a group. This is because otherwise the
%D indentation as set (by the output routine) inside the group are forgotten
%D afterwards. (I must not forget its existence).

% Todo (maybe):
%
% \parshape             \getparshape\relax
% \interlinepenalties   \getinterlinepenalties\relax
% \clubpenalties        \getclubpenalties\relax
% \widowpenalties       \getwidowpenalties\relax
% \displaywidowpenalties\getdisplaywidowpenalties\relax

\def\carryoverpar#1% #1 can be \endgroup or \egroup or ... expandable !
  {\normalexpanded
     {\noexpand#1%
      \hangindent\the\hangindent
      \hangafter \the\hangafter
      \parskip   \the\parskip
      \leftskip  \the\leftskip
      \rightskip \the\rightskip
      \relax}}

\unexpanded\def\pushparagraphproperties
  {\edef\currentparagraphproperties{\carryoverpar\relax}%
   \pushmacro\currentparagraphproperties}

\unexpanded\def\popparagraphproperties
  {\popmacro\currentparagraphproperties
   \currentparagraphproperties}

\unexpanded\def\flushparagraphproperties
  {\popmacro\currentparagraphproperties}

%D New experimental stuff, not supported in \MKIV:

\let\freezeparagraphproperties \relax
\let\defrostparagraphproperties\relax
\let\setparagraphfreezing      \relax
\let\forgetparagraphfreezing   \relax
\let\updateparagraphproperties \relax
\let\updateparagraphpenalties  \relax
\let\updateparagraphdemerits   \relax
\let\updateparagraphshapes     \relax

\let\updateparwrapper  \relax
\let\forgetparwrapper  \relax
\let\registerparwrapper\gobblethreearguments
\let\directparwrapper  \gobbletwoarguments

\let\spac_paragraph_wrap  \relax
\let\spac_paragraph_freeze\relax

%D Beware, changing this will break some code (like pos/backgrounds) but it has been
%D changed anyway so let's see where things go wrong.

\installcorenamespace{paragraphintro}

\let\insertparagraphintro\relax % hook into everypar

\newtoks\t_spac_paragraphs_intro_first
\newtoks\t_spac_paragraphs_intro_next
\newtoks\t_spac_paragraphs_intro_each

\newconditional\c_spac_paragraphs_intro_first
\newconditional\c_spac_paragraphs_intro_next
\newconditional\c_spac_paragraphs_intro_each

\unexpanded\def\setupparagraphintro
  {\dodoubleempty\spac_paragraphs_intro}

\unexpanded\def\spac_paragraphs_intro[#1][#2]%
  {\def\spac_paragraphs_intro_step##1%
     {\csname\??paragraphintro\ifcsname\??paragraphintro##1\endcsname##1\fi\endcsname{#2}}%
   \processcommacommand[#1]\spac_paragraphs_intro_step}

\letvalue{\??paragraphintro\empty}\gobbleoneargument

\setvalue{\??paragraphintro\v!reset}#1%
  {\global\setfalse\c_spac_paragraphs_intro_first
   \global\setfalse\c_spac_paragraphs_intro_next
   \global\setfalse\c_spac_paragraphs_intro_each
   \global\t_spac_paragraphs_intro_first\emptytoks
   \global\t_spac_paragraphs_intro_next \emptytoks
   \global\t_spac_paragraphs_intro_each \emptytoks
   \glet\insertparagraphintro\relax}

\setvalue{\??paragraphintro\v!first}#1%
  {\global\settrue\c_spac_paragraphs_intro_first
   \gtoksapp\t_spac_paragraphs_intro_first{#1}%
   \glet\insertparagraphintro\spac_paragraphs_flush_intro}

\setvalue{\??paragraphintro\v!next}#1%
  {\global\settrue\c_spac_paragraphs_intro_next
   \gtoksapp\t_spac_paragraphs_intro_next{#1}%
   \glet\insertparagraphintro\spac_paragraphs_flush_intro}

\setvalue{\??paragraphintro\v!each}#1%
  {\global\settrue\c_spac_paragraphs_intro_each
   \gtoksapp\t_spac_paragraphs_intro_each{#1}%
   \glet\insertparagraphintro\spac_paragraphs_flush_intro}

%D We can say:
%D
%D \starttyping
%D \setupparagraphintro[first][\index{Knuth}]
%D \stoptyping
%D
%D Maybe more convenient is:
%D
%D \starttyping
%D \flushatparagraph{\index{Zapf}}
%D \stoptyping
%D
%D \starttyping
%D \setupparagraphintro[first][\hbox to 3.5em{\tt FIRST \hss}]
%D \setupparagraphintro[first][\hbox to 3.5em{\tt TSRIF \hss}]
%D \setupparagraphintro[next] [\hbox to 3.5em{\tt NEXT  \hss}]
%D \setupparagraphintro[next] [\hbox to 3.5em{\tt TXEN  \hss}]
%D \setupparagraphintro[each] [\hbox to 3.0em{\tt EACH  \hss}]
%D \setupparagraphintro[each] [\hbox to 3.0em{\tt HCEA  \hss}]
%D
%D some paragraph \par
%D some paragraph \par
%D some paragraph \par
%D some paragraph \par
%D
%D \setupparagraphintro[first][\hbox to 3.5em{\tt FIRST \hss}]
%D \setupparagraphintro[first][\hbox to 3.5em{\tt TSRIF \hss}]
%D
%D some paragraph \par
%D some paragraph \par
%D
%D \setupparagraphintro[reset]
%D
%D some paragraph \par
%D \stoptyping

\unexpanded\def\flushatparagraph#1%
  {\global\c_spac_paragraphs_intro_first\plusone
   \gtoksapp\t_spac_paragraphs_intro_first{#1}%
   \glet\insertparagraphintro\spac_paragraphs_flush_intro}

%D Here comes the flusher (we misuse the one level expansion of token registers to
%D feed a nice stream into the paragraph.)

\unexpanded\def\spac_paragraphs_flush_intro % we make sure that the token lists expand directly
  {\normalexpanded{%                        % after another so the first code is there twice
     \ifconditional\c_spac_paragraphs_intro_each
       \ifconditional\c_spac_paragraphs_intro_next
         \glet\insertparagraphintro\spac_paragraphs_flush_intro_next
       \else
         \glet\insertparagraphintro\spac_paragraphs_flush_intro_each
       \fi
       \ifconditional\c_spac_paragraphs_intro_first
         \global\setfalse\c_spac_paragraphs_intro_first
         \global\t_spac_paragraphs_intro_first\emptytoks
         \the\t_spac_paragraphs_intro_first
       \fi
       \the\t_spac_paragraphs_intro_each
     \else
       \ifconditional\c_spac_paragraphs_intro_next
         \glet\insertparagraphintro\spac_paragraphs_flush_intro_next
       \fi
       \ifconditional\c_spac_paragraphs_intro_first
         \global\setfalse\c_spac_paragraphs_intro_first
         \global\t_spac_paragraphs_intro_first\emptytoks
         \the\t_spac_paragraphs_intro_first
       \fi
     \fi}}

\unexpanded\def\spac_paragraphs_flush_intro_next
  {\normalexpanded{%
     \global\setfalse\c_spac_paragraphs_intro_next
     \global\t_spac_paragraphs_intro_next\emptytoks
     \ifconditional\c_spac_paragraphs_intro_each
       \glet\insertparagraphintro\spac_paragraphs_flush_intro_each
       \the\t_spac_paragraphs_intro_next
       \the\t_spac_paragraphs_intro_each
     \else
       \glet\insertparagraphintro\relax
       \the\t_spac_paragraphs_intro_next
     \fi}}

\unexpanded\def\spac_paragraphs_flush_intro_each
  {\the\t_spac_paragraphs_intro_each}

%D \macros
%D   {flushatnextpar}
%D
%D This macro collects data that will be flushed at the next paragraph. By using
%D this macro you can avoid interfering nodes (writes, etc).

\let\flushpostponednodedata\relax % hook into everypar

\newbox  \b_spac_postponed_data
%newcount\c_spac_postponed_data

% \installcorenamespace {postponednodesstack}
%
% \initializeboxstack\??postponednodesstack
%
% \unexpanded\def\pushpostponednodedata
%   {\global\advance\c_spac_postponed_data\plusone
%    \savebox\??postponednodesstack{\the\c_spac_postponed_data}{\box\b_spac_postponed_data}}
%
% \unexpanded\def\poppostponednodedata
%   {\global\setbox\b_spac_postponed_data\hbox{\foundbox\??postponednodesstack{\the\c_spac_postponed_data}}%
%    \global\advance\c_spac_postponed_data\minusone
%    \ifvoid\b_spac_postponed_data\else
%      \glet\flushpostponednodedata\spac_postponed_data_flush
%    \fi}

\newtoks\everyflushatnextpar

\unexpanded\def\pushpostponednodedata
  {\globalpushbox\b_spac_postponed_data}

\unexpanded\def\poppostponednodedata
  {\globalpopbox\b_spac_postponed_data
   \ifvoid\b_spac_postponed_data\else
     \glet\flushpostponednodedata\spac_postponed_data_flush
   \fi}

\unexpanded\def\flushatnextpar
  {\begingroup
   \the\everyflushatnextpar
   \glet\flushpostponednodedata\spac_postponed_data_flush
   \dowithnextboxcs\spac_postponed_data_finish\hpack}

\def\spac_postponed_data_finish
  {\global\setbox\b_spac_postponed_data\hpack % to\zeropoint
     {\box\b_spac_postponed_data\box\nextbox}%
   \endgroup}

\def\spac_postponed_data_flush
  {%\iftrialtypesetting \else
     \ifvoid\b_spac_postponed_data\else
       \hpack{\smashedbox\b_spac_postponed_data}% \box\b_spac_postponed_data
     \fi
     \glet\flushpostponednodedata\relax
   }%\fi}

\unexpanded\def\doflushatpar % might be renamed
  {\ifvmode
     \expandafter\flushatnextpar
   \else
     \expandafter\firstofoneargument
   \fi}

\protect \endinput

