# -*- mode: Perl -*-
# /=====================================================================\ #
# |  psfrag                                                             | #
# | 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.     | #
# |---------------------------------------------------------------------| #
# | 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;
use LaTeXML::Util::Image;

#======================================================================
# Would be lovely to overlay SVG, MathML, Images etc
# but kinda impractical to hope to align things the same way as LaTeX would.
# So, we just punt all of it to LaTeX to create a composite image

# Store fragments for later use
AssignValue(saved_psfragments => Tokens());
AssignValue(psfrag_scan_all   => LookupValue('2.09_COMPATIBILITY'));
AssignValue(psfrag_scan       => 0);
DeclareOption('209mode', sub { AssignValue(psfrag_scan_all => 1); });
DeclareOption('2emode',  sub { AssignValue(psfrag_scan_all => 0); });
DeclareOption('scanall', sub { AssignValue(psfrag_scan_all => 1); });

ProcessOptions();

sub save_psfrag {
  my (@stuff) = @_;
  return unless @stuff;
  # NOT global!!!  And defer expansion of the leading CS
  AssignValue(saved_psfragments =>
      Tokens(LookupValue('saved_psfragments')->unlist, T_CS('\noexpand'), @stuff));
  return; }

sub unsave_psfrag {
  return Tokens(Digest(LookupValue('saved_psfragments'))->revert); }

# NOT a constructor since probably args should not be digested yet(?)
DefPrimitive('\psfrag OptionalMatch:* Semiverbatim [][][][]{}', sub {
    my ($stomach, $star, $a, $b, $c, $d, $e, $f) = @_;
    # Guard against empty $$ argument.
    my @argt = $f->unlist;
    if ((scalar(@argt) == 2) && ($argt[0][1] == CC_MATH) && ($argt[1][1] == CC_MATH)) {
      $f = Tokens(); }
    save_psfrag(Invocation(T_CS('\lx@delayed@psfrag'), $star, $a, $b, $c, $d, $e, $f));
    return; });
DefConstructor('\lx@delayed@psfrag OptionalMatch:* Semiverbatim [][][][]{}', '',
  alias => '\psfrag');

DefConstructor('\psfragscanon', '',
  afterDigest => sub {
    save_psfrag(T_CS('\psfragscanon'));
    AssignValue(psfrag_scan => 1); });
DefConstructor('\psfragscanoff', '',
  afterDigest => sub {
    save_psfrag(T_CS('\psfragscanoff'));
    AssignValue(psfrag_scan => 0); });

# AVOID using ltx:picture instead of ltx:graphic
# unless there actually are some psfrags defined, OR embedded fragments was explicitly enabled.
# (faster, probably more reliable image conversion)
sub psfrag_requirepicture {
  my (@candidates) = @_;
  my $have_ps = 0;
  if (scalar(@candidates) == 1) {
    my $type = image_type(pathname_absolute($candidates[0], LookupValue('SOURCEDIRECTORY')));
    $have_ps = ($type eq 'ps') || ($type eq 'eps'); }
  my $have_frags = scalar(LookupValue('saved_psfragments')->unlist);
  my $scan_on    = LookupValue('psfrag_scan') || LookupValue('psfrag_scan_all');
  return $have_ps && ($have_frags || $scan_on); }

# For graphics version of \includegraphics
DefConstructor('\lx@psfrag@includegraphics OptionalMatch:* [][] Semiverbatim',
  "?#pic(<ltx:picture width='#width' height='#height' unitlength='#unitlength' tex='#tex'/>)"
    . "(<ltx:graphics graphic='#path' candidates='#candidates' options='#options'/>)",
  alias      => '\includegraphics',
  sizer      => \&image_graphicx_sizer,
  properties => sub {
    my ($stomach, $starred, $op1, $op2, $graphic) = @_;
    my $options = graphicS_options($starred, $op1, $op2);
    my ($path, @candidates) = image_candidates(ToString($graphic));
    my $ifpicture = psfrag_requirepicture(@candidates);
    (graphic => $path,
      candidates => join(',', @candidates),
      options    => $options,
      pic        => $ifpicture); },
  afterDigest => sub {
    my ($stomach, $whatsit) = @_;
    my ($w, $h, $d) = $whatsit->getSize;
    AssignValue(psfrag_scan => 0, 'global');
    my $untex = UnTeX(Tokens(unsave_psfrag(), $whatsit->revert), 1);
    $whatsit->setProperties(tex => $untex,
      width => $w, height => $h, depth => $d); });

