# -*- mode: Perl -*-
# /=====================================================================\ #
# |  OmniBus.cls                                                        | #
# | 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 Catalin David <c.david@jacobs-university.de>              | #
# | of 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 OmniBus class file.
# It is a stand-in for class files for which we have no binding.
# It attempts to define in fairly generic fashion most of the frontmatter
# commands that are commonly encountered.
# Of course having the "wrong" things defined
# or the right things defined wrongly may lead to other errors.
# But we're betting that we come out ahead.
#======================================================================

LoadClass('article');
ProcessOptions();

# Various common things often defined or included by unique classes
# \institute,, \inst  from inst_support
RequirePackage('inst_support');
RequirePackage('epsf');
# One of the graphics|graphicx packages are often included, leading to undefined \includegraphics
# However, they have different parameter patterns! But, graphicx seems to be included
# by random cls files by over 10 to 1, so we'll just load graphicx and hope for the best.
# The alternative would be to write a version that sniffed the arguments...
RequirePackage('graphicx');
RequirePackage('aas_macros');

# natbib is also often used, but reportedly clashes with cite.sty
# We'll autoload natbib if it hasn't already been loaded, and if any of its obvious macros are used.
foreach my $trigger (qw(citet citep citealt citealp citenum citeauthor citefullauthor
  citeyear citeyearpar citeauthoryear setcitestyle bibpunct)) {
  DefAutoload($trigger, 'natbib.sty.ltxml'); }
Let('\lx@OmniBus@saved@bibitem', '\bibitem');
# Another hacky autoload: Recognize \bibitem[\protect\citeauthoryear...
# when it would otherwise be too late to fix.
DefPrimitive('\lx@late@usepackage Semiverbatim', sub { RequirePackage(ToString($_[1])); });
DefMacro('\bibitem',
'\@ifnext@n{[\protect\citeauthoryear}{\lx@late@usepackage{natbib}\bibitem}{\lx@OmniBus@saved@bibitem}');
DefEnvironment('{frontmatter}', '#body');
DefEnvironment('{mainmatter}',  '#body');
DefEnvironment('{backmatter}',  '#body');

DefMacro('\shorttitle{}', '\@add@frontmatter{ltx:toctitle}{#1}');
DefMacro('\subtitle{}',   '\@add@frontmatter{ltx:subtitle}{#1}');

DefMacro('\shortauthor{}', '');
DefRegister('\titlerunning',  Tokens());
DefRegister('\authorrunning', Tokens());
Let('\runningauthor', '\authorrunning');
Let('\runauthor',     '\authorrunning');

DefMacro('\runningtitle{}', Tokens());
Let('\runninghead', '\runningtitle');
DefMacro('\shortauthor{}',  Tokens());
DefMacro('\authors{}',      Tokens());
DefMacro('\shortauthors{}', Tokens());
DefMacro('\alignauthor',    Tokens());

DefConstructor('\@@@email{}{}', "^ <ltx:contact role='#2'>#1</ltx:contact>");
DefMacro('\email{}', '\@add@to@frontmatter{ltx:creator}{\@@@email{#1}{email}}');
Let('\emailaddr', '\email');
DefMacro('\ead{}[]',   '\@add@to@frontmatter{ltx:creator}{\@@@email{#1}{#2}}');
DefMacro('\emailname', 'E-mail');
DefMacro('\speaker{}', '\@add@frontmatter{ltx:creator}[role=speaker]{\@personname{#1}}');

# like from aas
DefConstructor('\@@@affiliation{}', "^ <ltx:contact role='affiliation'>#1</ltx:contact>");
DefMacro('\affil{}', '\@add@to@frontmatter{ltx:creator}{\@@@affiliation{#1}}');
DefMacro('\altaffilmark{}', sub {
    my ($gullet, $marks) = @_;
    map { (T_CS('\@altaffilmark'), T_BEGIN, @$_, T_END) } SplitTokens($marks, T_OTHER(',')); });
DefConstructor('\@altaffilmark{}',
  "?#1(<ltx:note role='affiliationmark' mark='#1'/> )()");
Let('\affilnum', '\@altaffilmark');

DefConstructor('\altaffiltext{}{}',
  "?#2(<ltx:note role='affiliationtext' mark='#1'>#2</ltx:note>)()");

