# -*- mode: Perl -*-
# /=====================================================================\ #
# |  AmSTeX.pool                                                        | #
# | Implementation for LaTeXML                                          | #
# |=====================================================================| #
# | Part of LaTeXML:                                                    | #
# |  Public domain software, produced as part of work done by the       | #
# |  United States Government & not subject to copyright in the US.     | #
# |---------------------------------------------------------------------| #
# | Thanks to the arXMLiv group for initial implementation              | #
# |    http://arxmliv.kwarc.info/                                       | #
# | Released to the Public Domain                                       | #
# |---------------------------------------------------------------------| #
# | Bruce Miller <bruce.miller@nist.gov>                        #_#     | #
# | http://dlmf.nist.gov/LaTeXML/                              (o o)    | #
# \=========================================================ooo==U==ooo=/ #
package LaTeXML::Package::Pool;
use strict;
use warnings;
use LaTeXML::Package;

#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
#  This is the `pool' for AmSTeX (_not_ AMS LaTeX)
# It should be loaded by LoadPool("AmSTeX"), or
# indirectly via \input amstex
# (from TeX mode, ie. before and without LaTeX.pool being loaded)
# This should put LaTeXML into "amstex mode"
#
# Since amstex uses \documentstyle, we _must_ define it here to
# keep TeX.pool from anticipating LaTeX mode and loading LaTeX.pool!
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
RequireResource('ltx-amsart.css');    # hopefully close enough...

DefConstructorI('\AmSTeX', undef, 'AMSTeX');
DefMacro('\fmtname',    'AmS-TeX');
DefMacro('\fmtversion', '2.1');
Let('\plainfmtversion', '\fmtversion');

DefPrimitive('\define SkipSpaces Token UntilBrace {}', sub {
    my ($stomach, $cs, $params, $body) = @_;
    $params = parseDefParameters($cs, $params);    # in TeX.pool
    if (LookupDefinition($cs)) {
      Info('ignore', $cs, $stomach,
        "Ignoring redefinition (\\define) of '" . Stringify($cs) . "'");
      return; }
    DefMacroI($cs, $params, $body);
    return; });

DefPrimitive('\redefine SkipSpaces Token UntilBrace {}', sub {
    my ($stomach, $cs, $params, $body) = @_;
    $params = parseDefParameters($cs, $params);    # in TeX.pool
    DefMacroI($cs, $params, $body);
    return; });

DefPrimitive('\predefine Token Token', sub {
    Let($_[1], $_[2]); });

DefPrimitive('\undefine Token', sub {
    my ($stomach, $cs) = @_;
    Let($_[1], '\relax'); });

#======================================================================
# Style choices

DefConstructor('\documentstyle  Semiverbatim',
  "<?latexml class='#1' amstex='true'?>",
  afterDigest => sub {
    my ($stomach, $whatsit) = @_;
    my $style = ToString($whatsit->getArg(1));
    # Load the package, but note that we're pretending it's a class (to some extent!)
    RequirePackage($style, type => 'sty', notex => 1, as_class => 1)
      || RequirePackage('amsppt');
    return; });

DefMacro('\NoPageNumbers', '');

DefMacro('\BlackBoxes',   '');    # These control whether overfull boxes show black; Ignorable
DefMacro('\NoBlackBoxes', '');

DefMacro('\TagsAsMath', '');
DefMacro('\TagsAsText', '');

DefMacro('\TagsOnLeft',  '');
DefMacro('\TagsOnRight', '');

DefMacro('\CenteredTagsOnSplits',    '');
DefMacro('\TopOrBottomTagsOnSplits', '');

DefMacro('\LimitsOnInts',    '');
DefMacro('\NoLimitsOnInts',  '');
DefMacro('\LimitsOnNames',   '');
DefMacro('\NoLimitsOnNames', '');
DefMacro('\LimitsOnSums',    '');
DefMacro('\NoLimitsOnSums',  '');

# These presumably load fonts (or commands?)
DefMacro('\UseAMSsymbols', '');
DefMacro('\loadbold',      '');
DefMacro('\loadeufb',      '');
DefMacro('\loadeufm',      '');
DefMacro('\loadeurb',      '');
DefMacro('\loadeurm',      '');
DefMacro('\loadeusb',      '');
DefMacro('\loadeusm',      '');
DefMacro('\loadmathfont',  '');
DefMacro('\loadmsam',      '');
DefMacro('\loadmsbm',      '');

DefMacro('\boldnotloaded{}', '');

DefMacro('\galleys',  '');
DefMacro('\flushpar', '\par\noindent');

DefMacro('\pagewidth{Dimension}',   '');
DefMacro('\pageheight{Dimension}',  '');
DefMacro('\hcorrection{Dimension}', '');
DefMacro('\vcorrection{Dimension}', '');

