#!/usr/bin/env perl

# This is valid Perl code but not yet .latexmkrc. 
# It is a template where the names of settings of this builder 
# must be replaced by their values. 
# As a result, a true .latexmkrc files arises which reflects the current settings of this builder. 

# The names to be replaced have the form $-{parameterName} or $-{functionName()} but without '-' 
# and both variants may only occur within double quoted literal Perl strings. 
# Although they look similarly, they are no variables to be substituted. 
# They are not allowed within single quoted strings 
# because if the java strings they represent contain a " this is always replaced by \" 
# before substituting. 
# This holds even if there is no variable substitution so " is superfluous and ' would do also from the point of view of Perl. 
# Perl interprets the sequence \" within double quoted strings as just " in the Perl string, 
# so that the Perl string is exactly what the original java string was. 

# A word on the difference between $-{parameterName} and $-{functionName()}: 
# Whereas the former is just the name of a setting, i.e. a parameter in class Settings, 
# the latter is the result of some computation based on the Settings. 
# As an example, $-patternLatexMainFilePerl()} is the parameter $-{patternLatexMainFile} 
# which is a regex pattern in the java world, which is useless in this context, 
# whereas $-{patternLatexMainFilePerl()} is the translation into an equivalent Perl pattern. 


# The following is to check whether the pom really overwrites the settings in defaultSettingsAs.properties
# ${chkTexOptions}<chkTexOptions>-q -b0 -L -H1</chkTexOptions>

# to create pdf via lualatex 
#$pdflatex = 'lualatex -file-line-error %O %S';

our ($pdf_mode, $lualatex, $bibtex_use, $bibtex, $max_repeat, $Pbase, 
    $cleanup_includes_cusdep_generated, $cleanup_includes_generated, $makeindex, $extra_rule_spec, 
    $compiling_cmd, $success_cmd, $warning_cmd, $failure_cmd);

# PDF-generating modes are:
# 0: do NOT generate a pdf version of the document. (default)
# 1: pdflatex, as specified by $pdflatex variable (still largely in use)
# 2: via postscript conversion, as specified by the $ps2pdf variable (useless)
# 3: via dvi conversion, as specified by the $dvipdf variable (useless)
# 4: lualatex, as specified by the $lualatex variable (best)
#    Note that we abuse that by replacing lualatex by a variable
# 5: xelatex, as specified by the $xelatex variable (second best)
# This is abused here, just to invoke $lualatex which leads to run_latex

# specifies creation of pdf via lualatex 
$pdf_mode = 4;


# If additional parameters must be passed to lualatex 
#'svg' package.
# It converts raw SVG files to the PDF+PDF_TEX combo using InkScape.
# $lualatex = "lualatex --shell-escape";

# note that -recorder is implicitly added by latexmk, 
# so may be duplicated, but no disadvantage 
# %O is the options (additional options passed by latexmk)
# %S source file (maybe %A and %B more appropriate: without ending)
#$lualatex = "${getLatex2pdfCommand()} ${latex2pdfOptions} %O %S";
$lualatex = "internal run_latex %A %O";

# superfluous for perl >=5.36 according to documentation, but does not work for me (perl 5.38?)
use v5.36; # by 2022
# The following are implied by v5.36 
#use strict;
#use warnings;
#use feature 'signatures';

# for treatment of sub functionName($val = undef)
no warnings 'experimental::signatures';
#no warnings 'experimental::args_array_with_signatures';
# the following desirable but currently not possible 


__PACKAGE__ eq 'main' or die "Not in main package!";


package LatexHelpers;
# TBD: distinguish between DocumentMetadata and SetKeys 

# written as side effect of parseTexFile 
# may be undef or empty which must be distinguished. 
my %docMeta;

# written as side effect of parseTexFile 
# Note that this does not just contain the magic comments, 
# but it contains the settings determined by base configuration 
# possibly overwritten by magic comments. 
# The keys are as in the configuration given by the pom 
# unlike docMeta, 
# this is always defined after compiling_cmd has been invoked. 
my %withMagicComments;

# written as side effect of parseTexFile 
# A pdf file for comparison. 
# This may well be undefined if a pdf is not to be reconstructed 
# or if the artifact is no PDF file at all. 
my $pdfFileDiff;

my %metaPdfFlat;
my %metaPdfXmp;

=head1 ATTRIBUTES

=over 4


=item C<%docMeta>

bla blubb

=back
=cut

=head1 FUNCTIONS

=over 4 

=item C<reset()>

Undefines `docMeta`, `metaPdfFlat` and `metaPdfXmp`. 