DefConstructor('\@@@address{}', "^ <ltx:contact role='address'>#1</ltx:contact>");
DefMacro('\address[]{}', '\@add@to@frontmatter{ltx:creator}{\@@@address{#2}}');
Let('\affaddr', '\address');
DefMacro('\affiliation{}', '\@add@to@frontmatter{ltx:creator}{\@@@affiliation{#1}}');
DefRegister('\affilskip' => Dimension(0));

# some rarer name macros that are functionally no-ops for latexml
DefMacro('\prefix{}',          '#1');
DefMacro('\suffix{}',          '#1');
DefMacro('\fnms{}',            '#1');
DefMacro('\snm{}',             '#1');
DefMacro('\inits{}',           '#1');
DefMacro('\printaddresses{}',  '#1');
DefMacro('\printead{}',        Tokens());
DefMacro('\firstpage{}',       Tokens());
DefMacro('\lastpage{}',        Tokens());
DefMacro('\runauthor{}',       Tokens());
DefMacro('\runtitle{}',        Tokens());
DefMacro('\corref{}',          Tokens());
DefMacro('\listofauthors{}',   Tokens());
DefMacro('\indexauthor{}',     Tokens());
DefMacro('\preface',           Tokens());
DefMacro('\thankstext',        Tokens());
DefMacro('\numberofauthors{}', Tokens());
DefMacro('\resumen{}',         '\@add@frontmatter{ltx:abstract}{#1}');
DefMacro('\ion{}{}',           '{#1 \textsc{#2}}');
Let(T_CS('\fulladdresses'), T_CS('\address'));
Let(T_CS('\smonth'),        T_CS('\month'));
Let(T_CS('\syear'),         T_CS('\year'));

# Comes as both macro with arg, and environment! w/ or w/o "s"!
DefMacro('\keywords{}', '\@add@frontmatter{ltx:keywords}{#1}');
DefMacro('\kword{}',    '\@add@frontmatter{ltx:keywords}{#1}');
DefMacro('\kwd[]{}',    '\@add@frontmatter{ltx:keywords}{#2, }');

# {keyword}, {keywords}
sub after_digest_keywords {
  my $frontmatter = LookupValue('frontmatter');
  push(@{ $$frontmatter{'ltx:classification'} },
    ['ltx:classification', { scheme => 'keywords' }, @LaTeXML::LIST]);
  return; }
DefEnvironment('{keyword}',  '', afterDigest => \&after_digest_keywords);
DefEnvironment('{keywords}', '', afterDigest => \&after_digest_keywords);
# Extend to be callable as \keywords{} or \begin{keywords}...
# Probably want to use this trick more often?
Let('\lx@begin@keywords', '\keywords');

sub auto_keywords {
  my ($gullet) = @_;
  return ($gullet->ifNext(T_BEGIN)
    ? (T_CS('\keywords@onearg'))
    : (T_CS('\g@addto@macro'), T_CS('\@startsection@hook'), T_CS('\maybe@end@keywords'),
      T_CS('\lx@begin@keywords'))); }
# see arxiv:math/0601658 for a singular {keyword} example
DefMacro('\keyword',  \&auto_keywords);
DefMacro('\keywords', \&auto_keywords);
DefMacro('\keywords@onearg{}', '\begin{keywords}#1\end{keywords}\let\endkeyword\relax\let\endkeywords\relax');
DefMacroI('\maybe@end@keywords', undef, '\endkeywords\let\maybe@end@keywords\relax');
Let(T_CS('\addto@keywords@list'), T_CS('\keyword'));

DefMacro('\classification{}', '\@add@frontmatter{ltx:classification}{#1}');
DefMacro('\pacs{}', '\@add@frontmatter{ltx:classification}[scheme=pacs]{#1}', locked => 1);
# \doi{doi} might be frontmatter, or just a \url-like thing.  So, let's guess!
DefMacro('\doi{}',
  '\if@in@preamble{\@add@frontmatter{ltx:classification}[scheme=doi]{#1}'
    . '\else\lx@doi{#1}\fi');
DefConstructor('\lx@doi{}', '<ltx:ref href="https:/doi.org/#1">#1</ltx:ref>');

