% Babelbidi: Bidi extensions for Babel.
%
% Copyright (C) 2026 Amer Amikhteh
%
% This file is part of the Babelbidi package.
%
% This work is free software: you may redistribute it and/or modify
% it under the terms of the LaTeX Project Public License as published
% by the LaTeX Project, either version 1.3c of the License, or
% (at your option) any later version.
%
% This work is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
%
% The full license text is available at:
% https://www.latex-project.org/lppl/
%
% This work is "maintained" by Amer Amikhteh.
%
% The current maintainer of this work is Amer Amikhteh.

\ProvidesFile{babelbidi-api-layout.def}[2026/11/08 v0.1.0 Additional Bidi API for Babelbidi]

\makeatletter

% XeTeX uses bidi's original interfaces, including its footnote machinery.
\ifXeTeX
    \makeatother
    \expandafter\endinput
\fi


% ------------------------------------------
% Footnote direction policy
% ------------------------------------------

% Keep Babel's default until the user explicitly selects a direction.
% Assignments are local, as are bidi's footnote direction switches.
\def\bbd@fn@policy{-1}
\def\bbd@fn@explicit{-1}

\ProvideDocumentCommand{\setfootnoteRL}{}{\def\bbd@fn@policy{1}}
\ProvideDocumentCommand{\setfootnoteLR}{}{\def\bbd@fn@policy{0}}
\DeclareCommandCopy{\unsetfootnoteRL}{\setfootnoteLR}
\DeclareCommandCopy{\unsetfootnoteLR}{\setfootnoteRL}