=item C<codMeta()>

A combined getter/setter for L</"%docMeta">

=back 

=cut

sub reset() {
  #undef %docMeta;
  undef %metaPdfFlat;
  undef %metaPdfXmp;
}


# sub docMeta ($key = undef) {
#   return $docMeta{$key} if defined $key;
#   return \%docMeta; # reference on hash 
# }

sub docMeta($key = undef) {
  # like in java: return null (undef) if ... 
  return undef unless %docMeta; 

  # if the key is given, return the according value 
  return $docMeta{$key} if defined $key;
  # else return the reference on the hash 
  return \%docMeta; 
}

sub withMagicComments($key = undef) {

  # if the key is given, return the according value 
  return $withMagicComments{$key} if defined $key;
    # else return the reference on the hash 
  return \%withMagicComments; 
}

sub pdfFileDiff() {
  return $pdfFileDiff;
}

use constant boolStrToVal => {true => 1, false => 0};



# for printing hashes 
# is in perl-core since Perl 5.005 
use Data::Dumper;

# TBD: in fact, if it is clear that we only create PDF, then we could simplify: 
# $fileName and the rest is by adding the ending. 
# If not then we must add detection of the ending of the target 
# and do only part of the functionality if no PDF file. 
sub parseTexFile($fileNameSrc, $fileNameTarget) {
  # parses the tex file to find out 
  # - magic comments which may modify basic settings 
  #   The result initializes `withMagicComments`
  # - documentmetadata which initializes `docMeta` 


  # The pattern is used to read magic comments. 
  # Double quotes because the pattern contains single quotes; 
  # no interpolation 
  my ($programMagic, $chkDiffMagic, $chkDiffMagicVal, $docMetadata, $docClass);
  my $patternLatexMainFile = "${patternLatexMainFilePerl()}";
  print("patternLatexMainFile: \n$patternLatexMainFile\n");
  open my $info, $fileNameSrc or die "Could not open $fileNameSrc : $!";
  # the lines read so far (each line with newline)
  my $lines = "";
  while (my $line = <$info>) {
    print "$line\n";
    $lines = "$lines$line";
    if ($line =~ /$patternLatexMainFile/) {
      #print("line matches |$+{programMagic}|\n");
      #print("line matches |$+{docClass}|\n");
      #print("lines: \n$lines\n");
      close $info;
      if ($lines !~ /$patternLatexMainFile/) {
        die("$fileNameSrc is no latex main file: preamble does not match\n");
      }
      print("preamble matches: \n");
      $programMagic    = $+{programMagic}    if $+{programMagic};
      $chkDiffMagic    = $+{chkDiffMagic}    if $+{chkDiffMagic};
      $chkDiffMagicVal = $+{chkDiffMagicVal} if $+{chkDiffMagicVal};
      $docMetadata     = $+{docMetadata}     if $+{docMetadata};
      $docClass        = $+{docClass}        if $+{docClass};
    }
    # Here, the line does not match: go on 
    last if $docClass;
  } # while 



  print("docClass: $docClass\n");
  print("docMetas: $docMetadata\n");

  if (defined $docMetadata) {
    my $patternMetadata = "${patternMetadataPerl()}";

    while ($docMetadata =~ /$patternMetadata/g) {
      my $key   = $+{key};
      my $value = $+{value};   # may be undefined 

      if (!defined $value) {
        $docMeta{$key} = 1;
        next;
      }

      # ggf. {} entfernen
      $value =~ s/^\{|\}$//g if defined $value;
      if ($key eq 'pdfstandard') {

        my $oldVal = $docMeta{$key};
        if (defined $oldVal) {
          # If an old value has been present, the new one is appended 
          # separated with a comma 
          $docMeta{$key} = $oldVal . ", " . $value;
        } else {
          # First `pdfstandard` 
          $docMeta{$key} = $value;
        }
      }

      $docMeta{$key} = $value // 1;  # 1 if $value is undef (uncompress)
    }
  } else {
    undef %docMeta;
  }
 
  print ("docMeta: %docMeta");


  #my $latexCommand = ($programMagic ? $programMagic : '${getLatex2pdfCommand()}');
  my $latexCommand = $programMagic //'${getLatex2pdfCommand()}';

  # Make default value explicit 
  # $chkDiffMagic = ($chkDiffMagic and not $chkDiffMagicVal)
  #   ? 'true' : $+{chkDiffMagicVal};
  $chkDiffMagic = ($chkDiffMagic and not $chkDiffMagicVal)
    ? 'true' : $chkDiffMagicVal;
  #my $chkDiffB     = ($chkDiffMagic ? $chkDiffMagic : '${chkDiff}');
  my $chkDiffB     = $chkDiffMagic // '${chkDiff}';
  $chkDiffB     = boolStrToVal->{$chkDiffB};
  %withMagicComments = (
    latex2pdfCommand => $latexCommand,
    chkDiff          => $chkDiffB,
  );

  if ($chkDiffB) {
    my $pdfFileOrg = catfile(getcwd(), $fileNameTarget);

    my $baseDirectory   = '${baseDirectory}/';  # trailing '/' for concatenation
    my $texSrcDirectory = '${texSrcDirectory}/';
    my $diffDirectory   = '${diffDirectory}/';

    $pdfFileOrg =~ s/\Q$baseDirectory$texSrcDirectory//;
    $pdfFileDiff = "$baseDirectory$diffDirectory$pdfFileOrg";
    if (!-e $pdfFileDiff) {
      # Here, $epoch_timestamp is not defined 
      undef $pdfFileDiff;
    }
  }

}