#======================================================================
# The Document
DefConstructor('\document', "<ltx:document>",
  afterDigest => sub { AssignValue(inPreamble => 0); });
DefConstructor('\enddocument', "</ltx:document>",
  beforeDigest => sub {
    $_[0]->getGullet->flush;
    return; });

#======================================================================
# Front Matter

DefMacro('\topmatter',             '');
DefMacro('\endtopmatter',          '');
DefMacro('\title Until:\endtitle', '\@add@frontmatter{ltx:title}{#1}');
DefConstructor('\@personname{}', "<ltx:personname>#1</ltx:personname>",
  bounded => 1, mode => 'text');
DefMacro('\author Until:\endauthor', '\@add@frontmatter{ltx:creator}[role=author]{\@personname{#1}}');
DefConstructor('\@institute{}', "<ltx:contact role='institute'>#1</ltx:contact>", bounded => 1);
DefMacro('\thanks Until:\endthanks',     '\@add@to@frontmatter{ltx:creator}{\@institute{#1}}');
DefMacro('\abstract Until:\endabstract', '\@add@frontmatter{ltx:abstract}{#1}');

#======================================================================
# Document structure
# See amsppt.sty or ...
DefMacro('\nofrills', '');

DefPrimitive('\comment', sub {
    my ($stomach, $line) = @_;
    my $gullet = $stomach->getGullet;
    $gullet->readRawLine;    # IGNORE 1st line (after the \begin{$name} !!!
    while (defined($line = $gullet->readRawLine) && ($line ne '\endcomment')) {
    }
    return; });

Let('\plainproclaim', '\proclaim');
Let('\plainfootnote', '\footnote');
RawTeX('\newbox\tocbox@');
#======================================================================
# Text level stuff

DefMacro('\newline', "\n");

DefPrimitiveI('\textfonti', undef, '',
  font => { family => 'serif', series => 'medium', shape => 'upright' });
DefPrimitiveI('\textfontii', undef, '',
  font => { family => 'serif', series => 'medium', shape => 'upright', size => 9 });

DefConstructor('\spreadlines {Dimension}', '');

DefPrimitive('\pagebreak',      undef);
DefPrimitive('\nopagebreak',    undef);
DefPrimitive('\smallpagebreak', undef);
DefPrimitive('\medpagebreak',   undef);
DefPrimitive('\bigpagebreak',   undef);

DefPrimitive('\allowlinebreak',     undef);
DefPrimitive('\allowmathbreak',     undef);
DefPrimitive('\linebreak',          undef);
DefPrimitive('\nolinebreak',        undef);
DefPrimitive('\mathbreak',          undef);
DefPrimitive('\nomathbreak',        undef);
DefPrimitive('\allowdisplaybreaks', undef);
DefPrimitive('\allowdisplaybreak',  undef);

DefMacro('\tie', '\unskip\nobreak\ ');
Let('\graveaccent', "\\`");
Let('\acuteaccent', "\\'");
Let('\tildeaccent', "\\~");
Let('\hataccent',   "\\^");
Let('\underscore',  "\\_");
Let('\B',           "\\=");
Let('\D',           "\\.");

DefMacro('\.', '. ');

#======================================================================
# Math stuff.

# We'd like to be able to leverage the ams (LaTeX) packages we've already written.
# However, they were written in the context of LaTeX, and assume LaTeX.pool was loaded.
# We either need to duplicate them, or alter them to be aware of LaTeX vs AMSTeX mode!
# Especially, DefEnvironment is to be avoided! (or usurped!!)

# We need stuff from amsmath, BUT it shouldn't define "environments",
# rather \foo ... \endfoo....
# But, of course, DefEnvironment, DOES do that!
# Will this work????
# The question is whether AMSTeX's \foo..\endfoo incorporates \begingroup/\endgroup pairs?
# MOST Likely, all of amsmath will need to be redone here, since the argument patterns are
# so different!  The rest are probably OK.
RequirePackage('amsmath');
RequirePackage('amssymb');
RequirePackage('amsfonts');
RequirePackage('amsopn');
RequirePackage('amsxtra');
RequirePackage('amscd');

Let('\dsize',  '\displaystyle');
Let('\tsize',  '\textstyle');
Let('\ssize',  '\scriptstyle');
Let('\sssize', '\scriptscriptstyle');
Let('\tag',    '\eqno');
DefMath('\and', '\&', role => 'ADDOP', meaning => 'and');
DefConstructor("\\\\",
  "?#isMath(<ltx:XMHint name='newline'/>)(<ltx:break/>)",
  reversion => Tokens(T_CS("\\\\"), T_CR));

# This is an analog to \align's template, but hopefully we can just ignore it???
DefMacro("\\format Until:\\\\", '');