# For graphicx version of \includegraphics
DefConstructor('\lx@psfrag@includegraphicx OptionalMatch:* OptionalKeyVals:Gin Semiverbatim',
  "?#pic(<ltx:picture width='#width' height='#height' unitlength='#unitlength' tex='#tex'/>)"
    . "(<ltx:graphics graphic='#path' candidates='#candidates' options='#options'/>)",
  alias      => '\includegraphics',
  sizer      => \&image_graphicx_sizer,
  properties => sub {
    my ($stomach, $starred, $kv, $graphic) = @_;
    my $options = graphicX_options($starred, $kv);
    my ($path, @candidates) = image_candidates(ToString($graphic));
    my $ifpicture = psfrag_requirepicture(@candidates);
    (path => $path,
      candidates => join(',', @candidates),
      options    => $options,
      pic        => $ifpicture); },
  afterDigest => sub {
    my ($stomach, $whatsit) = @_;
    my ($w, $h, $d) = $whatsit->getSize;
    AssignValue(psfrag_scan => 0, 'global');
    my $untex = UnTeX(Tokens(unsave_psfrag(), $whatsit->revert), 1);
    $whatsit->setProperties(tex => $untex,
      width => $w, height => $h, depth => $d); });

DefConstructor('\lx@psfrag@epsfbox[] Semiverbatim',
  "?#pic(<ltx:picture width='#width' height='#height' unitlength='#unitlength' tex='#tex'/>)"
    . "(<ltx:graphics graphic='#path' candidates='#candidates' options='#options'/>)",
  alias      => '\epsfbox',
  sizer      => \&image_graphicx_sizer,
  properties => sub {
    my ($stomach, $bb, $graphic) = @_;
    my $clip    = LookupValue('epsf_clip');
    my $options = ($clip ? ($bb ? "viewport=$bb, clip" : "clip") : '');
    my ($path, @candidates) = image_candidates(ToString($graphic));
    my $ifpicture = psfrag_requirepicture(@candidates);
    (graphic => $path,
      candidates => join(',', @candidates),
      options    => $options,
      pic        => $ifpicture); },
  afterDigest => sub {
    my ($stomach, $whatsit) = @_;
    my ($w, $h, $d) = $whatsit->getSize;
    AssignValue(psfrag_scan => 0, 'global');
    my $untex = UnTeX(Tokens(unsave_psfrag(), $whatsit->revert), 1);
    $whatsit->setProperties(tex => $untex,
      width => $w, height => $h, depth => $d); });

# Just for grouping
DefEnvironment('{psfrags}', '#body');

# Note that if psfrag is loaded, ANY eps figure may have embedded TeX
# that needs to be processed by LaTeX, so really needs to end up as ltx:picture
AtBeginDocument(<<'EoTeX');
\@ifundefined{@includegraphics}{}{
\global\let\lx@orig@includegraphics\@includegraphics
\global\let\@includegraphics\lx@psfrag@includegraphics}
\@ifundefined{@includegraphicx}{}{
\global\let\lx@orig@includegraphicx\@includegraphicx
\global\let\@includegraphicx\lx@psfrag@includegraphicx}
\@ifundefined{epsfbox}{}{
\global\let\lx@orig@epsfbox\epsfbox
\global\let\epsfbox\lx@psfrag@epsfbox}
EoTeX

#**********************************************************************
1;
