#!/usr/bin/perl -w
use strict;
use FindBin;
use lib "$FindBin::RealBin/../lib";
use LaTeXML::Post;
use LaTeXML::Post::MathML;
use Carp;
use Getopt::Long;

my $verbosity=1;
my $help=0;
my ($demo,$master)=(0,0);
GetOptions("verbose+"     =>\$verbosity,
	   "demo+"        =>\$demo,
	   "master",       =>\$master,
	   "help|?"       =>\$help,
	  ) or warn("Wah!");

BEGIN { $SIG{__DIE__} = \&confess; }

#**********************************************************************
my $DLMFBASE = "$ENV{HOME}/dlmf";
my $SITEBASE = ($demo
		? "/local/www/site/htdocs/DigitalMathLib/LaTeXML/dlmf"
		: ($master
		   ? "/local/dlmf/web"
		   : "/local/www/site/htdocs/DigitalMathLib/xdlmf"));


$ENV{TEXINPUTS}="$DLMFBASE/styles/DLMFtex::";
#**********************************************************************
binmode(STDERR,":utf8");

my $processors=[DLMFMath->new(),
		DLMFGraphics->new(),
		DLMFGallery->new(),
		LaTeXML::Post::MathML::Presentation->new(),
#		DLMFAugment->new()
];

my $post = LaTeXML::Post->new();

foreach my $CH (@ARGV){
  print STDERR "Processing Chapter $CH\n" if $verbosity;
  my $srcdir  = "$DLMFBASE/$CH";
  my $destdir = "$SITEBASE/$CH";
  my $dest    = "$destdir/$CH.xml";
  my $inchap = $post->readDocument("$srcdir/$CH.xml");
  my $outchap = $post->process($inchap,
			       sourceDirectory=>$srcdir,
			       destinationDirectory=>$destdir,
			       destination=>$dest,
			       verbosity=>$verbosity,
			       processors=>$processors);
  $post->writeDocument($outchap,$dest);
}

#**********************************************************************
package DLMFMath;
use strict;
use LaTeXML::Post::MathImages;
BEGIN{ our @ISA = qw(LaTeXML::Post::MathImages); }

# Override the default TeX code for capturing display equations.
# We'll use breqn's framing for display math.
# Alas, it's a bit broken right now, so add some padding between formula and frame.
sub preamble {
  my($self,$doc)=@_;
  $self->SUPER::preamble($doc) 
      ."\\def\\beginDISPLAY{\\begingroup\\[[fullframe]}\n"
      ."\\def\\endDISPLAY{\\]\\endgroup\\clearpage}\n";  }

#**********************************************************************
package DLMFGraphics;
use strict;
use LaTeXML::Post::Graphics;
use LaTeXML::Util::Pathname;
BEGIN{ our @ISA = qw(LaTeXML::Post::Graphics);}

# Need to handle specially:
# TODO:
#   vrml : copy vrml & proto files.

# Graphics in 2D subdirs tend to be line drawings: Prefer the postscript source.
sub findGraphicsFile {
  my($self,$node)=@_;
  my $name = $node->getAttribute('graphic');
# Let's try _always_ using the postscript
# They've been touched up by graphics arts...
  if($name =~ m|^\dD/|){
    my $file = $self->findFile($name,['eps','ps']); 
    return $file if $file; }
  $self->SUPER::findGraphicsFile($node); }

our @VRML_EXTRA;
BEGIN { @VRML_EXTRA = qw(dlmf_proto.wrl sml_rec_proto.wrl
			four.gif legendXYZ.gif smap.gif); }

