%D \module
%D   [       file=page-pcl,
%D        version=2017.11.08,
%D          title=\CONTEXT\ Page Macros,
%D       subtitle=Page Columns,
%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 Page Macros / Page Columns}

%D This is very experimental code! We took a bit from the mixed columns and single
%D column page code. This one works acceptable with floats and is for whole double
%D column documents. We don't balance (yet). Footnotes are per column. One can have
%D side floats too. No balancing and other fancy features.
%D
%D Don't use this in production! Although the main approach will stay there might be
%D changes in the way floats are dealt with. Not much testing has been done but as
%D we stay close to the single column mode we expect most to just work. Only floats
%D are the (usual) pain. Backgrounds, line numbering, etc.\ not tested either.

\unprotect

\definemeasure[onecolumn]   [\columnwidth]
\definemeasure[twocolumns]  [\dimexpr\plustwo  \columnwidth+          \columndistance\relax]
\definemeasure[threecolumns][\dimexpr\plusthree\columnwidth+\plustwo  \columndistance\relax]
\definemeasure[fourcolumns] [\dimexpr\plusfour \columnwidth+\plusthree\columndistance\relax]

\newinteger    \c_page_col_n_of_columns \c_page_col_n_of_columns\plusone
\newinteger    \c_page_col_current      \c_page_col_current     \plusone
\newdimension  \d_page_col_distance
\newdimension  \d_page_col_max_height
\newdimension  \d_page_col_max_width
%newdimension  \d_page_col_balance_step
\newdimension  \d_page_col_column_width
\newdimension  \d_page_col_top_height
\newdimension  \d_page_col_top_width
\newdimension  \d_page_col_available
\newdimension  \d_page_col_sofar
\newconditional\c_page_col_page

%D We need to step over empty columns.

\protected\def\page_col_command_next_page
  {\page_col_eject_page}

\permanent\protected\def\page_col_column
  {\page_otr_eject_page}

\protected\def\page_col_eject_page
  {\begingroup
   \scratchcountertwo  \realpageno
   \page_otr_eject_page
   \scratchcounterone  \c_page_col_current
   \scratchcounterthree\zerocount
   \doloop{%
     \ifnum\scratchcounterthree>\plushundred
       % too many attempts
       \exitloop
     \orelse\ifnum\realpageno>\scratchcountertwo
       % we advanced at least one page so we're done
       \exitloop
     \else
       \ifnum\scratchcounterone=\c_page_col_current
          \dontleavehmode\null
       \fi
       \page_otr_eject_page
       \scratchcounterone\c_page_col_current
       \advanceby\scratchcounterthree\plusone
     \fi
   }%
   \endgroup}

%D \unknown

\protected\def\page_col_command_next_page_and_inserts
  {\page_otr_eject_page_and_flush_inserts}

%D \unknown

\protected\def\page_col_command_set_hsize
  {\global\hsize\d_page_col_column_width\relax
   \global\d_page_col_available{%
      \numexpr\c_page_col_n_of_columns-\c_page_col_current+\plusone\relax\d_page_col_column_width
    + \numexpr\c_page_col_n_of_columns-\c_page_col_current         \relax\d_page_col_distance
   }%
   \global\d_page_col_sofar
   \ifnum\c_page_col_n_of_columns=\plusone
     \zeropoint
   \else
     \numexpr\c_page_col_n_of_columns-\plusone\relax
     \dimexpr\d_page_col_column_width+\d_page_col_distance\relax
   \fi
   % consistent with mixed:
   \textwidth\d_page_col_column_width}

%D \unknown