# from acm_proc_article, is it general enough?
DefMacro('\category{}{}{}[]', '\@add@frontmatter{ltx:classification}[scheme=category]{#1 #2 #3}\keywords{#4}');

our $omni_theorem_main = <<'EOL';
\newtheorem{theorem}{Theorem}[section]
\newtheorem{conjecture}[theorem]{Conjecture}
\newtheorem{proposition}[theorem]{Proposition}
\newtheorem{proof}[theorem]{Proof}
\newtheorem{lemma}[theorem]{Lemma}
\newtheorem{corollary}[theorem]{Corollary}
\newtheorem{example}[theorem]{Example}
\newtheorem{exercise}[theorem]{Exercise}
\newtheorem{definition}[theorem]{Definition}
\newtheorem{problem}[theorem]{Problem}
\newtheorem{question}[theorem]{Question}
\newtheorem{remark}[theorem]{Remark}
\newtheorem{solution}[theorem]{Solution}
\newtheorem{step}[theorem]{Step}
\newtheorem{note}[theorem]{Note}
EOL
# Additional theorem aliases (e.g. autart.cls)
our $omni_theorem_aux = <<'EOL';
\newtheorem{thm}{Theorem}
\newtheorem{cor}[thm]{Corollary}
\newtheorem{lem}[thm]{Lemma}
\newtheorem{claim}[thm]{Claim}
\newtheorem{axiom}[thm]{Axiom}
\newtheorem{conj}[thm]{Conjecture}
\newtheorem{fact}[thm]{Fact}
\newtheorem{hypo}[thm]{Hypothesis}
\newtheorem{assum}[thm]{Assumption}
\newtheorem{prop}[thm]{Proposition}
\newtheorem{crit}[thm]{Criterion}
\theoremstyle{definition}
\newtheorem{defn}[thm]{Definition}
\newtheorem{exmp}[thm]{Example}
\newtheorem{rem}[thm]{Remark}
\newtheorem{prob}[thm]{Problem}
\newtheorem{prin}[thm]{Principle}
\newtheorem{alg}{Algorithm}
EOL

for my $env (qw(
  conjecture theorem corollary definition example exercise lemma
  note problem proof proposition question remark solution
  thm cor lem claim axiom conj fact hypo assum prop crit defn exmp rem prob prin alg)) {
  my $beginenv = "\\begin{$env}";
  DefMacroI(T_CS($beginenv), undef, sub {
      RequirePackage('amsthm');
      return Tokenize($omni_theorem_main . $omni_theorem_aux . $beginenv)->unlist; }); }
for my $new_theorem_alias (qw(\newproclaim \newdef \newremark)) {
  DefMacroI(T_CS($new_theorem_alias), undef, sub {
      RequirePackage('amsthm');
      return T_CS('\newtheorem'); }); }
DefAutoload('theoremstyle', 'amsthm.sty.ltxml');

Let('\abstracts', '\abstract');
Let('\abst',      '\abstract');

# Seems to come in different spellings and often misused!
DefConstructor('\acknowledgments', "<ltx:acknowledgements name='#name'>",
  properties => sub { (name => Digest(T_CS('\acknowledgmentsname'))); });
DefConstructor('\endacknowledgments', "</ltx:acknowledgements>");
Tag("ltx:acknowledgements", autoClose => 1);

DefMacro('\acknowledgmentsname', 'Acknowledgements');
Let('\acknowledgements',      '\acknowledgments');
Let('\endacknowledgements',   '\endacknowledgments');
Let('\theacknowledgments',    '\acknowledgments');
Let('\endtheacknowledgments', '\endacknowledgments');