DefConstructor('\text {}',
  "<ltx:text _noautoclose='1'>#1</ltx:text>", mode => 'text');

DefConstructor('\overset Until:\to {}',
  "<ltx:XMApp>"
    . "<ltx:XMWrap role='OVERACCENT'>#1</ltx:XMWrap>"
    . "<ltx:XMArg>#2</ltx:XMArg>"
    . "</ltx:XMApp>");
DefConstructor('\underset Until:\to {}',
  "<ltx:XMApp>"
    . "<ltx:XMWrap role='UNDERACCENT'>#1</ltx:XMWrap>"
    . "<ltx:XMArg>#2</ltx:XMArg>"
    . "</ltx:XMApp>");

DefMacro('\oversetbrace Until:\to {}',  '\overbrace{#2}^{#1}');
DefMacro('\undersetbrace Until:\to {}', '\underbrace{#2}^{#1}');

Let('\overarrow',  '\overrightarrow');
Let('\underarrow', '\underrightarrow');

DefConstructor('\frac InFractionStyle InFractionStyle',
  "<ltx:XMApp>"
    . "<ltx:XMTok meaning='divide' role='FRACOP' mathstyle='#mathstyle'/>"
    . "<ltx:XMArg>#1</ltx:XMArg><ltx:XMArg>#2</ltx:XMArg>"
    . "</ltx:XMApp>",
  sizer => sub { fracSizer($_[0]->getArg(1), $_[0]->getArg(2)); },
  properties => { mathstyle => sub { LookupValue('font')->getMathstyle; } });

DefConstructor('\Cal{}', '#1', bounded => 1, requireMath => 1,
  font => { family => 'caligraphic', series => 'medium', shape => 'upright' });

# \bold in amsfonts
DefConstructor('\roman{}', '#1', bounded => 1, requireMath => 1,
  font => { family => 'serif', series => 'medium', shape => 'upright' });
DefConstructor('\italic{}', '#1', bounded => 1, requireMath => 1,
  font => { shape => 'italic', series => 'medium', shape => 'upright' });
DefConstructor('\slanted{}', '#1', bounded => 1, requireMath => 1,
  font => { shape => 'slanted', series => 'medium', shape => 'upright' });
DefConstructor('\boldkey{}', '#1', bounded => 1, requireMath => 1,
  font => { series => 'bold', family => 'typewriter', series => 'medium', shape => 'upright' });

# holy cow...
DefMacro('\thickfrac', sub {
    ($_[0]->ifNext('\thickness') ? T_CS('\@thickfrac') : T_CS('\frac')); });
DefMacro('\@thickfrac Token Number {}{}', '\genfrac{}{}{#2}{}{#3}{#4}');

DefMacro('\thickfracwithdelims{}{}', sub {
    (($_[0]->ifNext('\thickness') ? T_CS('\@thickfracwithdelims') : T_CS('\fracwithdelims')), $_[1], $_[2]); });
DefMacro('\@thickfracwithdelims {}{} Token Number {}{}', '\genfrac{#1}{#2}{#4}{}{#5}{#6}');

DefMacro('\spcheck',  '^{\vee}');
DefMacro('\sptilde',  '^{\sim}');
DefMacro('\spacute',  "^{'}");
DefMacro('\spgrave',  "^{`}");
DefMacro('\spdot',    "^{.}");
DefMacro('\spddot',   "^{..}");
DefMacro('\spdddot',  "^{...}");
DefMacro('\spddddot', "^{....}");
DefMacro('\spbreve',  "^{\\hbox{\\u{}}}");
DefMacro('\spbar',    "^{-}");
DefMacro('\spvec',    "^{\\rightarrow}");

# \boldsymbol{}
# Note this is really messed up.  \boldsymbol doesn't necessarily just expand,
# it recognizes certain arguments specially.  Among other things this allows perversities like:
#   \redefine\cdot{\boldsymbol\cdot}
DefMathI('\lx@ams@boldsymbol@cdot', undef, "\x{22C5}", role => 'MULOP',
  bounded => 1, font => { forcebold => 1 });
DefMathI('\lx@ams@boldsymbol@prime', undef, "\x{2032}", role => 'SUPOP', locked => 1,
  bounded => 1, font => { forcebold => 1 });
DefMathI('\lx@ams@boldsymbol@lbrack', undef, '[', role => 'OPEN', stretchy => 'false',
  bounded => 1, font => { forcebold => 1 });
DefMathI('\lx@ams@boldsymbol@rbrack', undef, ']', role => 'CLOSE', stretchy => 'false',
  bounded => 1, font => { forcebold => 1 });
DefMathI('\lx@ams@boldsymbol@lbrace', undef, '{', role => 'OPEN', stretchy => 'false', alias => '\{',
  bounded => 1, font => { forcebold => 1 });