#parseTexFile($ARGV[0]);

use Cwd qw(getcwd);# in core-modules since Perl 5.000
use File::Spec::Functions qw(catfile);# in core-modules since Perl 5.005 
use Capture::Tiny qw(capture_stdout);# NO core-module 
# replace 
# my ($stdout, $res) = capture_stdout {
#     system("${getPdfMetainfoCommand()} ${pdfMetainfoOptions} \"$pdfFile\"");
# };
# by 
# $stdout = `${getPdfMetainfoCommand()} ${pdfMetainfoOptions} "$pdfFile"`
# $res = $? >> 8;

#use DateTime;
# this is NO core module. 
# TBD: try to replace by Time::Piece 
use DateTime::Format::ISO8601; # for ->parse_datetime


#sub initPdfMetadataHash($pdfFile) {
sub initPdfMetadataHash() {
    
  # 1. base infos (CreationDate, Author, Pages, etc.) neet not be present
  my ($stdout, $res) = capture_stdout {
      system('${getPdfMetainfoCommand()} ${pdfMetainfoOptions} ' . "\"$pdfFileDiff\"");
  };
  $res == 0 or die "FATAL: ${getPdfMetainfoCommand()} failed with return value $res.";
  my @lines = split /\r?\n/, $stdout;

  foreach my $line (@lines) {
    $line =~ /^(?<key>[^:]+):\s+(?<value>.*)$/ 
      or die "FATAL: Unexpected pdfinfo output format or empty line: ['$line']";
    $metaPdfFlat{$+{key}} = $+{value};
  }

  # TBD: factor out hash print. 
  print "\n[DEBUG] Flat Metadata Hash Dump:\n";
  while (my ($k, $v) = each %metaPdfFlat) {
    print "    Key: '$k' -> Value: '$v'\n";
  }


  # 2. XMP-Metadata (modern, precise)
  ($stdout, $res) = capture_stdout {
    system('${getPdfMetainfoCommand()} ${pdfMetainfoXmpOptions} ' . "\"$pdfFileDiff\"");
  };
  $res == 0 or die "FATAL: ${getPdfMetainfoCommand()} failed with return value $res.";

  # TBD: read completely all 
  while ($stdout =~ m'<(?<key>(?:pdf|pdfaid|pdfuaid|xmp|xmpMM|prism):\w+)>(?<value>[^<>]+)</\k<key>>'sg) {
    print("key $+{key}\n");
    # TBD: reactivate after architecture switch. 
    #die "FATAL: Duplicate XMP key found: ['$+{key}']" if exists $metaPdfXmp{$+{key}};
    $metaPdfXmp{$+{key}} = $+{value};
  }
  print "\n[DEBUG] XMP Metadata Hash Dump:\n";
  while (my ($k, $v) = each %metaPdfXmp) {
    print "    Key: '$k' -> Value: '$v'\n";
  }
}


# To avoid 
# use DateTime::Format::ISO8601 qw(parse_datetime)
  # my $dt = DateTime::Format::ISO8601->parse_datetime($creationDate);
  # my $creationDateEpoch = $dt->epoch();
# try 
# # in Perl core module since Perl 5.10.0 (2007) latexmk ca 2000, tlmgr since 2008
# use Time::Piece ww(strptime) 
# eval {
#        # %Y: year, %m: month, %d: day, %H: hour, %M: minute, %S: second, %z: time zone 
#        # caution: whereas ISO8601 knows about Z for +0000, %z can be numerical only. 
#        # means also that +hh:mm does not work, only +0hhmm, whereas ISO8601 allows both. 
#        # Although ISO8601 allows doing without time zone and also PDF standard allows, 
#        # latex compiler always provide a time zone. 
#         my $t = Time::Piece->strptime($iso_string, "%Y-%m-%dT%H:%M:%S%z");
#         return $t->epoch;
#     };
    