sub processGraphic {
  my($self,$node)=@_;
  my $source = $self->findGraphicsFile($node);
  return $self->Warn("Missing graphic for $node; skipping") unless $source;
  my $transform = $self->getTransform($node);

  # Check for magnifiable and/or vrml options; then remove them.
  my $mag    = grep($_->[0] eq 'magnifiable',@$transform);
  my ($vrml) = grep(($_->[0] eq 'vrml' ? $_->[1] : ''),@$transform);
  $vrml = $vrml->[1] if $vrml;
  $transform = [grep( $_->[0] !~/^(magnifiable|vrml)$/, @$transform)];
  # Process the main image
  my($image,$width,$height)=$self->transformGraphic($node,$source,$transform); 
  $self->setGraphicsSrc($node,$image,$width,$height) if $image;

  if($mag){			# Generate Magnified image, if requested
    my($mimage,$mwidth,$mheight)=$self->transformGraphic($node,$source,[@$transform,['scale',2.5]]);
    $node->setAttribute('magsrc',$mimage);
    $node->setAttribute('magwidth',$mwidth);
    $node->setAttribute('magheight',$mheight); }

  if($vrml){			# Copy vrml & related files, if requested
    if(my $vrmlsource = $self->findFile($vrml,['wrl'])){
      $node->setAttribute('vrml',$self->copyFile($vrmlsource));
      my($srcdir,$name,$type)=pathname_split($vrmlsource);
#      foreach my $extra (@VRML_EXTRA){
#	my $x = pathname_make(dir=>$srcdir,name=>$extra);
#	$self->copyFile($x) if -f $x; }
      # Too much variability in aux files; copy 'em all!!!
      opendir(DIR, $srcdir) or $self->Warn("Couldn't read files from VRML directory $srcdir: $!");
      my @allvrml = readdir(DIR);
      closedir(DIR);
      foreach my $extra (@allvrml){
	next if $extra =~ /^\./;
	my $x = pathname_make(dir=>$srcdir,name=>$extra);
	$self->copyFile($x) if -f $x; }

    }
    else {
      $self->Warn("Couldn't find VRML file for $vrml at graphic $source"); }}
}

sub XXget_type_map {
  my($self,$src,$options)=@_;
  if($src =~ m|/2D/|){		# 2D: line graphics: use png with transparency.
    {type=>'png', transparent=>1}; }
##  elsif($src =~ m|/3D/|){	# 3D: surfaces best using jpeg.
##    {type=>'jpeg'}; }
  else {
    $self->SUPER::get_type_map($src,$options); }}

#**********************************************************************
# Custom form for Gallery images.
package DLMFGallery;
use strict;
use LaTeXML::Post::Graphics;
BEGIN{ our @ISA = qw(LaTeXML::Post::Graphics);}

sub selectGraphicsNodes { 
  $_[1]->getElementsByTagNameNS($_[0]->getNamespace,'galleryitem'); }
sub getTransform {
  [['scale-to',72,72]]; }

#**********************************************************************
package DLMFAugment;
use strict;
BEGIN{ our @ISA = qw(LaTeXML::Post::Processor); }
use LaTeXML::Util::LibXML;

sub process {
  my($self,$doc)=@_;
  local %::LABELS = map( ($_->getValue()=>1), $doc->findnodes('//@label'));
  local %::LASTOFTYPE = ();
  $self->Progress("Augmenting labels, refnums");
  $self->process_node($doc->documentElement,'','');
  $doc; }