\def\page_col_registered_text_area_b#1%
  {\begingroup
   \makeupwidth\d_page_col_column_width
   \page_one_registered_text_area_b{#1}%
   \endgroup}

\protected\def\page_col_command_package_contents#1#2% \box<n> \unvbox<n> % this one will be redone (checked)
  {\bgroup
   \setbox\b_page_one_contents\vbox to \textheight
     {\page_one_registered_text_area_a#1#2}%
   \page_one_command_package_show_state
   \ht\b_page_one_contents\textheight
   \page_col_registered_text_area_b
     {\box\b_page_one_contents}%
   \egroup}

\def\page_col_fix_depth
  {\scratchdepth{\openstrutdepth-\d_page_one_natural_depth}%
   \ifdim{\d_page_one_natural_total+\scratchdepth}>\textheight
     % forget about it, prevents an overfull warning
   \else
     \vskip\scratchdepth
     \prevdepth\openstrutdepth
   \fi}

\protected\def\page_col_command_package_contents_one#1#2% \box<n> \unvbox<n> % this one will be redone (checked)
  {\bgroup
     \forgetall
     % see one for comments as it is similar
     \strc_notes_check_if_bottom_present
    %\d_page_one_natural_height\ht#2\relax
     \d_page_one_natural_depth\dp#2\relax
     \d_page_one_natural_total\boxrepack#2\relax
   % \page_layouts_check_stretch#2%
     \setbox\b_page_one_contents\vbox to \textheight
       {\page_col_command_flush_top_insertions
        \page_one_registered_text_area_a#1#2%
        \hsize\d_page_col_column_width
        \ifgridlinesnapping
          % gridlinesnapping: to be decided
          \page_col_fix_depth
          \page_col_command_flush_bottom_insertions
          \vfil
        \orelse\ifgridsnapping
          \page_col_fix_depth
          \page_col_command_flush_bottom_insertions
          \vfil
        \orelse\ifcase\bottomraggednessmode
          % ragged (default)
          \page_col_fix_depth
          \page_col_command_flush_bottom_insertions
          \vfil
        \or
          % align (normal)
          \page_col_command_flush_bottom_insertions
        \or
          % baseline
          \vkern{\maxdepth-\d_page_one_natural_depth}%
          \page_col_command_flush_bottom_insertions
        \or
          % depth
          \vskip-\d_page_one_natural_depth
          \page_col_command_flush_bottom_insertions
        \fi
        \fakepagenotes}%
     \page_layouts_check_stretch\b_page_one_contents
     \page_one_command_package_show_state
     \ifconditional\c_notes_bottom_present
       \ifgridlinesnapping
         % gridlinesnapping: to be decided
         \ifcase\layoutlines % todo: use helper
           \getrawnoflines\textheight
         \else
           \noflines\layoutlines
         \fi
         \scratchoffset{\numexpr\noflines-\plusone\relax\lineheight+\topskip}%
       \orelse\ifgridsnapping
         \ifcase\layoutlines % todo: use helper
           \getrawnoflines\textheight
         \else
           \noflines\layoutlines
         \fi
         \scratchoffset{\numexpr\noflines-\plusone\relax\lineheight+\topskip}%
       \else
         \scratchoffset\ht\b_page_one_contents
       \fi
       \setbox\b_page_one_bottom_notes\hpack
         {\hsize\d_page_col_column_width
          \setupnotes[\c!width=\textwidth]%
          \lower{\scratchoffset-\initialpageskip}\vbox\bgroup
            \placebottomnotes
           %\kern\zeropoint
            \vkern
             %
             % needs testing:
             %
             % \ifgridlinesnapping
             %   -% indeed
             % \orelse\ifgridsnapping
             %   -% indeed
             % \fi
              \d_strc_notes_bottom_depth
          \egroup}%
       \ht\b_page_one_contents    \zeropoint
       \wd\b_page_one_contents    \zeropoint
       \ht\b_page_one_bottom_notes\zeropoint
       \wd\b_page_one_bottom_notes\d_page_col_column_width
       \page_col_registered_text_area_b
         {\vpack to \textheight
            {\hpack{\box\b_page_one_contents\box\b_page_one_bottom_notes}}}%
     \else
       \ifcase\c_page_scale_lines
         % nothing to do: vz not enabled
       \orelse\ifdim\d_page_box_stretch_delta>\zeropoint
         \page_scale_text_box_register_box\b_page_one_contents
         \page_scale_text_box\b_page_one_contents
       \else
         \page_scale_text_box_register_page
         \page_scale_text_box\b_page_one_contents
       \fi
       \ht\b_page_one_contents\textheight
       \wd\b_page_one_contents\d_page_col_column_width
       \page_col_registered_text_area_b
         {\box\b_page_one_contents}%
     \fi
   \egroup}

%D \unknown

\protected\def\page_col_command_side_float_output
  {% % %
   \ifzeropt\insertheight\namedinsertionnumber\s!topfloat\else
     \scratchwidth\insertwidth\namedinsertionnumber\s!topfloat\relax
     \ifdim\scratchwidth>\d_page_col_top_width
       \global\d_page_col_top_width \scratchwidth
     \fi
     \global\d_page_col_top_height\insertheight\namedinsertionnumber\s!topfloat\relax
   \fi
   % % %
   \setbox\scratchbox\vbox\bgroup
      \page_col_command_package_contents_one\unvbox\normalpagebox
   \egroup
   \putboxincache\s!pagecolumn{\the\c_page_col_current}\scratchbox
   \ifnum\c_page_col_current=\c_page_col_n_of_columns
     \page_col_routine_package
     \page_otr_construct_and_shipout\box\normalpagebox\plusone
     \global\c_page_col_current\plusone
     \global\d_page_col_top_height\zeropoint
     \global\d_page_col_top_width\zeropoint
   % \page_col_command_flush_top_insertions
   % \page_col_command_flush_floats
   \else
     \ifdim\d_page_col_top_width>\zeropoint
       \ifdim\d_page_col_top_width>\d_page_col_sofar
         \begingroup
         \floatingpenalty\zerocount
         \insert\namedinsertionnumber\s!topfloat\bgroup
           \vbox to \d_page_col_top_height{\vss}%
             % can be an option
             \page_col_command_flush_top_insertions
             \page_col_command_flush_floats
             % so far till option
           \egroup
         \endgroup
       \fi
     \fi
     \global\advanceby\c_page_col_current\plusone
   \fi
   %
   \page_col_notes_synchronize
   %
   \page_col_command_set_vsize
   \page_col_command_set_hsize}

% use \currentmixedcolumns instead of \recurselevel

\lettonothing\page_col_routine_balance

\def\page_col_routine_package
  {\page_col_routine_balance
   \global\setbox\normalpagebox\hbox to \makeupwidth\bgroup
     \edef\p_separator{\pagecolumnsparameter\c!separator}%
     \pagecolumnseparatorwidth\d_page_col_distance
     \ifcstok{\pagecolumnsparameter\c!direction}\v!reverse
       \localcontrolledloop\c_page_col_n_of_columns\plusone\minusone
         {\mofcolumns\currentloopiterator
          \page_col_routine_package_step
          \ifnum\mofcolumns>\plusone
            \page_col_routine_package_separate
          \fi}%
     \else
       \localcontrolledloop\plusone\c_page_col_n_of_columns\plusone
         {\mofcolumns\currentloopiterator
          \page_col_routine_package_step
          \ifnum\mofcolumns<\c_page_col_n_of_columns
            \page_col_routine_package_separate
          \fi}%
     \fi
   \egroup
   \resetboxesincache{\s!pagecolumn\s!pagecolumn}%
   \resetboxesincache{\s!pagecolumn}%
   \global\initialpageskip\zeroskip
   \global\initialtopskip \zeroskip}


\def\page_col_routine_package_step
  {% needs packaging anyway
    \getboxfromcache{\s!pagecolumn\s!pagecolumn}{\number\mofcolumns}\scratchboxone
    \getboxfromcache{\s!pagecolumn}{\number\mofcolumns}\scratchboxtwo
    \ht\scratchboxtwo{\ht\scratchboxtwo-\ht\scratchboxone}%
    \page_lines_add_numbers_to_box\scratchbox\mofcolumns\c_page_col_n_of_columns\plusone % new
    \page_marks_synchronize_column\plusone\c_page_col_n_of_columns\mofcolumns\scratchboxtwo
    % backgrounds
    \anch_mark_column_box\scratchboxtwo\mofcolumns
    \pagecolumnseparatorheight\ht\scratchboxtwo
    \pagecolumnseparatordepth \dp\scratchboxtwo
    \vpack\bgroup
      \box\scratchboxone
      \nointerlineskip\par
      \inheritedpagecolumnsframedbox\mofcolumns\scratchboxtwo
   \egroup}

%D \unknown

\protected\def\page_col_command_check_if_float_fits
  {\ifconditional\c_page_floats_not_permitted
     % forget about it anyway
     \global\c_page_floats_room\conditionalfalse
   \else
     % first we check the current column
     \ifdim{\hsize-\naturalfloatwd}>-\onepoint
       \global\c_page_floats_room\conditionaltrue
     \else
       \global\c_page_floats_room\conditionalfalse
     \fi
     \ifconditional\c_page_floats_room
       % we fit in the column but do we have room
       \ifdim{\pagetotal+\lineheight}>\pagegoal
         % try again later
         \goodbreak
       \fi
       \ifdim\pagetotal>\zeropoint
         \scratchdimenone{\pagetotal+\floatheight+\d_strc_floats_top-\pageshrink}%
         \scratchdimentwo\pagegoal
         \relax % needed
         \ifcase\c_page_one_float_method
           % method 0 : raw
         \or
           % method 1 : safe
           \advanceby\scratchdimentwo -\strutdp
         \or
           % method 2 : tight
           \advanceby\scratchdimenone -\onepoint
         \fi
         \relax % really needed ! ! ! !
         \ifdim\scratchdimenone>\scratchdimentwo
           % there is no room, give up
           \global\c_page_floats_room\conditionalfalse
           % now we can decide on a top float
%          \fi
         \else
%            \ifconditional\c_page_floats_room
%              \global\setbox\floatbox\hpack to \d_page_col_float_available{\hss\box\floatbox\hss}%
%            \fi
         \fi
       \fi
     \fi
   \fi}

%D \unknown

\def\page_col_set_float_pack_hsize
  {\ifnum\c_page_col_current=\c_page_col_n_of_columns
     \c_page_col_current\plusone
   \else
     \advanceby\c_page_col_current\plusone
   \fi
   \page_col_command_set_hsize
   \hsize\d_page_col_available}

\protected\def\page_col_command_flush_floats
  {\global\c_page_floats_flushing\conditionaltrue
   \ifconditional\c_page_floats_some_waiting
     \par
     \page_col_set_float_pack_hsize
     \page_col_command_flush_floats_indeed
   \fi
   \global\savednoffloats\zerocount
   \global\c_page_floats_some_waiting\conditionalfalse
   \global\c_page_floats_flushing\conditionalfalse}

\def\page_floats_show_pack_state_indeed#1%
  {\llap{\smash{\backgroundline[black]{\strut\smallinfofont\white#1\space\the\nofcollectedfloats\space of\space\the\savednoffloats:\the\hsize}}\hkern.25\emwidth}}

\installtextracker
  {floats.collecting}
  {\let\page_floats_show_pack_state\page_floats_show_pack_state_indeed}
  {\let\page_floats_show_pack_state\gobbleoneargument}

\let\page_floats_show_pack_state\gobbleoneargument

\def\page_col_command_flush_floats_indeed % much in common with OTRSET
  {\ifconditional\c_page_floats_some_waiting
     \ifconditional\c_page_floats_compress_flushed
       \c_page_floats_center_box\conditionalfalse % not needed as we do call directly
       \page_floats_collect\s!text\hsize\d_page_floats_compress_distance
       %
       \ifnum\nofcollectedfloats=\plusone
         \ifdim\naturalfloatwd>\hsize
           \nofcollectedfloats\zerocount
         \fi
       \fi
       \ifnum\nofcollectedfloats>\zerocount
         \global\setbox\floatbox\hpack to \hsize
           {\page_floats_show_pack_state F%
            \hfil
            \dorecurse\nofcollectedfloats
              {\ifcase\columndirection % nog document wide
                 \page_floats_flush\s!text\plusone
               \else
                 \page_floats_flush\s!text{\tointeger{\nofcollectedfloats-\recurselevel+1}}%
               \fi
               % this could happen at the lua end instead
               \scratchdimen{\wd\floatbox-\naturalfloatwd}%
               \ifdim\scratchdimen<\zeropoint
                 \global\setbox\floatbox\hpack spread -\scratchdimen{\hss\box\floatbox\hss}%
               \fi
               %
               \ifdim\wd\floatbox>\textwidth % \hsize
                 \hpack to \textwidth{\hss\box\floatbox\hss}% \textwidth
               \else
                 \box\floatbox
               \fi
               \ifnum\recurselevel<\nofcollectedfloats
                 \hfil
               \fi}%
            \hfil}%
           \doplacefloatbox
         % \page_one_insert_top_float
           \doubleexpandafter\page_col_command_flush_floats_indeed
       \else
         % todo
       \fi
     \else
       \page_floats_get
     % \page_one_insert_top_float
       \doplacefloatbox
       \doubleexpandafter\page_col_command_flush_floats_indeed
     \fi
   \fi}

\protected\def\page_col_command_flush_saved_floats % like one
  {\global\d_page_floats_inserted_top\zeropoint
   \global\d_page_floats_inserted_bottom\zeropoint
   \ifconditional\c_page_floats_flushing \else
     \page_col_command_set_top_insertions
     \page_col_command_set_bottom_insertions
     \ifconditional\c_page_floats_some_waiting
        \ifcstok{\rootfloatparameter\c!cache}\v!no
          \page_col_command_flush_floats % could be _otr_
        \fi
     \orelse\ifconditional\c_page_margin_blocks_present
       \page_col_command_flush_floats
     \fi
   \fi}

\protected\def\page_col_command_set_top_insertions
  {\bgroup
   \ifconditional\c_page_floats_some_waiting
     \noffloatinserts\zerocount
     \let\totaltopinserted\!!zeropoint
     \page_col_set_float_pack_hsize
     \page_col_command_set_top_insertions_indeed
     \ifnum\rootfloatparameter\c!nbottom=\zerocount
       \ifnum\rootfloatparameter\c!nlines>\zerocount
         \ifdim\totaltopinserted>\zeropoint\relax
           \ifdim{\rootfloatparameter\c!nlines\lineheight+\totaltopinserted}>\textheight
             \showmessage\m!floatblocks8{\rootfloatparameter\c!nlines}%
             \page_otr_fill_and_eject_page % was tripple: vfilll
           \fi
         \fi
       \fi
     \fi
   \fi
   \egroup}

\permanent\def\d_page_col_collected_top_float_height % pseudo
  {\dimexpr
     \d_page_floats_inserted_top +
     \maxcollectedfloatstotal +
     \ifdim\d_strc_floats_top>\d_strc_floats_bottom
       \d_strc_floats_top
     \else
       \d_strc_floats_bottom
     \fi
   \relax}

\def\page_col_command_set_top_insertions_indeed
  {\ifnum\noffloatinserts<\c_page_floats_n_of_top
     \ifcase\savednoffloats
       \let\page_col_command_set_top_insertions_indeed\relax
     \else
       \page_floats_collect\s!text\hsize\emwidth
       \ifdim\d_page_col_collected_top_float_height<\textheight
         \global\setbox\floatbox\hpack to \hsize
           {\page_floats_show_pack_state T%
            \hfil
            \dorecurse\nofcollectedfloats
              {\ifcase\columndirection % nog document wide
                 \page_floats_flush\s!text\plusone
               \else
                 \page_floats_flush\s!text{\tointeger{\nofcollectedfloats-\recurselevel+1}}%
               \fi
               % this could happen at the lua end instead
               \scratchdimen{\wd\floatbox-\naturalfloatwd}%
               \ifdim\scratchdimen<\zeropoint
                   \global\setbox\floatbox\hpack spread -\scratchdimen{\hss\box\floatbox\hss}%
               \fi
               %
               \ifdim\wd\floatbox>\makeupwidth % \hsize
                 \hpack to \makeupwidth{\hss\box\floatbox\hss}%
               \else
                 \box\floatbox
               \fi
               \ifnum\recurselevel<\nofcollectedfloats
                 \hfil
               \fi}%
            \hfil}%
         \page_one_prepare_top_float
         \xdef\totaltopinserted{\the\d_page_floats_inserted_top}%
         \page_one_insert_top_float
         \ifconditional\c_page_floats_some_waiting
           \advanceby\noffloatinserts \plusone
         \else
           \noffloatinserts\c_page_floats_n_of_top\relax
         \fi
         \page_floats_report_flushed
      \else
         \let\page_col_command_set_top_insertions_indeed\relax
       \fi
     \fi
   \else
     \ifconditional\c_page_floats_some_waiting
       \showmessage\m!floatblocks6{\the\c_page_floats_n_of_top}%
     \fi
     \let\page_col_command_set_top_insertions_indeed\relax
   \fi
   \page_col_command_set_top_insertions_indeed}

\let\page_col_command_flush_top_insertions   \page_one_command_flush_top_insertions
\let\page_col_command_flush_bottom_insertions\page_one_command_flush_bottom_insertions

\let\page_col_command_set_bottom_insertions  \page_one_command_set_bottom_insertions

\let\page_col_command_flush_float_box        \page_one_command_flush_float_box
\let\page_col_command_synchronize_side_floats\page_one_command_synchronize_side_floats
\let\page_col_command_flush_side_floats      \page_one_command_flush_side_floats
\let\page_col_command_flush_margin_blocks    \page_one_command_flush_margin_blocks
\let\page_col_command_test_page              \page_one_command_test_page

%D The separator code is more or less the same as mixed columns but we need
%D to compensate for the top floats so we comment a bit for now.

\newdimension\pagecolumnseparatorheight
\newdimension\pagecolumnseparatordepth
\newdimension\pagecolumnseparatorwidth

% \installcorenamespace{pagecolumnsseparator}
%
% \protected\def\installpagecolumnseparator#1#2%
%   {\setvalue{\??pagecolumnsseparator#1}{#2}}
%
% \installpagecolumnseparator\v!rule
%   {\vrule
%      \s!width \pagecolumnsparameter\c!rulethickness
%      \s!height\pagecolumnseparatorheight
%      \s!depth \pagecolumnseparatordepth
%    \relax}
%
% \def\page_col_routine_package_separate
%   {\ifcsname\??pagecolumnsseparator\p_separator\endcsname
%      \page_col_command_inject_separator
%    \else
%      \hss
%    \fi}
%
% \protected\def\page_col_command_inject_separator
%   {\begingroup
%    \setbox\scratchbox\hbox to \zeropoint \bgroup
%      \hss
%      \starttextproperties
%      \usepagecolumnscolorparameter\c!rulecolor
%      \begincsname\??pagecolumnsseparator\p_separator\endcsname % was \c!rule
%      \stoptextproperties
%      \hss
%    \egroup
%    \ht\scratchbox\zeropoint
%    \dp\scratchbox\zeropoint
%    \hss
%    \box\scratchbox
%    \hss
%    \endgroup}

\def\page_col_routine_package_separate
  {\hss}

%D \unknown

\protected\def\page_col_command_routine
  {\page_sides_output_routine}

% % not:
%
% \protected\def\page_col_command_routine
%   {\ifconditional\c_page_sides_short
%      \page_sides_output_routine_yes_column
%    \else
%      \page_sides_output_routine_nop_column
%    \fi}
%
% \let\page_sides_output_routine_nop_column\page_sides_output_routine
%
% \def\page_sides_output_routine_yes_column % this might become the main one too
%   {\unvbox\normalpagebox % bah, and the discards?
%   %\page_col_column
%    \column % \page
%    % why was this \global\holdinginserts\zerocount
%    \global\c_page_sides_short\conditionalfalse}

\let\page_col_command_flush_all_floats\relax

%D \unknown

\defineoutputroutine
  [\s!pagecolumn]
  [\s!page_otr_command_routine                =\page_col_command_routine,
   \s!page_otr_command_package_contents       =\page_col_command_package_contents,
   \s!page_otr_command_set_vsize              =\page_col_command_set_vsize,
   \s!page_otr_command_set_hsize              =\page_col_command_set_hsize,
 % \s!page_otr_command_synchronize_hsize      =\page_col_command_synchronize_hsize, % not done
   \s!page_otr_command_next_page              =\page_col_command_next_page,
   \s!page_otr_command_next_page_and_inserts  =\page_col_command_next_page_and_inserts,
   \s!page_otr_command_set_top_insertions     =\page_col_command_set_top_insertions,
   \s!page_otr_command_set_bottom_insertions  =\page_col_command_set_bottom_insertions,
   \s!page_otr_command_flush_top_insertions   =\page_col_command_flush_top_insertions,
   \s!page_otr_command_flush_bottom_insertions=\page_col_command_flush_bottom_insertions,
   \s!page_otr_command_check_if_float_fits    =\page_col_command_check_if_float_fits,
 % \s!page_otr_command_set_float_hsize        =\page_col_command_set_float_hsize,   % not done
   \s!page_otr_command_flush_float_box        =\page_col_command_flush_float_box,
   \s!page_otr_command_side_float_output      =\page_col_command_side_float_output,
   \s!page_otr_command_synchronize_side_floats=\page_col_command_synchronize_side_floats,
   \s!page_otr_command_flush_floats           =\page_col_command_flush_floats,
   \s!page_otr_command_flush_side_floats      =\page_col_command_flush_side_floats,
   \s!page_otr_command_flush_saved_floats     =\page_col_command_flush_saved_floats,
   \s!page_otr_command_flush_all_floats       =\page_col_command_flush_all_floats,
   \s!page_otr_command_flush_margin_blocks    =\page_col_command_flush_margin_blocks,
   \s!page_otr_command_test_column            =\page_col_command_test_page
  ]

%D \unknown

\installfloatmethod \s!pagecolumn \v!here        \page_one_place_float_here
\installfloatmethod \s!pagecolumn \v!force       \page_one_place_float_force
\installfloatmethod \s!pagecolumn \v!left        \page_one_place_float_left
\installfloatmethod \s!pagecolumn \v!right       \page_one_place_float_right
\installfloatmethod \s!pagecolumn \v!text        \page_one_place_float_text
\installfloatmethod \s!pagecolumn \v!top         \page_one_place_float_top
\installfloatmethod \s!pagecolumn \v!bottom      \page_one_place_float_bottom
\installfloatmethod \s!pagecolumn \v!auto        \page_one_place_float_auto
\installfloatmethod \s!pagecolumn \v!margin      \page_one_place_float_margin
\installfloatmethod \s!pagecolumn \v!opposite    \page_one_place_float_face
\installfloatmethod \s!pagecolumn \v!page        \page_one_place_float_page
\installfloatmethod \s!pagecolumn \v!leftpage    \page_one_place_float_leftpage
\installfloatmethod \s!pagecolumn \v!rightpage   \page_one_place_float_rightpage
\installfloatmethod \s!pagecolumn \v!inmargin    \page_one_place_float_inmargin
\installfloatmethod \s!pagecolumn \v!inleft      \page_one_place_float_leftmargin
\installfloatmethod \s!pagecolumn \v!inright     \page_one_place_float_rightmargin
\installfloatmethod \s!pagecolumn \v!leftmargin  \page_one_place_float_leftmargin
\installfloatmethod \s!pagecolumn \v!rightmargin \page_one_place_float_rightmargin
\installfloatmethod \s!pagecolumn \v!leftedge    \page_one_place_float_leftedge
\installfloatmethod \s!pagecolumn \v!rightedge   \page_one_place_float_rightedge
\installfloatmethod \s!pagecolumn \v!somewhere   \page_one_place_float_somewhere
\installfloatmethod \s!pagecolumn \v!backspace   \page_one_place_float_backspace
\installfloatmethod \s!pagecolumn \v!cutspace    \page_one_place_float_cutspace
%installfloatmethod \s!pagecolumn \s!tblr        \page_one_place_float_top
%installfloatmethod \s!pagecolumn \s!lrtb        \page_one_place_float_top
%installfloatmethod \s!pagecolumn \s!tbrl        \page_one_place_float_top
%installfloatmethod \s!pagecolumn \s!fxtb        \page_one_place_float_top
%installfloatmethod \s!pagecolumn \s!rltb        \page_one_place_float_top
%installfloatmethod \s!pagecolumn \s!btlr        \page_one_place_float_bottom
%installfloatmethod \s!pagecolumn \s!lrbt        \page_one_place_float_bottom
%installfloatmethod \s!pagecolumn \s!btrl        \page_one_place_float_bottom
%installfloatmethod \s!pagecolumn \s!rlbt        \page_one_place_float_bottom
%installfloatmethod \s!pagecolumn \s!fxbt        \page_one_place_float_bottom
%installfloatmethod \s!pagecolumn \s!fixd        \page_one_place_float_force

\installfloatmethod \s!pagecolumn \v!local       \somelocalfloat

%D The main interface:

\installcorenamespace{pagecolumns}

\installframedcommandhandler \??pagecolumns {pagecolumns} \??pagecolumns

\setuppagecolumns
  [\c!distance=1.5\bodyfontsize,
   \c!n=\plustwo,
   \c!page=\v!yes,
  %\c!align=, % inherit (also replaces tolerance)
  %\c!before=,
  %\c!after=,
  %\c!separator=\v!none,
  %\c!setups=,
  %\c!balance=\v!no,
  %\c!blank={\v!line,\v!fixed}, yes or no
   \c!frame=\v!off,
   \c!strut=\v!no,
   \c!offset=\v!overlay,
  %\c!maxheight=\textheight,
   \c!maxwidth=\makeupwidth,
  %\c!grid=\v!tolerant,
  %\c!internalgrid=\v!line,
   \c!direction=\v!normal]

\appendtoks % could become an option
    \protected\frozen\instance\edefcsname\e!start\currentpagecolumns\endcsname{\startpagecolumns[\currentpagecolumns]}%
    \protected\frozen\instance\edefcsname\e!stop \currentpagecolumns\endcsname{\stoppagecolumns}%
\to \everydefinepagecolumns

\def\page_col_pickup_preceding
  {\begingroup
   \setupoutputroutine[\s!mixedcolumn]%
   \c_page_mix_routine\c_page_mix_routine_intercept
   \page_otr_trigger_output_routine
   \ifvoid\b_page_mix_preceding \else
     % moved here, before the packaging
     \page_postprocessors_linenumbers_deepbox\b_page_mix_preceding
     % we need to avoid unvboxing with successive balanced on one page
     \global\setbox\b_page_mix_preceding\vbox\bgroup
       % yes or no: \forcestrutdepth
       \unvbox\b_page_mix_preceding
       \forcestrutdepth
     \egroup
     \wd\b_page_mix_preceding\makeupwidth
     \global\d_page_mix_preceding_height\ht\b_page_mix_preceding
   \fi
   \endgroup}

% Keep this one as original:
%
% \def\page_col_flush_preceding
%   {\ifvoid\b_page_mix_preceding \else
%      % this is just one method but ok for now
%      \begingroup
%      % we might need more but for now this is ok
%      \setupfloat[\c!spacebefore=,\c!spaceafter=]%
%      \startplacefigure[\c!location={\v!top,\v!none}]%
%        \box\b_page_mix_preceding
%      \stopplacefigure
%      \endgroup
%    \fi}

\def\page_col_flush_preceding
  {\ifvoid\b_page_mix_preceding \else
     \scratchwidth \emwidth
     \scratchheight\ht\b_page_mix_preceding
     \scratchdepth \dp\b_page_mix_preceding
     \global\initialpageskip\htdp\b_page_mix_preceding
     \global\initialtopskip \strutht
     % for the moment
     \setbox\scratchbox\vbox\bgroup
        \pagediscards
     \egroup
     \global\advanceby\initialtopskip \ht\scratchbox
     % till here
     \setbox\scratchbox\hbox to \zeropoint
       \bgroup
         \box\b_page_mix_preceding
       \egroup
     \putboxincache{\s!pagecolumn\s!pagecolumn}{\number\plusone}\scratchbox
     \dostepwiserecurse\plustwo\c_page_col_n_of_columns\plusone
       {\setbox\scratchbox\hbox to \zeropoint
          \bgroup
            \novrule
              \s!width \scratchwidth
              \s!height\scratchheight
              \s!depth \scratchdepth
            \hss
          \egroup
        \putboxincache{\s!pagecolumn\s!pagecolumn}{\recurselevel}\scratchbox}%
   \fi}

% \let\page_col_notes_initialize \relax
% \let\page_col_notes_synchronize\relax
% \let\page_col_notes_reset      \relax
%
% \protected\def\page_col_command_set_vsize % \page_one_command_set_vsize minus the pagegoal setting
%   {\ifgridlinesnapping
%      % gridlinesnapping: to be decided
%      \ifcase\layoutlines % todo: use helper
%        \getrawnoflines\textheight
%      \else
%        \noflines\layoutlines
%      \fi
%      \global\vsize\noflines\openlineheight
%    \orelse\ifgridsnapping
%      \ifcase\layoutlines % todo: use helper
%        \getrawnoflines\textheight
%      \else
%        \noflines\layoutlines
%      \fi
%      \global\vsize\noflines\openlineheight
%    \else
%      \global\vsize\textheight
%    \fi}

\newconditional\c_page_col_notes_lastcolumn

\def\page_col_notes_synchronize
  {\insertstoring\zerocount
   \ifnum\c_page_col_current=\c_page_col_n_of_columns\relax
     \strc_notes_process\page_col_notes_inject
     \ifconditional\c_page_col_notes_lastcolumn
       \insertstoring\plusone
     \fi
   \else
     \strc_notes_process\page_col_notes_delay
     \ifconditional\c_page_col_notes_lastcolumn
       \insertstoring\plustwo
     \fi
   \fi}

\def\page_col_notes_delay {\c_page_col_notes_lastcolumn\conditionalfalse\ifcstok{\noteparameter\c!location}\v!lastcolumn\c_page_col_notes_lastcolumn\conditionaltrue\insertstorage\currentnoteinsertionnumber\plusone  \fi}
\def\page_col_notes_inject{\c_page_col_notes_lastcolumn\conditionalfalse\ifcstok{\noteparameter\c!location}\v!lastcolumn\c_page_col_notes_lastcolumn\conditionaltrue\insertstorage\currentnoteinsertionnumber\zerocount\fi}

\def\page_col_notes_initialize {\insertstoring\zerocount\strc_notes_process\page_col_notes_delay}
\def\page_col_notes_reset      {\insertstoring\zerocount\strc_notes_process\page_col_notes_inject}

\protected\def\page_col_command_set_vsize % different !
  {\page_one_command_set_vsize}

\permanent\tolerant\protected\def\startpagecolumns[#S#1]%
  {\begingroup
   \begingroup
   \ifhastok={#1}%
     \lettonothing\currentpagecolumns
     \setuppagecolumns[#1]%
   \else
     \cdef\currentpagecolumns{#1}%
   \fi
   \edef\p_page{\pagecolumnsparameter\c!page}%
   \ifempty\p_page
     \c_page_col_page\conditionalfalse
   \orelse\ifx\p_page\v!no
     \c_page_col_page\conditionalfalse
   \else
     \c_page_col_page\conditionaltrue
     \page[\p_page]%
   \fi
   \c_page_col_n_of_columns\pagecolumnsparameter\c!n\relax
   \ifnum\c_page_col_n_of_columns>\plusone
     \expandafter\page_col_start_yes
   \else
     \expandafter\page_col_start_nop
   \fi} % public

\aliased\let\stoppagecolumns\relax

\protected\def\page_col_start_yes
  {\d_page_col_distance     {\pagecolumnsparameter\c!distance}%
 % \d_page_col_max_height   {\pagecolumnsparameter\c!maxheight}%
   \d_page_col_max_width    {\pagecolumnsparameter\c!maxwidth}%
 % \d_page_col_balance_step {\pagecolumnsparameter\c!step}%
   \c_page_col_current  \plusone
   %
   \d_page_col_column_width{(\d_page_col_max_width-\d_page_col_distance*\numexpr\c_page_col_n_of_columns-\plusone\relax)/\c_page_col_n_of_columns}%
   %
   \columnwidth    \d_page_col_column_width
   \columndistance \d_page_col_distance
   \nofcolumns     \c_page_col_n_of_columns
   \textwidth      \columnwidth % kind of redundant
   %
   \nopenalties
   %
   \global\initialpageskip\zeroskip
   \global\initialtopskip \zeroskip
   %
   % \insidecolumnstrue % NO!
   %
   \enforced\let\column\page_col_column
   %
   \def\page_floats_get_used_hsize{\makeupwidth} % a bit of a hack
   %
   \usealignparameter  \pagecolumnsparameter
   \useblankparameter  \pagecolumnsparameter
 % \useprofileparameter\pagecolumnsparameter
   %
   \usepagecolumnscolorparameter\c!color
   %
   \setupnotes[\c!width=\textwidth]%
   %
   \usesetupsparameter\pagecolumnsparameter
   %
   % This will become a method but for now it's good enough
   %
   \ifconditional\c_page_col_page\else
     \page_col_pickup_preceding
   \fi
   \setupoutputroutine[\s!pagecolumn]%
   \ifconditional\c_page_col_page\else
     \page_col_flush_preceding
   \fi
   %
   \setupfloats[\c!ntop=\plusthousand]%
 % \setupfloats[\c!nbottom=\plusthousand]%
   %
   \page_col_notes_initialize
   %
   \page_col_command_set_vsize
   \page_col_command_set_hsize
   %
   \enforced\permanent\protected\def\startpagecolumns[##1]{\page_col_start_nop}%
   %
   \enforced\let\stoppagecolumns\page_col_stop_yes}

\protected\def\page_col_start_nop
  {\nofcolumns\c_page_mix_n_of_columns
   \enforced\let\stoppagecolumns\page_col_stop_nop}

\lettonothing\page_col_routine_balance_check

\protected\def\page_col_stop_yes
  {%\column % \page_otr_eject_page
   \page_col_routine_balance_check
   \page    % beware for empty pages
   \endgroup
 % \setupoutputroutine[\s!singlecolumn]%
   \global\initialpageskip\zeroskip
   \global\initialtopskip \zeroskip
   \page_otr_command_set_vsize
   \page_otr_command_set_hsize
   \page
   \page_col_notes_reset
   \endgroup}

\protected\def\page_col_stop_nop
  {\page
   \endgroup
   \endgroup}

% This is only for me, experimental and subject to changes! The problem is that we're already
% wrapped so e.g. when we use vz we are toast.

% \def\page_col_routine_balance_check
%   {\ifcstok{\pagecolumnsparameter\c!balance}\v!yes
%      \let\page_col_routine_balance\page_col_routine_balance_indeed
%    \fi}
%
% \def\page_col_routine_balance_indeed
%   {\ifnum\nofcolumns=\plustwo
%      \setbox\scratchbox\vbox\bgroup
%         \directboxfromcache{\s!pagecolumn}{1}
%         \setbox\scratchbox\lastbox\unvbox\scratchbox
%         \setbox\scratchbox\lastbox\unvbox\scratchbox
%         \directboxfromcache{\s!pagecolumn}{2}
%         \setbox\scratchbox\lastbox\unvbox\scratchbox
%         \setbox\scratchbox\lastbox\unvbox\scratchbox
%      \egroup
%      % holdinginserts
%      \scratchdimen.5\htdp\scratchbox
%      \splittopskip\topskip
%      \localcontrolledendless {%
%        \setbox\scratchboxtwo\copy\scratchbox
%        \setbox\scratchboxone\vsplit\scratchboxtwo to \scratchdimen
%        \ifdim\ht\scratchboxone<\ht\scratchboxtwo
%          \quitloop
%        \orelse\ifvoid\scratchboxtwo
%          \quitloop
%        \orelse\ifdim\scratchdimen>\textheight
%          \quitloop
%        \else
%          \advanceby\scratchdimen\onepoint
%        \fi
%      }%
%      \setbox\scratchboxone\vtop to \scratchdimen{\unvbox\scratchboxone}%
%      \setbox\scratchboxtwo\vtop to \scratchdimen{\unvbox\scratchboxtwo}%
%      \putboxincache{\s!pagecolumn}{1}\scratchboxone
%      \putboxincache{\s!pagecolumn}{2}\scratchboxtwo
%    \fi}

% \def\page_col_routine_balance_indeed
%   {\ifnum\nofcolumns=\plustwo
%      \setbox\scratchbox\vbox\bgroup
%         \directboxfromcache{\s!pagecolumn}{1}
%         \setbox\scratchbox\lastbox\ifvbox\scratchbox\unvbox\scratchbox\fi
%         \setbox\scratchbox\lastbox\ifvbox\scratchbox\unvbox\scratchbox\fi
%         \doifelseboxincache{\s!pagecolumn}{2}
%           {\directboxfromcache{\s!pagecolumn}{2}
%            \setbox\scratchbox\lastbox\ifvbox\scratchbox\unvbox\scratchbox\fi
%            \setbox\scratchbox\lastbox\ifvbox\scratchbox\unvbox\scratchbox\fi
%           }%
%           {}%
%      \egroup
%      % holdinginserts
%      \scratchdimen.5\htdp\scratchbox
%      \splittopskip\topskip
%      \localcontrolledendless {%
%        \setbox\scratchboxtwo\copy\scratchbox
%        \setbox\scratchboxone\vsplit\scratchboxtwo upto \scratchdimen
% % \writestatus{page columns}{  \the\ht\scratchboxone,\the\ht\scratchboxtwo}%
%        \ifdim\ht\scratchboxone<\ht\scratchboxtwo
%          \quitloop
%        \orelse\ifvoid\scratchboxtwo
%          \quitloop
%        \orelse\ifdim\scratchdimen>\textheight
%          \quitloop
%        \else
%          \advanceby\scratchdimen\onepoint
%        \fi
%      }%
% %      \ifdim\ht\scratchboxone<\ht\scratchboxtwo
% %        \scratchdimen\ht\scratchboxone
% %        \advanceby\scratchdimen\onepoint
% %        \localcontrolledendless {%
% %          \setbox\scratchboxtwo\copy\scratchbox
% %          \setbox\scratchboxone\vsplit\scratchboxtwo upto \scratchdimen
% % \writestatus{page columns}{  \the\ht\scratchboxone,\the\ht\scratchboxtwo}%
% %          \ifdim\ht\scratchboxone>\ht\scratchboxtwo
% %            \quitloop
% %          \orelse\ifdim\ht\scratchboxone=\ht\scratchboxtwo
% %            \quitloop
% %          \orelse\ifvoid\scratchboxtwo
% %            \quitloop
% %          \orelse\ifdim\scratchdimen>\textheight
% %            \quitloop
% %          \else
% %            \advanceby\scratchdimen\onepoint
% %          \fi
% %        }%
% %      \fi
%      \setbox\scratchboxone\vtop to \scratchdimen{\unvbox\scratchboxone}%
%      \setbox\scratchboxtwo\vtop to \scratchdimen{\unvbox\scratchboxtwo}%
%      \putboxincache{\s!pagecolumn}{1}\scratchboxone
%      \putboxincache{\s!pagecolumn}{2}\scratchboxtwo
%    \fi}

\protect \endinput