#     # Falls pdfinfo mal eine Zone ohne Doppelpunkt/Offset liefert (Fallback)
#     if ($@) {
#         my $t = Time::Piece->strptime($iso_string, "%Y-%m-%dT%H:%M:%S");
#         return $t->epoch;
#     }



sub getTimestampDiff() {
  #initPdfMetadataHash($pdfFileDiff);
  initPdfMetadataHash();
 my $creationDate = $metaPdfXmp{'xmp:CreateDate'} // $metaPdfFlat{'CreationDate'};
  defined $creationDate or die "Found no creation date";
  #$creationDate =~ s/^D://;
  #print("metainfo ok: $res\n");
  #print("metainfos: \n$stdout\n");
  #print("CreationDate: $creationDate}n");
  my $dt = DateTime::Format::ISO8601->parse_datetime($creationDate);
  my $creationDateEpoch = $dt->epoch();
  #print("internal epoch time: $creationDateEpoch\n");
  return $creationDateEpoch;
}


1;

package main;


# TBD: not ideal for pdfViaDvi=true: conversion dvi to pdf is needed only once at the end, 
# whereas this method does conversion dvi to pdf each time also tex to dvi is performed. 
# Thus in the long run only run dvi2pdf; the rest is done with rules. 
sub run_latex($fileName, @opts) {

  # Already initialized in run_preDecideCompilation
  my $ref = LatexHelpers::withMagicComments();
  # {$ref} dereferences the hash 
  my ($latexCommand, $chkDiffB) = @{$ref}{'latex2pdfCommand', 'chkDiff'};
  # This is just short for 
  # my $latexCommand = $ref->{latex2pdfCommand};
  # my $chkDiffB     = $ref->{chkDiff};

  #$chkDiffB = LatexHelpers::boolStrToVal->{$chkDiffB};

  my $timeEnv = "";
  my $epoch_timestamp;
  if ($chkDiffB) {
    # # The following is to determing PDF file to diff if chkDiff is set 

    # Here, getTimestampDiff is undef if there is no PDF to reproduce. 
    # else it is the timestamp of the pdf to be reproduced. 
    
    
    if (defined(LatexHelpers::pdfFileDiff())) {
      # Here, the reference file exists 
      $epoch_timestamp = LatexHelpers::getTimestampDiff();
      # For lualatex setting TZ=UTC is needed but FORCE_SOURCE_DATE is ignored 
      # For pdflatex setting TZ=UTC is superfluous but FORCE_SOURCE_DATE is needed; 
      # the same for xelatex 
      $timeEnv = "TZ=UTC SOURCE_DATE_EPOCH=$epoch_timestamp FORCE_SOURCE_DATE=1 ";
    } else {
      # Here, the reference PDF file does not exist, so local time but with GMT timezone 
      $timeEnv = "TZ=UTC ";
    }
    # in both cases note the trailing blank 
    # The settings are required both for direct compilation into PDF and for compilation via DVI 
  }

  my $pdfViaDvi = LatexHelpers::boolStrToVal->{'${pdfViaDvi}'};
  # note that exactly one of the two options -no-pdf -output-format=dvi applies; 
  # the other is ignored. 
  # TBD: eliminate: xelatex emits a warning because -output-format is unknown 
  my $addArgs = $pdfViaDvi ? "-no-pdf -output-format=dvi " : "";
  # TBD: evaluate return values properly.  
  my $res = system("$timeEnv$latexCommand " . '${latex2pdfOptions} ' . "$addArgs @opts $fileName");
  if ($pdfViaDvi) {
    # Note that $timeEnv is first of all suitable for the latex compiler. 
    # strictly speaking FORCE_SOURCE_DATE is not needed; the other variables are needed 
    # to set up 
    # TBC: ignores options %O from latexmk, acceptable 
    $res = $res or
      system("$timeEnv" . '${getDvi2pdfCommand()} ${dvi2pdfOptions} ' . "$fileName");
  }
  return $res;
}

#$postscript_mode = $dvi_mode = 0;

# to configure bibtex 
# bbl files are never precious 
$main::bibtex_use = 2;
$main::bibtex = '${bibtexCommand} ${bibtexOptions} ' . "%O %S";# default: bibtex %O %S

