# -*- cperl -*-
# ABSTRACT: NotesFactory

=head1 SYNOPSIS

Worker object to distill notes from the original Beamer TeX file.

=cut

package BeamerReveal::NotesFactory;
# VERSION

use strict;
use warnings;

use Carp;

use File::Which;
#use File::Path;

use Data::UUID;

use BeamerReveal::IPC::Run;
use IPC::Run qw(harness start pump finish); 

use BeamerReveal::Log;

sub nofdigits { length( "$_[0]" ) }

=method new()

  $nf = BeamerReveal::NotesFactory->new( $base, $presentationparameters $xres, $yres, $progressId );

=over 4

=item . C<$base>

the directory where the files that will be used by the reveal HTML file will be stored.

=item . C<$presentationparameters}

the presentation data that we need to determine the compiler used

=item . C<$xres>

the x-resolution of the canvas. This will determine the resolution at which the PDF will be converted to a bitmap file.

=item . C<$yres>

the x-resolution of the canvas. This will determine the resolution at which the PDF will be converted to a bitmap file.

=item . C<$progressId

the ID of the progress bar that displays the progress on screen.

=item . <$nf>

the notes factory

=back

=cut

sub new {
  my $class = shift;
  my ( $base, $pdf_dir, $presentationparameters, $xres, $yres, $progressId ) = @_;

  my $self = {
      base       => $base,
      pdf_dir    => $pdf_dir,
      presentationparameters => $presentationparameters,
      xres       => $xres,
      yres       => $yres,
      progressId => $progressId,
  };
  $class = (ref $class ? ref $class : $class );
  bless $self, $class;

  my $logger = $BeamerReveal::Log::logger;

  $self->{compiler} = File::Which::which( $self->{presentationparameters}->{compiler} )
      or $logger->fatal( "Error: your setup is incomplete, I cannot find your $self->{presentationparameters}->{compiler } compiler (should be part of your TeX installation)\n" .
			 "Make sure it is accessible in a directory on your PATH list variable\n" );
  
  
  $self->{pdftoppm} = File::Which::which( 'pdftoppm' )
    or $logger->fatal( "Error: your setup is incomplete, I cannot find pdftoppm (part of the poppler library)\n" .
	    "Install 'Poppler-utils' and make sure pdftoppm is accessible in a directory on your PATH list variable\n" );

  $self->{slides} = "$self->{base}/media/Slides";
  
  return $self;
}


=method $fc->toJPG()

Converts the presentation to one jpg file per frame. This is done at 3/4 of the canvas resolution.
The process goes in several steps

= over 4

=item . writing an altered source file

=item . compiling it

=item . converting it to jpg

=cut


sub toJPG {
  my $self = shift;

  my $logger = $BeamerReveal::Log::logger;

  # pdf generate of n slides, and jpeg generation of n slides
  $logger->progress( $self->{progressId},
		     0, "notes generation", 2 * $self->{presentationparameters}->{nofnotes}  );
  
  #############################
  # write altered source file
  
  # 1. read the source file
  $logger->log( 2, "- Reading LaTeX source file" );
  my $sourceFileName = $self->{presentationparameters}->{sourcefilename};
  my $source = do {
      local $/ = undef;
      open my $fh, "<". $sourceFileName
	  or $logger->fatal( "Error: could not open your LaTeX source file '$sourceFileName' for reading" );
      <$fh>;
  };

  # 2. alter it
  my $notesMagic = '';
  $source =~ s/\\begin\{document\}/\\setbeameroption\{show only notes\}\n\\begin\{document\}/;


  # 3. write it to a temporary file
  $logger->log( 2, "- Writing LaTeX notes file" );
  my $id = Data::UUID->new();
  my $notesFileName;
  do {
      my $uuid = $id->create();
      $uuid = $id->to_string( $uuid );
      $notesFileName = $sourceFileName;
      $notesFileName =~ s/(\.\w)/-notes-$uuid$1/;
  } until( ! -e $notesFileName );
  my $notesFile = IO::File->new();
  $notesFile->open( ">$notesFileName" )
      or $logger->fatal( "Error could not open notes file '$notesFileName' for writing" );
  print $notesFile $source;
  $notesFile->close();

  #############
  # compile it

  # 4. run TeX
  my $cmd = [ $self->{compiler},
	      "-halt-on-error", "-interaction=nonstopmode", "-output-directory=$self->{pdf_dir}", "$notesFileName" ];
  my $logFilename = $notesFileName;
  $logFilename =~ s/\.\w+$/.log/;


  
  my $counter = 0;
  my $progress = MCE::Shared::Scalar->new( 0 );
  BeamerReveal::IPC::Run::runsmart( $cmd, 1, qr/\[(\d+)\]/,
				    sub {
				      while( scalar @_ ) {
					my $a = shift @_;
					while( $a > $counter ) {
					  ++$counter;
					  $progress->incr();
					  $logger->progress( $self->{progressId},
							     $progress->get(), "pdf generation"  );
					}
				      }
				    },
				    1, # coreId
				    2, # indent
				    undef, # directory
				    "Error: notes generation failed: check $logFilename"
      );

  ####################
  # convert it to jpg
  $notesFileName =~ s/\.\w+$/.pdf/;
  $cmd = [ $self->{pdftoppm},
	   $notesFileName,
	   "$self->{slides}/notes",
	   '-jpeg',
	   '-jpegopt',
	   'optimize=y,quality=85',
	   '-scale-to-x', @{[1.5*$self->{xres}]},
	   '-scale-to-y', @{[1.5*$self->{yres}]},
	   '-progress',
	 ];
  BeamerReveal::IPC::Run::runsmart( $cmd, 2, qr/^(\d+) (\d+) .*$/,
				    sub {
					while( scalar @_ ) {
					    my ( $a, $b ) = ( shift @_, shift @_ );
					    $logger->progress( $self->{progressId},
							       $a, "note $1/$2", $b );
					}
				    },
				    0, # coreId
				    2, # indent
				    undef, # directory
				    "Error: notes conversion failed, is your notes PDF damaged?"
      );

  $notesFileName =~ s/\.\w+$//;
  foreach my $file ( glob( "$notesFileName*" ) ) {
      unlink $file;
  }
}

1;