# Worthwhile attributes on all `important' (ie. labelable, referable), nodes
#    label  : hopefully given by author, else generated.
#    refnum : the full reference number, as generated by latex
#    altrefnum : for those nodes not labeled by latex.
#    relrefum  : the reference number relative to the (important) parent.
sub process_node {
  my($self,$node,$dest,$parent)=@_;
  my $tag       = $node->localname;
  my $label     = $node->getAttribute('label');
  my $refnum    = $node->getAttribute('refnum');
  my $altrefnum = $node->getAttribute('altrefnum');
  my $whole=0;

  if(my $d = $node->getAttribute('destination')){ # File marked with destination.
    $dest = $d;  $whole=1; }

  if($tag =~ /^(mainpage|document|authorbio|sidebar)$/){ # !?!?!?!?!
    $node->setAttribute(label=>($label = synthesize_label($node,$parent))) unless $label;
    $parent = $node;
    }
  elsif($tag =~ /^(chapter|part|section|subsection|subsubsection|paragraph|para)$/){
    $node->setAttribute(label=>($label = synthesize_label($node,$parent))) unless $label;
    my $ispart = $tag eq 'part';
    if(!($refnum||$altrefnum)){
      $altrefnum = $self->synthesize_refnum($node,$parent, $tag=~/^(sub|part)/, $ispart);
      $node->setAttribute(altrefnum=>$altrefnum) if $altrefnum; }

    my ($r);
    my $n = $refnum || $altrefnum;
    # In the following refnum formats, XX is chapter code, II is uppercase roman, ii lowercase roman,
    # ## is digits.
    if(!$n){}
    # Chapter refnum:  XX
    elsif($tag eq 'chapter'){
      $dest=$refnum."/"; }
    # Part refnum:  XX.Pt.II
    elsif(($tag eq 'part')         &&($n =~ /^(\w\w)\.Pt\.(\w+)$/)){
      $r=$2; }
    # Section refnum: XX.##
    elsif(($tag eq 'section')      &&($n =~ /^(\w\w)\.(\d+)$/)){
      $r=$2; $dest=$dest.$2; 
      $::LASTOFTYPE{subsection}=$::LASTOFTYPE{subsubsection}
	=$::LASTOFTYPE{paragraph}=$::LASTOFTYPE{subparagraph}
	  =$::LASTOFTYPE{equation}=$::LASTOFTYPE{equationmix}=$::LASTOFTYPE{equationgroup}
	    =$::LASTOFTYPE{figure}=$::LASTOFTYPE{table}
	      =$::LASTOFTYPE{para} = 0; }
    # Subsection refnum: XX.##(ii)
    elsif(($tag eq 'subsection')   &&($n =~ /^(\w\w)\.(\d+)\((\w+)\)$/)){
      $r="($3)"; 
      $::LASTOFTYPE{para} = 0; }
    # Subsubsection refnum: XX.##(ii)(ii)
    elsif(($tag eq 'subsubsection')&&($n =~ /^(\w\w)\.(\d+)\((\w+)\)\((\w+)\)$/)){
      $r="($4)";
      $::LASTOFTYPE{para} = 0; }
    # Paragraph refnum: XX.##(ii)*P##
    # where (ii)* are optional sub/section numbers, assuming paragraph appears within section, at least.
    elsif(($tag eq 'paragraph')    &&($n =~ /^(\w\w)\.(\d)+(.*).\x{00B6}(\d+)$/)){ # Pilcrow
      my($ch,$s,$unit,$n)=($1,$2,$3,$4);
      $unit =~ s/\(//g; $unit=~s/\)/./g;
      $r = $n;
      $::LASTOFTYPE{para} = 0; }
    $node->setAttribute(relrefnum=>$r) if $r;
    $parent = $node unless $tag eq 'para';
    }
  elsif($tag =~ /^(table|figure)$/){
    $node->setAttribute(label=>($label = synthesize_label($node,$parent))) unless $label;
    if(!($refnum||$altrefnum)){
      $altrefnum = $self->synthesize_refnum($node,$parent);
      $node->setAttribute(altrefnum=>$altrefnum); }
    my $n = ((($refnum||$altrefnum) =~ /^(\w\w)\.(\d+)\.(\d+)$/) ? $3 : '');
    $node->setAttribute(relrefnum=>$n) if $n;
    $parent = $node; }
  # No, I think we shouldn't add labels to equationgroup;
  # If they weren't numbered, they apparently are only for visual alignment,
  # rather than implying any logical structure
#  elsif($tag =~ /^(equation|equationmix|equationgroup)$/){
  elsif($tag =~ /^(equation|equationmix)$/){
    $node->setAttribute(label=>($label = synthesize_label($node,$parent))) unless $label;
    if(!($refnum||$altrefnum)){
      $altrefnum = $self->synthesize_refnum($node,$parent);
      $node->setAttribute(altrefnum=>$altrefnum); }
    my $n =((($refnum||$altrefnum||'') =~ /^(\w\w)\.(\d+)\.(\d+)$/) ? $3 : '');
    $node->setAttribute(relrefnum=>$n) if $n;
    $parent = $node; }
  elsif($tag eq 'equationgroup'){
    $parent = $node if $node->getAttribute('label'); }
  elsif($tag =~ /^(bibentry)$/){
    # needs label?
  }
  # Recurse on content.
  map($self->process_node($_,$dest,$parent), element_nodes($node));
}

#======================================================================
# NOTE: Where does this belong???
# Here??? Or in Target???
# Create a unique label for $node if none was given.
# Assume labels of the form "type:ch.pt.sec" or similar.
# Type is an abbreviation drawn from the following:
our %LABELPREFIX;
our %PREFIXES;
BEGIN{
%LABELPREFIX=(chapter=>'ch', part=>'pt', section=>'sec',
		  subsection=>'sec',subsubsection=>'sec',
		  paragraph=>'par', subparagraph=>'par', para=>'p',
		  table=>'tab', figure=>'fig',
		  equation=>'eq', equationmix=>'eq',equationgroup=>'eq',
		  sidebar=>'sb');
%PREFIXES = 
  (equation     =>'Eq.', equationmix  =>'Eq.', equationgroup=>'Eq.',
   figure       =>'Fig.', table        =>'Tab.',
   chapter      =>'Ch.', part         =>'Pt.',
   section      =>"\x{00A7}", subsection   =>"\x{00A7}", subsubsection=>"\x{00A7}",
   paragraph    =>"\x{00B6}", subparagraph =>"\x{00B6}");
}
sub synthesize_label {
  my($node,$parent)=@_;
  return unless $parent;
  my $label = $parent->getAttribute('label');
  my $tag = $node->localname;
  $label =~ s/^(\w+):/ {$LABELPREFIX{$tag}.":";} /e; # Substitute our prefix
  my ($title) =$node->findnodes("*[local-name()='toctitle' or local-name()='title'"
				."   or local-name()='toccaption' or local-name()='caption']"
#				."[namespace-uri()='".NSURI."']"
			       );
  $title = stringify($title) if $title;
  my($newlabel,$suf)=('','');
  # Try different ways of creating a label from the title/caption.
  if($title && ($suf = join('',map( s/^(\w).*/$1/ && $_, split(/ /,$title))))
     && length($suf)>1 && !$::LABELS{"$label.$suf"}){
    $newlabel = "$label.$suf"; }
  elsif($title && ($title =~ /^(\w\w?\w?)/) && ($suf=$1)
	&& length($suf)>1 && !$::LABELS{"$label.$suf"}){
    $newlabel = "$label.$suf"; }
  else {
    my $i=1;
    while($::LABELS{"$label.$suf$i"}){ $i++; }
    $newlabel = "$label.$suf$i"; }
  $::LABELS{$newlabel}=1;
  $node->setAttribute('label', $newlabel);
  $newlabel; }


sub synthesize_refnum {
  my($self,$node,$parent,$roman,$uppercase)=@_;
  if(my $prefnum =  $parent && ($parent->getAttribute('refnum')||$parent->getAttribute('altrefnum'))){
    my $n = ++$::LASTOFTYPE{$node->nodeName};
    $n = roman($n) if $roman;
    $n = uc($n) if $uppercase;
    $prefnum . '.'. ($PREFIXES{$node->nodeName}||'') . $n; }}

# Cribbed from LaTeXML [The TeX way! (bah!! hint: try a large number)]
my @rmletters;
BEGIN { @rmletters=('i','v',  'x','l', 'c','d', 'm'); }
sub roman {
  my($n)=@_;
  my $div= 1000;
  my $s=($n>$div ? ('m' x int($n/$div)) : '');
  my $p=4;
  while($n %= $div){
    $div /= 10;
    my $d = int($n/$div);
    if($d%5==4){ $s.= $rmletters[$p]; $d++;}
    if($d > 4 ){ $s.= $rmletters[$p+int($d/5)]; $d %=5; }
    if($d) {     $s.= $rmletters[$p] x $d; }
    $p -= 2;}
  $s; }

sub stringify {
  my(@stuff)=@_;
  my $string = join('', map((ref $_ ? $_->textContent : $_),@stuff)); 
  $string =~ s/^\s+//;
  $string =~ s/\s+$//;
  $string; }

#**********************************************************************