# this cannot be done according to the according latex maven plugin, 
# because the according parameter maxNumReRunsLatex may be set to -1 
# which signifies an infinite number of runs. 
$main::max_repeat = 30;

# default are tex and eps, but could also be pdf and ptx and mps
# Currently, all those files are given with explicit endings, 
# so no extensions to be added. 
#add_input_ext('');

# It is what it seems to be: clean inludes what was generated by cus 
$main::cleanup_includes_cusdep_generated = 1;
$main::cleanup_includes_generated = 1;

# TBD: clarify: xdv and dvi seem to be internal. 
# maybe missing other extensions in conjunction with synctex 
# maybe better @generated_exts see below 
push @main::generated_exts, "%R.synctex.gz", "%R.synctex";;

# bbl does not work
#@generated_exts = (@generated_exts, 'lol', 'bbl', 'glo', 'ist')
#print "Hello!"
#foreach (@generated_exts) {
#print "Generated exts: $_\n";
#}
#print "clean_ext\n";
# Here @generated_exts is ('aux', 'fls', 'log', # generated by latex already
# 'toc', 'lof', 'lot', 'out', # generated by latex conditionally 
# 'idx', 'ind', 'blg', 'ilg', # concerning indices 
# # strange enough: nothing for bibtex 
# 'xdv', 'bcf'

# extensions ext to be deleted by latexmk -c 
# Note that the file names are %R.ext. 
# this may cause problems with extensions containing a dot. 
# Also this is not general enough 
# if the generated file deviates from %R by more than an extension. 
# In this case, use the form with explicit '%R'. 
# list of listings, whereas lof and lot are already present. 
push @main::generated_exts, "lol";
push @main::generated_exts, "dvi", "xdv";
# for beamer class 
push @main::generated_exts, "nav", "snm", "vrb", 'run.xml';
push @main::generated_exts, "clg";# log file for chktex: specific for latex builder LMP 
push @main::generated_exts, "soc";# package changes, also adding toc if not present 
push @main::generated_exts, "sil";# package silence
push @main::generated_exts, "tdo";# package todonotes
push @main::generated_exts, "xmpdata";# written by filecontents for pdfx 

# why are 'ist' and 'xdy' not under generated_exts? 
# note that currently, either %R or what is present is the extension only! 
# this does not make sense very much. 
# $clean_ext .= " stateMachine.log"; does not work, because stateMachine.log is the extension! 

# should be under indexing 
push @main::generated_exts, '%ist', '%xdy', '%R-*.ind', '%R-*.idx', '%R-*.ilg', '%R-*.ind';

# many arguments shall be quoted 
# but in many cases it is immaterial; except in metapost 
sub quote($inString) {
  my $outString = $inString;
  $outString =~ s/^ */'/; # add leading ' after eliminating leading blanks 
  $outString =~ s/ *$/'/; # add closing ' after eliminating trailing blanks 
  # so far: quote after trim 
  $outString =~ s/ +/' '/g; # replace a sequence of blanks by a single one 
  $outString =~ s/''//;     # unquote the empty string 
  
  #print "out: $outString\n";
  return $outString;
}


add_cus_dep('fig', 'ptx', 0, 'fig2dev');
sub fig2dev($file) {
  print("create 'ptx' from '$file.fig'\n");
  rdb_add_generated("$file.pdf", "$file.eps");
  my ($name, $path) = fileparse($file);
  pushd($path);
    #fig2dev -L pstex    <fig2devGenOptions> <fig2devPdfEpsOptions>        xxx.fig xxx.eps   
    #fig2dev -L pdftex   <fig2devGenOptions> <fig2devPdfEpsOptions>        xxx.fig xxx.pdf   
    #fig2dev -L pdftex_t <fig2devGenOptions> <fig2devPtxOptions>    -p xxx xxx.fig xxx.ptx
    # TBD: evaluate return values properly 
    my $ret1 = system('${getFig2devCommand()} -L  pstex   ${fig2devGenOptions} ${fig2devPdfEpsOptions}       ' . "$name.fig $name.eps");
    my $ret2 = system('${getFig2devCommand()} -L pdftex   ${fig2devGenOptions} ${fig2devPdfEpsOptions}       ' . "$name.fig $name.pdf");
    my $ret3 = system('${getFig2devCommand()} -L pdftex_t ${fig2devGenOptions} ${fig2devPtxOptions} -p ' . "$name $name.fig $name.ptx");
  popd();
  $ret1 >>= 8;
  $ret2 >>= 8;
  $ret3 >>= 8;
 return ($ret1 or $ret2 or $ret3);
}