DefMacro('\editors{}',          '\@add@frontmatter{ltx:note}[role=editors]{#1}');
DefMacro('\received{}',         '\@add@frontmatter{ltx:date}[role=received]{#1}');
DefMacro('\revised{}',          '\@add@frontmatter{ltx:date}[role=revised]{#1}');
DefMacro('\accepted{}',         '\@add@frontmatter{ltx:date}[role=accepted]{#1}');
DefMacro('\pubyear{}',          '\@add@frontmatter{ltx:date}[role=publication]{#1}');
DefMacro('\copyrightyear{}',    '\@add@frontmatter{ltx:date}[role=copyright]{#1}');
DefMacro('\preprint{}',         '\@add@frontmatter{ltx:note}[role=preprint]{#1}');
DefMacro('\communicated{}',     '\@add@frontmatter{ltx:date}[role=communicated]{#1}');
DefMacro('\dedicated{}',        '\@add@frontmatter{ltx:note}[role=dedicated]{#1}');
DefMacro('\presented{}',        '\@add@frontmatter{ltx:date}[role=presented]{#1}');
DefMacro('\articletype{}',      '\@add@frontmatter{ltx:note}[role=articletype]{#1}');
DefMacro('\issue{}',            '\@add@frontmatter{ltx:note}[role=issue]{#1}');
DefMacro('\journal{}',          '\@add@frontmatter{ltx:note}[role=journal]{#1}');
DefMacro('\jname{}',            '\@add@frontmatter{ltx:note}[role=journal]{#1}');
DefMacro('\volume{}',           '\@add@frontmatter{ltx:note}[role=volume]{#1}');
DefMacro('\titlenote{}',        '\@add@frontmatter{ltx:note}[role=titlenote]{#1}');
DefMacro('\terms{}',            '\@add@frontmatter{ltx:note}[role=terms]{#1}');
DefMacro('\conferenceinfo{}{}', '\@add@frontmatter{ltx:note}[role=conference]{#1 #2}');

# what useful behavior can we add here? e.g. see arxiv:math/0601658
DefMacro('\thanksref{}', Tokens());

# rarer variants:
Let('\CopyrightYear', '\copyrightyear');
DefRegister('\confinfo',     Tokens());
DefRegister('\acmcopyr',     Tokens());
DefRegister('\copyrightetc', Tokens());
Let('\crdata', '\acmcopyr');

# work as environment or not...
DefConstructor('\references',
  "<ltx:bibliography xml:id='#id' "
    . "bibstyle='#bibstyle' citestyle='#citestyle' sort='#sort'>"
    . "<ltx:title font='#titlefont' _force_font='true'>#title</ltx:title>"
    . "<ltx:biblist>",
  beforeDigest => sub { beforeDigestBibliography(); },
  afterDigest  => sub { beginBibliography($_[1]); }
);

DefConstructor('\endreferences', sub {
    $_[0]->maybeCloseElement('ltx:biblist');
    $_[0]->maybeCloseElement('ltx:bibliography'); });

Let('\reference', '\bibitem');

DefMacro('\comment{}',    '');
DefMacro('\etal',         '\textit{et al.}');
DefMacro('\firstsection', '');

DefAutoload('align',                       'amsmath.sty.ltxml');
DefAutoload('subequations',                'amsmath.sty.ltxml');
DefAutoload('split',                       'amsmath.sty.ltxml');
DefAutoload('\multline',                   'amsmath.sty.ltxml');
DefAutoload('\csname multline*\endcsname', 'amsmath.sty.ltxml');
DefAutoload('numberwithin',                'amsmath.sty.ltxml');
DefAutoload('mathfrak',                    'amsfonts.sty.ltxml');
DefAutoload('mathbb',                      'amsfonts.sty.ltxml');
DefAutoload('deluxetable',                 'deluxetable.sty.ltxml');
DefAutoload('curraddr',                    'ams_support.sty.ltxml');
DefAutoload('subjclass',                   'ams_support.sty.ltxml');
DefAutoload('thechapter',                  'book.cls.ltxml');

# nostalgicly painful from the 1990s arXiv:
# We lock to the internal definition, since we have
# \let\section\Section
# in some documents, and we don't want infinite loops
DefMacroI('\Section',       undef, '\@startsection{section}{1}{}{}{}{}',       locked => 1);
DefMacroI('\Subsection',    undef, '\@startsection{subsection}{2}{}{}{}{}',    locked => 1);
DefMacroI('\Subsubsection', undef, '\@startsection{subsubsection}{3}{}{}{}{}', locked => 1);
DefMacroI('\Paragraph',     undef, '\@startsection{paragraph}{4}{}{}{}{}',     locked => 1);
DefMacroI('\Subparagraph',  undef, '\@startsection{subparagraph}{5}{}{}{}{}',  locked => 1);

# author block, see e.g. arxbj.cls from arXiv:math0603447
DefEnvironment('{aug}', '#body');

1;