DefMathI('\lx@ams@boldsymbol@rbrace', undef, '}', role => 'CLOSE', stretchy => 'false', alias => '\}',
  bounded => 1, font => { forcebold => 1 });
DefMathI('\lx@ams@boldsymbol@surd', undef, "\x{221A}", role => 'OPERATOR', meaning => 'square-root',
  bounded => 1, font => { forcebold => 1 });
DefMathI('\lx@ams@boldsymbol@S', undef, UTF(0xa7),
  bounded => 1, font => { forcebold => 1 });
DefMathI('\lx@ams@boldsymbol@P', undef, UTF(0xB6),
  bounded => 1, font => { forcebold => 1 });
DefMathI('\lx@ams@boldsymbol@dag', undef, "\x{2020}",
  bounded => 1, font => { forcebold => 1 });
DefMathI('\lx@ams@boldsymbol@ddag', undef, "\x{2021}",
  bounded => 1, font => { forcebold => 1 });

DefConstructor('\lx@ams@boldsymbol@{}', '#1',
  bounded => 1, requireMath => 1, font => { forcebold => 1 });

DefMacro('\boldsymbol DefToken', sub {
    my ($gullet, $token) = @_;
    my $name = ToString($token); $name =~ s/^\\//;
    my $btoken = T_CS('\lx@ams@boldsymbol@' . $name);
    return (IsDefined($btoken) ? ($btoken) : (T_CS('\lx@ams@boldsymbol@'), $token)); });

# Ignore these?
DefRegister('\buffer' => Dimension(0));
DefMacro('\ChangeBuffer Dimension', '\buffer#2\relax');
DefMacro('\ResetBuffer',            '');
DefMacro('\shave{}',                '#1');
DefMacro('\botshave{}',             '#1');
DefMacro('\topshave{}',             '#1');

DefMacro('\minCDarrowwidth Dimension',  '');
DefMacro('\pretend Until:\haswidth {}', '#1');

DefMacro('\snug', '');
DefConstructor('\topsmash{}', "#1");
DefConstructor('\botsmash{}', "#1");

DefConstructor('\spreadmatrixlines Dimension', '');

DefMacro('\MultlineGap Dimension', '');
DefMacro('\multlinegap Dimension', '');
DefMacro('\nomultlinegap',         '');

DefMacro('\innerhdotsfor Number Match:\after {}', sub {
    (map { '\hdots' } 1 .. $_[1]->valueOf); });
DefMacro('\spacehdots Number Match:\for Number', sub {
    (map { '\hdots' } 1 .. $_[1]->valueOf); });
DefMacro('\spaceinnerhdots Number Match:\for Number Match:\after {}', sub {
    (map { '\hdots' } 1 .. $_[1]->valueOf); });

DefMacro('\foldedtext', sub {
    my ($gullet) = @_;
    if ($gullet->ifNext('\foldedwidth')) {
      $gullet->readToken; $gullet->readDimension; }    # ignore?
    T_CS('\text'); });

Let('\topfoldedtext', '\foldedtext');
Let('\botfoldedtext', '\foldedtext');

# Maybe?
DefMacro('\Sb Until:\endSb', '_{\substack{#1}}');
DefMacro('\Sp Until:\endSp', '^{\substack{#1}}');
Let('\endSb', '\relax');
Let('\endSp', '\relax');

DefMacro('\thetag', sub { T_OTHER(LookupValue('EQUATIONROW_NUMBER')); });    # ?

DefMacro('\topaligned', '\aligned[t]');
Let('\endtopaligned', '\endaligned');
DefMacro('\botaligned', '\aligned[b]');
Let('\endbotaligned', '\endaligned');

# close enough?
DefMacro('\accentedsymbol{}{}', '\def#1{#2}');

# Tricky:
#  \cfrac, \lcfrac, \endcfrac
DefConstructor('\cfrac', '',
  afterDigest => sub {
    my ($stomach) = @_;
    $stomach->bgroup;
    Let(T_CS("\\\\"), T_CS('\lx@cfrac')); });
DefConstructor('\endcfrac', '',
  afterDigest => sub {
    my ($stomach) = @_;
    $stomach->egroup; });

# These really need a way to pass denomalign=left|right to the MathML!
Let('\lcfrac', '\cfrac');
Let('\rcfrac', '\cfrac');

DefMacro('\lx@cfrac',
  '\lx@generalized@over{\\\\}{meaning=continued-fraction,role=MULOP}\displaystyle');

#======================================================================
# Bibliography
# See amsppt.sty

#======================================================================
# Dubious

DefMacro('\printoptions',    '');
DefMacro('\showallocations', '');
DefMacro('\syntax',          '');
1;