my $gnuplotOptions = "";
add_cus_dep('gp', 'ptx', 0, 'gnuplot');
sub gnuplot($file) {
  print("create 'ptx' from '$file.gp'\n");
  rdb_add_generated("$file.pdf", "$file.eps");
  my ($name, $path) = fileparse($file);
  pushd($path);
    # here in the java code no quoting occurs 
    #my $gnuplotOptionsQ = quote(qq/${gnuplotOptions}/);
    my $ret1 = system(qq/${getGnuplotCommand()} -e "set terminal cairolatex pdf ${gnuplotOptions};\
            set output '$name.ptx';\
            load '$name.gp'"/);
    # my $ret2 = system("gnuplot -e \"set terminal cairolatex eps ${gnuplotOptions};\
    #           set output '$name.ptx';\
    #           load '$name.gp'\"");
  popd();
  $ret1 >>= 8; # reconstruct return value of the application 
  return $ret1;
}

# metapost rule from http://tex.stackexchange.com/questions/37134
#add_cus_dep('mp', 'mps', 0, 'mpost');
add_cus_dep('mp', 'mps', 0, 'mpost');
sub mpost($file) {
  print("create 'mps' from '$file.mp'\n");
  rdb_add_generated("$file.mpx", "$file.fls", "$file.log");
  # TBD: mpx files are written only if the mp file contains latex parts. 
  # It would be cleaner to add the mpx file after invoking mpost 
  # with the condition that an mpx file is present. 
  # Likewise, 
  my ($name, $path) = fileparse($file);
  pushd($path);
    my $metapostOptionsQ = quote('${metapostOptions}');
    #print "quoted: $metapostOptionsQ\n";
    my $ret = system(qq/${getMetapostCommand()} $metapostOptionsQ $name/);
  popd();
  $ret >>= 8; # reconstruct return value of the application 
  return $ret;
}


add_cus_dep('svg', 'ptx', 0, 'inkscape');
sub inkscape($file) {
  print("create  'ptx'from '$file.svg'\n");
  rdb_add_generated("$file.pdf", "$file.eps");
  my ($name, $path) = fileparse($file);
  pushd($path);
    my $svg2devCommand = '${getSvg2devCommand()}';
    my $svg2devOptions = '${svg2devOptions}';
    my $ret1 = system(qq/$svg2devCommand --export-filename=$name.pdf $svg2devOptions $name.svg/);
    #my $ret2 = system("inkscape --export-filename=$name.eps -D --export-latex $name.svg ");
    #use File::Copy;
    # This works only for pdf, not for eps. 
    #unlink($name.pdf_tex) or die "cannot unlink $name.pdf_tex";
    rename("$name.pdf_tex", "$name.ptx");# or die "cannot move $name.pdf_tex";
  popd();
  $ret1 >>= 8; # reconstruct return value of the application 
  return $ret1;# or $ret2;
}


# graphics for xfig (not appropriate for mixed tex/pdf)

# add_cus_dep('fig', 'pdf', 0, 'fig2pdf');

# sub fig2pdf {
# system( "fig2dev -Lpdf \"$_[0].fig\" \"$_[0].pdf\"" );
# }

$main::makeindex = 'internal run_makeSplitindex %A %O';

# if used \sindex[idx]{} and no other index name, this is misleading: is a single multi-index
sub parseIdxFileForMultiIdx($fileName) {
  $fileName = "$fileName.idx";
  # since the patter is likely to end in $, we use single quotes here 
  my $patternMultiIndex = '${patternMultiIndex}';
  open my $info, $fileName or die "Could not open $fileName: $!";
  my $foundDefaultEntry = 0;
  my %res = ();
  while (my $line = <$info>) {
    if ($line =~ /$patternMultiIndex/) {
      # Here, it is clear that we have a multi-index 
      $res{$2} = 1;
    } else {
      $foundDefaultEntry = 1;
    }
  }

  if ($foundDefaultEntry && %res) {
    # Here, both \index and \sindex are used 
    $res{"idx"} = 1;
  }
  close $info;
  # Here, it is clear that we have no multi-index 
  return keys %res;
}

sub run_makeSplitindex($fileName, @opts) {
  # $fileName is without ending 

  my @indexLabels = parseIdxFileForMultiIdx($fileName);
  my $ret;
  if (@indexLabels) {
    # create dummy ind file 
    my $ind_fh = 'This is a dummy file. ';
    open($ind_fh, '>>', "$fileName.ind");
    close $ind_fh;

    foreach (@indexLabels) {
      # splitindex splits up the idx file into many 
      # and then generates ind file each 
      rdb_add_generated("$fileName-$_.idx", "$fileName-$_.ind");
    }

    $ret = system('${splitIndexCommand} --makeindex ${makeIndexCommand} ${splitIndexOptions} ' . 
          "$fileName " . '-- ${makeIndexOptions} ' . "@opts");
  } else {
    $ret = system('${makeIndexCommand} ${makeIndexOptions} ' . "@opts $fileName");
  }
  $ret >>= 8; # reconstruct return value of the application 
  return $ret
}