% The existing directed footnotes take precedence over the policy.
\let\bbd@bidi@footnote\bbd@footnote
\long\def\bbd@footnote#1#2#3{%
    \begingroup
    \def\bbd@fn@explicit{#1}%
    \bbd@bidi@footnote{#1}{#2}{#3}%
    \endgroup
}

% Resolve the formatter at insertion time: titles and minipages may replace it.
\long\def\bbd@fn@insert#1#2{%
    \begingroup
    \ifnum\bbd@fn@explicit<\z@
        \let\bbd@fn@selected\bbd@fn@policy
    \else
        \let\bbd@fn@selected\bbd@fn@explicit
    \fi
    \ifPDFTeX
        \bbd@pdf@remember@fn@dir{\bbd@fn@selected}%
    \fi
    \let\bbd@bidi@makefntext\@makefntext
    % Also synchronize the existing LuaTeX footnote formatter.
    \def\bbd@fn@dir{\bbd@footnote@dir{\bbd@fn@selected}}%
    \long\def\@makefntext##1{%
        \bbd@fn@dir
        \bbd@bidi@makefntext{{\bbd@fn@dir##1}}%
    }%
    #1{#2}%
    \endgroup
}

% Leave unconfigured footnotes unread, including verbatim-aware scanners.
\def\bbd@fn@dispatch#1{%
    \ifnum\bbd@fn@explicit<\z@
        \ifnum\bbd@fn@policy<\z@
            \let\bbd@fn@next#1%
        \else
            \def\bbd@fn@next{\bbd@fn@insert#1}%
        \fi
    \else
        \def\bbd@fn@next{\bbd@fn@insert#1}%
    \fi
    \bbd@fn@next
}

% Babel wraps ordinary footnotes in their source language. Apply the policy
% inside that wrapper, so language selection cannot reset the text direction.
\long\def\bbd@fn@language#1#2{%
    #1{\bbd@footnote@dir{\bbd@fn@policy}#2}%
}

% Install after BabelBidi's engine patches and preamble package patches.
\AddToHook{begindocument/before}[babelbidi/bidi-api]{%
    \ifLuaTeX
        \let\bbd@bidi@babel@footnote\bbl@footnote
        \def\bbl@footnote#1#2#3{%
            \ifnum\bbd@fn@policy<\z@
                \def\bbd@fn@next{\bbd@bidi@babel@footnote{#1}{#2}{#3}}%
            \else
                \def\bbd@fn@next{\bbd@bidi@babel@footnote{\bbd@fn@language{#1}}{#2}{#3}}%
            \fi
            \bbd@fn@next
        }%
    \fi
    \let\bbd@bidi@footnotetext\@footnotetext
    \def\@footnotetext{\bbd@fn@dispatch\bbd@bidi@footnotetext}%
    \let\bbd@bidi@mpfootnotetext\@mpfootnotetext
    \def\@mpfootnotetext{\bbd@fn@dispatch\bbd@bidi@mpfootnotetext}%
}


\DeclareHookRule{begindocument/before}{babelbidi/bidi-api}{after}{babelbidi}


% ------------------------------------------
% Directed footnote text and title thanks
% ------------------------------------------

\long\def\bbd@footnotetext#1#2#3{%
    \begingroup
    \def\bbd@fn@explicit{#1}%
    \IfNoValueTF{#2}%
    {\footnotetext{{\bbd@footnote@dir{#1}#3}}}%
    {\footnotetext[#2]{{\bbd@footnote@dir{#1}#3}}}%
    \endgroup
}

\ProvideDocumentCommand{\LTRfootnotetext}{o +m}{%
    \bbd@footnotetext{0}{#1}{#2}%
}

\ProvideDocumentCommand{\RTLfootnotetext}{o +m}{%
    \bbd@footnotetext{1}{#1}{#2}%
}

\ProvideDocumentCommand{\LTRthanks}{m}{%
    \footnotemark
    \protected@xdef\@thanks{\@thanks
        \protect\LTRfootnotetext[\the\c@footnote]{#1}}%
}

\ProvideDocumentCommand{\RTLthanks}{m}{%
    \footnotemark
    \protected@xdef\@thanks{\@thanks
        \protect\RTLfootnotetext[\the\c@footnote]{#1}}%
}


% ------------------------------------------
% Footnote rule alias
% ------------------------------------------

\DeclareCommandCopy{\LRfootnoterule}{\leftfootnoterule}
\DeclareCommandCopy{\RLfootnoterule}{\rightfootnoterule}



% ------------------------------------------
% Direction-sensitive overlaps
% ------------------------------------------

\ProvideDocumentCommand{\bidillap}{m}{%
    \if@RTL
        \hboxL to \z@{\RLE{#1}\hss}%
    \else
        \hboxL to \z@{\hss#1}%
    \fi
}

\ProvideDocumentCommand{\bidirlap}{m}{%
    \if@RTL
        \hboxL to \z@{\hss\RLE{#1}}%
    \else
        \hboxL to \z@{#1\hss}%
    \fi
}


% ------------------------------------------
% Directional list items
% ------------------------------------------

\def\bbd@items@shape{%
    \ifLuaTeX
        % Babel sets shapemode on a direction mismatch but does not reset it.
        \shapemode\z@
        \@ifundefined{bbl@listparshape}%
        {\parshape\@ne\@totalleftmargin\linewidth}%
        {\bbl@listparshape\@ne\@totalleftmargin\linewidth}%
    \else
        \ifnum\bbl@thetextdir>\z@
            \parshape\@ne
            \dimexpr\hsize-\@totalleftmargin-\linewidth\relax\linewidth
        \else
            \parshape\@ne\@totalleftmargin\linewidth
        \fi
    \fi
}

% Nested lists must recompute their shape in the selected direction too.
\long\def\bbd@items@list#1#2{%
    \bbd@items@original@list{#1}{#2}%
    \bbd@items@shape
    \ignorespaces
}

\def\bbd@items#1{%
    \par
    \bbd@setdir{#1}%
    \bbd@items@shape
    \ifx\list\bbd@items@list\else
        \let\bbd@items@original@list\list
        \let\list\bbd@items@list
    \fi
    \ignorespaces
}

\ProvideDocumentEnvironment{LTRitems}{}
{\bbd@items{0}}
{\par}

\ProvideDocumentEnvironment{RTLitems}{}
{\bbd@items{1}}
{\par}

% bidi gives bibliography groups the same layout as ordinary item groups.
\DeclareCommandCopy{\LTRbibitems}{\LTRitems}
\DeclareCommandCopy{\endLTRbibitems}{\endLTRitems}
\DeclareCommandCopy{\RTLbibitems}{\RTLitems}
\DeclareCommandCopy{\endRTLbibitems}{\endRTLitems}


% ------------------------------------------
% Bibliography item direction, independent of the heading
% ------------------------------------------

\def\bbd@bib@dir{-1}

\ProvideDocumentCommand{\setLTRbibitems}{}{\def\bbd@bib@dir{0}}
\ProvideDocumentCommand{\setRTLbibitems}{}{\def\bbd@bib@dir{1}}
\ProvideDocumentCommand{\setdefaultbibitems}{}{\def\bbd@bib@dir{-1}}

% Delay the switch until the bibliography opens its list: the heading and
% running marks retain the surrounding direction. Restore \list immediately.
\AddToHook{env/thebibliography/begin}{%
    \ifPDFTeX
        % Keep brackets and multi-digit labels intact in TeXXeT paragraphs.
        \let\bbd@bib@label\@biblabel
        \def\@biblabel#1{\hboxL{\bbd@bib@label{#1}}}%
    \fi
    \ifnum\bbd@bib@dir<\z@\else
        \let\bbd@bib@list\list
        \long\def\list#1#2{%
            \let\list\bbd@bib@list
            \bbd@setdir{\bbd@bib@dir}%
            \list{#1}{#2}%
            \bbd@items@shape
            \ignorespaces
        }%
    \fi
}


% ------------------------------------------
% Cases with a right-hand brace
% ------------------------------------------

% Like bidi, cells use text mode; mathematics is entered explicitly with $.
\ProvideDocumentEnvironment{RTLcases}{+b}
{%
    \leavevmode
    \hboxL{%
        $\left.\hboxR{%
                \def\arraystretch{1.2}%
                % Physical left alignment becomes right alignment in this box.
                % Disable our LuaTeX table swap locally, so both engines agree.
                \let\bbd@swap@lr@chnum\relax
                \begin{tabular}{@{}l@{\quad}l@{}}%
                    #1%
                \end{tabular}%
            }\right\rbrace$%
    }%
}
{}


% ------------------------------------------
% Separator in compound counter representations
% ------------------------------------------

\def\@SepMark{.}
\ProvideDocumentCommand{\SepMark}{m}{\gdef\@SepMark{#1}}
\def\@thmcountersep{\@SepMark}

% Replace only a separator following the named parent counter. Keep the
% rest of the formatter, including Babel's localized digits, unchanged.
\def\bbd@sep@counter#1#2{%
    \@ifundefined{the#1}{}{%
        \expandafter\bbd@sep@counter@i\csname the#2\endcsname{#1}%
    }%
}

\def\bbd@sep@counter@i#1#2{%
    \expandafter\bbl@sreplace\csname the#2\endcsname
    {#1.}{#1\@SepMark}%
}

\def\bbd@sep@counters{%
    \bbd@sep@counter{section}{chapter}%
    \bbd@sep@counter{subsection}{section}%
    \bbd@sep@counter{subsubsection}{subsection}%
    \bbd@sep@counter{paragraph}{subsubsection}%
    \bbd@sep@counter{subparagraph}{paragraph}%
    \bbd@sep@counter{equation}{chapter}%
    \bbd@sep@counter{figure}{chapter}%
    \bbd@sep@counter{table}{chapter}%
}

% Support preamble use too, then incorporate later package/class changes.
\bbd@sep@counters
\AddToHook{begindocument/before}{\bbd@sep@counters}

% amsmath's \numberwithin creates a new formatter at the point of use.
\AddToHook{package/amsmath/after}{%
    \DeclareCommandCopy{\bbd@numberwithin}{\numberwithin}%
    \RenewDocumentCommand{\numberwithin}{s O{\arabic} m m}{%
        \IfBooleanTF{#1}%
        {\bbd@numberwithin*[#2]{#3}{#4}}%
        {%
            \bbd@numberwithin[#2]{#3}{#4}%
            \bbd@sep@counter{#3}{#4}%
        }%
    }%
}

\AddToHook{package/amsthm/after}{%
    \def\@thmcountersep{\@SepMark}%
}


% ------------------------------------------
% Margin note direction and placement
% ------------------------------------------

\def\bbd@margin@policy{-1}

\ProvideDocumentCommand{\setRTLmarginpar}{}{\def\bbd@margin@policy{1}}
\ProvideDocumentCommand{\setLTRmarginpar}{}{\def\bbd@margin@policy{0}}
\ProvideDocumentCommand{\setdefaultmarginpar}{}{\def\bbd@margin@policy{-1}}

\def\bbd@margin@direction{%
    \ifnum\bbd@margin@policy<\z@
        \the\bbl@thetextdir
    \else
        \bbd@margin@policy
    \fi
}

\def\bbd@margin@setdir{%
    \edef\bbd@margin@dir{\bbd@margin@direction}%
    \bbd@setdir{\bbd@margin@dir}%
}

% Explicit commands change the note's text direction, not its placement.
% Resolve \marginpar at use time and retain its optional left-hand text.
\long\def\bbd@marginpar#1#2#3{%
    \IfNoValueTF{#2}%
    {\marginpar{{\bbd@setdir{#1}#3\par}}}%
    {\marginpar[{\bbd@setdir{#1}#2\par}]%
        {{\bbd@setdir{#1}#3\par}}}%
}

\ProvideDocumentCommand{\LTRmarginpar}{o +m}{%
    \bbd@marginpar{0}{#1}{#2}%
}

\ProvideDocumentCommand{\RTLmarginpar}{o +m}{%
    \bbd@marginpar{1}{#1}{#2}%
}

% Mirror only the final placement box. LaTeX still selects the optional text
% and handles page parity, reverse margins, columns and vertical collisions.
\long\def\bbd@margin@place#1{%
    \ifnum\bbd@margin@direction>\z@
        \hboxR to \columnwidth{#1}%
    \else
        \hboxL to \columnwidth{#1}%
    \fi
}

\AddToHook{begindocument/before}{%
    \ifPDFTeX
        \let\bbd@margin@reset\@marginparreset
        \def\@marginparreset{%
            \bbd@margin@reset
            % A note may be placed in a box with the opposite direction.
            % Give LTR paragraphs an explicit TeXXeT run as well as RTL ones.
            \def\bbl@xeeverypar{%
                \ifnum\bbl@thepardir=\z@
                    \beginL
                \else
                    {\setbox\z@\lastbox\beginR\box\z@}%
                \fi
            }%
        }%
    \fi
    \let\bbd@margin@ympar\@ympar
    \long\def\@ympar#1{%
        % As in bidi, the policy applies to ordinary notes without optional
        % text; the optional form retains the surrounding text direction.
        \bbd@margin@ympar{{\bbd@margin@setdir#1\par}}%
    }%
    \bbl@sreplace\@addmarginpar
    {\hb@xt@\columnwidth}{\bbd@margin@place}%
}


% ------------------------------------------
% Two-column order, independent of the text direction
% ------------------------------------------

\def\bbd@dblcol@dir{-1}

\ProvideDocumentCommand{\RTLdblcol}{}{\def\bbd@dblcol@dir{1}}
\ProvideDocumentCommand{\LTRdblcol}{}{\def\bbd@dblcol@dir{0}}

\def\bbd@dblcol@direction{%
    \ifnum\bbd@dblcol@dir<\z@
        \bbd@main@dir
    \else
        \bbd@dblcol@dir
    \fi
}

% Change only the box joining the two completed columns. Keep the output
% routine's float handling, marks and column contents intact.
\long\def\bbd@dblcol@box#1{%
    \hboxL to \textwidth{%
        \ifnum\bbd@dblcol@direction>\z@
            % Swap the register names locally, not the contents of the boxes.
            % A directional outer box would also reverse pdfTeX's text.
            \let\bbd@dblcol@first\@leftcolumn
            \let\@leftcolumn\@outputbox
            \let\@outputbox\bbd@dblcol@first
        \fi
        #1%
    }%
}

\AddToHook{begindocument/before}{%
    \bbl@sreplace\@outputdblcol
    {\hb@xt@\textwidth}{\bbd@dblcol@box}%
    % Babel's columns layout may already have replaced the same box.
    \bbl@sreplace\@outputdblcol
    {\bbl@outputhbox}{\bbd@dblcol@box}%
}


% ------------------------------------------
% Continued footnote rules and direction diagnostics
% ------------------------------------------

\def\bbd@split@rule{%
    \ifx\@listdepth\@mplistdepth
        \bbd@split@mp
    \else
        \ifnum\bbd@split@previous=\z@
            \bbd@split@page
        \else
            \kern-3\p@\hrule\kern2.6\p@
        \fi
        \xdef\bbd@split@previous{\the\insertpenalties}%
    \fi
}

\ProvideDocumentCommand{\SplitFootnoteRule}{}{%
    \ifx\footnoterule\bbd@split@rule\else
        \gdef\bbd@split@previous{0}%
        \DeclareCommandCopy{\bbd@split@page}{\footnoterule}%
        \DeclareCommandCopy{\bbd@split@mp}{\footnoterule}%
        \DeclareCommandCopy{\footnoterule}{\bbd@split@rule}%
    \fi
}

\newif\ifbbd@fn@debug
\ProvideDocumentCommand{\debugfootnotedirection}{}{\bbd@fn@debugtrue}

% Like bidi, diagnostics are emitted when the automatic rule is evaluated.
\DeclareCommandCopy{\bbd@fn@auto@original}{\bbd@fn@rule@auto}
\def\bbd@fn@rule@auto{%
    \bbd@fn@auto@original
    \ifbbd@fn@debug
        \begingroup
        \ifLuaTeX
            \count@\bbd@fn@rule@dir
        \else
            \count@\bbd@pdf@fn@dir
        \fi
        \typeout{[footdir] \number\c@page: \ifnum\count@<\z@ else\else
                \ifnum\count@=\z@ left\else right\fi\fi}%
        \endgroup
    \fi
}

\makeatother

\endinput
