# -*- mode: Perl -*-
# /=====================================================================\ #
# |  amscd                                                              | #
# | 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;

#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
# Note that the amscd authors themselves point out that amcsd is limited,
# only covering array-like commutative diagrams, and they suggest
# diagram, xypic or kuvio as alternatives.
#
# However, it is just that simplicity that mkes it possible to represent
# the commutative diagram in straight latexml math, w/o resorting to
# the more general svg(-like) problems.
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

DefMacro('\CD',    '\@@CD\@start@alignment');
DefMacro('\endCD', '\@finish@alignment\@end@CD');
DefPrimitive('\@end@CD', sub { $_[0]->egroup; });
DefConstructor('\@@CD DigestedBody',
  '#1',
  beforeDigest => sub {
    $_[0]->bgroup;
    alignmentBindings(MatrixTemplate(), 'math', attributes => { meaning => 'commutative-diagram' });
    Let(T_ALIGN, '\@cd@invisible@align');
    Let("\\\\",  '\@alignment@newline@noskip');
    $STATE->assignMathcode('@' => 0x8000);
    Let('@', '\cd@'); },
  reversion => '\begin{CD}#1\end{CD}');

DefMacroI('\@cd@invisible@align', undef,
  '\@close@inner@column\@close@column'
    . '\@open@column\@open@inner@column');
#DefConstructorI('\@alignment@align@marker',undef,'',reversion=>'&');

DefMacro('\cd@ Token', sub {
    my ($gullet, $token) = @_;
    (T_CS('@' . ToString($token))); });

DefMacroI(T_CS('@>'), 'Until:> Until:>',
  '&\cd@stack{>}{\rightarrowfill@}{#1}{#2}&');
DefMacroI(T_CS('@)'), 'Until:) Until:)',
  '&\cd@stack{)}{\rightarrowfill@}{#1}{#2}&');
DefMacroI(T_CS('@<'), 'Until:< Until:<',
  '&\cd@stack{<}{\leftarrowfill@}{#1}{#2}&');
DefMacroI(T_CS('@('), 'Until:( Until:(',
  '&\cd@stack{(}{\leftarrowfill@}{#1}{#2}&');

DefMacroI(T_CS('@A'), 'Until:A Until:A',
  '\cd@adjacent{A}{\Big\uparrow}{#1}{#2}&&');
DefMacroI(T_CS('@V'), 'Until:V Until:V',
  '\cd@adjacent{V}{\Big\downarrow}{#1}{#2}&&');

DefMacroI(T_CS('@='), undef,
  '&\@cd@equals@&');
DefMacroI(T_CS('@|'), undef,
  '\Big\Vert&&');
DefMacroI(T_CS('@\vert'), undef,
  '\Big\Vert&&');
DefMacroI(T_CS('@.'), undef,
  '&&');

# Horizontal
DefMath('\@cd@equals@', "=", role => 'ARROW', stretchy => 'true', reversion => '@=');
# Vertical
DefMath('\@cd@bar@', "|", role => 'ARROW', font => { size => 'Big' }, reversion => '@|');
DefMath('\@cd@vert@', "\x{2225}", role => 'ARROW', font => { size => 'Big' }, reversion => '@\vert');

DefRegister('\minaw@' => Dimension('11.111pt'));

# deal with under, over & underover!
DefConstructor('\cd@stack Undigested {}{}{}', sub {
    my ($document, $reversion, $op, $over, $under, %props) = @_;
    my $scriptpos = $props{scriptpos};
    if ($under->unlist) {
      $document->openElement('ltx:XMApp', role => 'ARROW');    # Role?
      $document->insertElement('ltx:XMTok', undef, role => 'SUBSCRIPTOP', scriptpos => $scriptpos);
      if ($over->unlist) {
        $document->openElement('ltx:XMApp');                   # Role?
        $document->insertElement('ltx:XMTok', undef, role => 'SUPERSCRIPTOP', scriptpos => $scriptpos);
        $document->insertElement('ltx:XMArg', $op);
        $document->insertElement('ltx:XMArg', $over);
        $document->closeElement('ltx:XMApp'); }
      else {
        $document->insertElement('ltx:XMArg', $op); }
      $document->insertElement('ltx:XMArg', $under);
      $document->closeElement('ltx:XMApp'); }
    elsif ($over->unlist) {
      $document->openElement('ltx:XMApp');                     # Role?
      $document->insertElement('ltx:XMTok', undef, role => 'SUPERSCRIPTOP', scriptpos => $scriptpos);
      $document->insertElement('ltx:XMArg', $op);
      $document->insertElement('ltx:XMArg', $over);
      $document->closeElement('ltx:XMApp'); }
    else {
      $document->insertElement('ltx:XMArg', $op); } },
  properties => { scriptpos => sub { "mid" . $_[0]->getBoxingLevel; } },
  reversion => '@#1{#3}#1{#4}#1');

# \cd@adj{}{}{}
# Temporary...
# Later deal with vertically centering the side things, parser issues...
#DefMacro('\cd@adjacent{}{}{}{}','{#3}{#2}{#4}');

DefConstructor('\cd@adjacent Undigested {}{}{}', sub {
    my ($document, $reversion, $op, $left, $right, %props) = @_;
    $document->openElement('ltx:XMWrap', role => 'ARROW');    # Role?
    $document->insertElement('ltx:XMArg', $left)  if $left->unlist;
    $document->insertElement('ltx:XMArg', $op);
    $document->insertElement('ltx:XMArg', $right) if $right->unlist;
    $document->closeElement('ltx:XMWrap'); },
  reversion => '@#1{#3}#1{#4}#1');

# This isn't really having the desired effect when transformed to MathML and
# displayed in Firefox.... have I got it right; has Firefox???
DefMath('\leftarrowfill@',  "\x{2190}", role => 'ARROW', stretchy => 'true');
DefMath('\rightarrowfill@', "\x{2192}", role => 'ARROW', stretchy => 'true');

DefRegister('\minCDarrowwidth' => Dimension('2.5pc'));

#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

1;