# This set of dependencies is only complete 
# if we restrict ourselves to types defined by options 
# without using \newglossary explicitly 
add_cus_dep( 'acn', 'acr', 0, 'run_makeglossaries' );
add_cus_dep( 'slo', 'sls', 0, 'run_makeglossaries' );
add_cus_dep( 'nlo', 'nls', 0, 'run_makeglossaries' );
#add_cus_dep( 'idx', 'ind', 0, 'run_makeglossaries' ); # would collide with indexing 
add_cus_dep( 'glo', 'gls', 0, 'run_makeglossaries' );
# TBD: add file endings for symbols, 
# not only here but also in the java code. 
push @main::generated_exts, 'glo', 'gls', 'glg';
push @main::generated_exts, 'acn', 'acr', 'alg';
push @main::generated_exts, 'slo', 'sls', 'slg';
push @main::generated_exts, 'nlo', 'nls', 'nlg';
# push @generated_exts, 'idx', 'ind', 'ilg'; # would collide with indexing 
push @main::generated_exts, "ist", "xdy"; # index stylefile created by the glossaries package 
# TBD: add xdy also in java code 

#$clean_ext .= " acr acn alg glo gls glg";# TBD: clarify: better in @generated_exts? 

sub run_makeglossaries($file) {
  my $options = '${makeGlossariesOptions}';
  if ($main::silent) {
    $options = "$options -q";
  }
  my $ret = system('${makeGlossariesCommand} ' . "$options $file");
  $ret >>= 8; # reconstruct return value of the application 
  return $ret;
}

# !!! ONLY WORKS WITH VERSION 4.54 or higher of latexmk
#TBD: take into account: modified:
#  '$_[0]'->

# #############
# # makeindex #
# #############
# @ist = glob("*.ist");
# if (scalar(@ist) > 0) {
#         $makeindex = "makeindex -s $ist[0] %O -o %D %S";
# }

# Implementing glossary with bib2gls and glossaries-extra, with the
#  log file (.glg) analyzed to get dependence on a .bib file.

# !!! ONLY WORKS WITH VERSION 4.54 or higher of latexmk

push @main::generated_exts, 'glg', '%R*.glstex';
# TBD: clarify 
#push @generated_exts, 'glg', '%R*.glstex';

# TBD: clarify treatment of encoding. 
# why we can avoid  
#        "--tex-encoding", "UTF-8",
#        "--log-encoding", "UTF-8",
# We need tex sources encoding in editor: utf8 
# in header 
# \iftutex%
#   \usepackage{fontspec}% sets utf8
# \else
#   % this seems to work with beamer also 
#   \usepackage[utf8]{inputenc}
#   \usepackage[T1]{fontenc}
# \fi
# in bib file: 1st line: 
# % Encoding: UTF-8


add_cus_dep('aux', 'glstex', 0, 'run_bib2gls');
# Explanation can be found in 
# https://tex.stackexchange.com/questions/400325/latexmkrc-for-bib2gls
sub run_bib2gls($file) {
  my $options = "--group";
  if ($main::silent) {
    $options = "--silent $options";
  }
  my $ret = system("bib2gls $options $file");
  $ret >>= 8; # reconstruct return value of the application 
  if ($ret) {
    warn "Run_bib2gls: Error, running bib2gls; return value $ret.\n";
    return $ret;
  }

  # my ($base, $path) = fileparse($file);
  # if ($path && -e "$base.glstex") {
  #   rename "$base.glstex", "$path$base.glstex";
  # }

  # Analyze log file to find the bib-files.
  my $glg= "$file.glg";
  my $isopen = open(my $glg_fh, '<', $glg);
  if (not $isopen) {
    warn "Run_bib2gls: Error opening log file '$glg'\n";
    return not $isopen;
  }
  rdb_add_generated($glg); 
 
  while (<$glg_fh>) {
    s/\s*$//;
    if (/^Reading\s+(.+)$/) {
      rdb_ensure_file($main::rule, $1);
    }
    if (/^Writing\s+(.+)$/) {
      rdb_add_generated($1);
    }
  }
  close $glg_fh;

  return $ret;
}

