# -*- 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.
#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
RequirePackage('amsgen');

DefMacro('\CD', '\lx@ams@CD{name=CD,datameaning=commutative-diagram}');
DefMacro('\lx@ams@CD RequiredKeyVals:lx@GEN',
  '\lx@gen@matrix@bindings{#1}\lx@ams@CD@bindings\lx@ams@matrix@{#1}\@start@alignment');
DefMacro('\endCD', '\@finish@alignment\lx@end@gen@matrix');
DefPrimitive('\lx@ams@CD@bindings', sub {
    Let("\\\\", '\@alignment@newline@noskip');
    $STATE->assignMathcode('@' => 0x8000);
    Let('@', '\cd@'); });

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

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

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

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

# 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'));

DefConstructor('\cd@stack Undigested {} ScriptStyle ScriptStyle', sub {
    my ($document, $reversion, $op, $over, $under, %props) = @_;
    my $scriptpos = $props{scriptpos};
    if (!IsEmpty($under)) {
      $document->openElement('ltx:XMApp', role => 'ARROW');    # Role?
      $document->insertElement('ltx:XMTok', undef, role => 'SUBSCRIPTOP', scriptpos => $scriptpos);
      if (!IsEmpty($over)) {
        $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 (!IsEmpty($over)) {
      $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]->getScriptLevel; } },
  reversion  => '@#1{#3}#1{#4}#1');

# Temporary...
# Later deal with vertically centering the side things, parser issues...

DefConstructor('\cd@adjacent Undigested {} ScriptStyle ScriptStyle', sub {
    my ($document, $reversion, $op, $left, $right, %props) = @_;
    $document->openElement('ltx:XMWrap', role => 'ARROW');    # Role?
    $document->insertElement('ltx:XMArg', $left) unless IsEmpty($left);
    $document->insertElement('ltx:XMArg', $op);
    $document->insertElement('ltx:XMArg', $right) unless IsEmpty($right);
    $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;