# The following code was developed out of a suggestion from John Collins 
# It is complementary to code in changes/PythonTeXdep
# This code shall not be erased, it may only be deactivated. 

push @main::generated_exts, "pytxcode", "plg";
push @main::generated_exts, "depytx", "%R.depytx.tex", "dplg";

push @main::generated_exts, '${prefixPytexOutFolder}%R/*', '${prefixPytexOutFolder}%R';
#$extra_rule_spec{'pythontex'}  = [ 'internal', '', 'mypythontex', "%Y%R.pytxcode", "%Y${prefixPytexOutFolder}-%R/%R.pytxmcr", "%R", 1 ];
$main::extra_rule_spec{'pythontex'} = [
  'internal', '', 'mypythontex', 
  "%R.pytxcode", '${prefixPytexOutFolder}%R/%R.pytxmcr', "%R", 1
];

# Explanation for PythonTeX dependency 
# can be found in changes/PythonTeXdep 
# In fact, to make this work, 
# the code provided there must be included in package pythontex
# TBD: this function is invoked based on global variables. 
# For me, this is quite ugly... no parameters 
sub mypythontex {
  my $prefixPytexOutFolder = '${prefixPytexOutFolder}';
  my $result_dir = "$main::aux_dir1$prefixPytexOutFolder$$main::Pbase";
  my $pythontex = '${getPythontexCommand()} ${pythontexOptions} %R';#'pythontexW %O %R';
  my $ret        = Run_subst($pythontex, 2);
  rdb_add_generated(glob "$result_dir/*");

  my $fh = FileHandle->new($$main::Pdest, "r");
  #open( my $fh, "<", $$Pdest );
  if ($fh) {
    #print "path: $ENV{PATH}";
    while (<$fh>) {
      if (/^%PythonTeX dependency:\s+'([^']+)';/) {
        print "Found pythontex dependency '$1'\n";
        rdb_ensure_file( $main::rule, $main::aux_dir1 . $1 );
      }
    }
    undef $fh;
  } else {
    warn "mypythontex: I could not read '$$main::Pdest'\n",
         "  to check dependencies\n";
  }
  return $ret;
}


# for htlatex 
push @main::generated_exts, "4tc", "4ct", "tmp", "xref", "css", "idv", "lg";
# TBD: for -C remove also html and xhtml
# TBD: check that this plugin also removes all these extensions.. think of lg. 


# biblatex
# push @generated_exts, "run.xml";# does run.xml work? 
# $clean_ext .= " %R-blx.bib";

sub run_preDecideCompilation($source, $target) {
  print("prior to decision whether compiling $source to $target needed\n");
  LatexHelpers::reset();
  LatexHelpers::parseTexFile($source, $target);
}

$main::compiling_cmd = "internal run_preDecideCompilation %T %D";

sub run_onSuccess($target) {
  print("Compilation succeeded without warning.\n");
  run_onSuccessWarn($target);
}

sub run_onWarn($target) {
  print("Compilation succeeded with warning(s).\n");
  run_onSuccessWarn($target);
}

sub run_onSuccessWarn($target) {
  # TBD: find out the cases where $target is empty 
  if ($target !~ m/.pdf$/) {
    print("created no pdf\n");
    return;
  }
  # currently, postprocessing occurs for pdf files only 


  my $ref = LatexHelpers::docMeta();

  if (!defined $ref) {
    print "no \\DocumentMetadata/SetKeys";
    return;
  }
  my %all = %$ref;
  print "All Metadata:\n";
  for my $k (keys %all) {
    print "  $k => $all{$k}\n";
  }
  # TBD: this is a bit too raw: not all standards are validated: PDF/X is not 
  return unless LatexHelpers::docMeta("pdfstandard");

  # Generalization needed for windows only 
  my ($bat, $cmd) = ("", "");
  if ($^O eq "Mswin32" ) {
    $bat=".bat";
    $cmd="cmd /c ";
  }
  my $verifyStdCommand = '${verifyStdCommand}';
  my $verifyStdOptions = '${verifyStdOptions}';
  my $verifyCmd = "$cmd$verifyStdCommand$bat";
  my $res = system("$verifyCmd $verifyStdOptions \"$target\"");
  $res >>= 8; # reconstruct return value of the application 
  print("$verifyStdCommand return value: $res\n");
  if ($res == 0) {
    print("Conformance as requested. \n");
  } else {
    print("Conformance ***not*** as requested. \n");
  }
}

$main::success_cmd="internal run_onSuccess %D";

$main::warning_cmd="internal run_onWarn %D";

$main::failure_cmd="echo '...compilation with failure'";
