#!/usr/bin/env perl
my $version_banner = <<END;
epsffit 1.90
Copyright (c) Reuben Thomas 2016
Released under the GPL version 3, or (at your option) any later version.
END

use v5.10;
use warnings;
use strict;

use File::Basename;
use Getopt::Long;
use POSIX qw(round);
use List::Util qw(min);

use PSUtils;

my $prog = basename($0);
my ($help_flag, $version_flag, $center, $rotate, $aspect, $maximize, $showpage);

sub usage {
  my ($exit_code) = @_;
  print STDERR <<END;
$prog [OPTION...] LLX LLY URX URY [INFILE [OUTFILE]]
Fit EPSF file into constrained size.

  --center             center the image in the given bounding box
  --rotate             rotate the image by 90 degrees counter-clockwise
  --aspect             adjust the aspect ratio to fit the bounding box
  --maximize           rotate the image to fill more of the page if possible
  --showpage           append a /showpage to the file to force printing
  --help               display this help and exit
  --version            display version information and exit
END
  exit $exit_code;
}

# Get arguments
Getopt::Long::Configure("bundling");
# Having configured bundling, must give short option names explicitly
my $opts = GetOptions(
  "center|centre|c" => \$center,
  "rotate|r" => \$rotate,
  "aspect|a" => \$aspect,
  "maximize|maximise|m" => \$maximize,
  "showpage|s" => \$showpage,
  "help" => \$help_flag,
  "version" => \$version_flag,
 ) or usage(1);
if ($version_flag) {
  print STDERR $version_banner;
  exit 0;
}
usage(0) if $help_flag;
usage(1) if $#ARGV < 3 || $#ARGV > 5;

my $bbfound = 0;              # %%BoundingBox: found
my ($urx, $ury, $llx, $lly) = (0, 0, 0, 0);

my $fllx = singledimen(shift);
my $flly = singledimen(shift);
my $furx = singledimen(shift);
my $fury = singledimen(shift);

my ($infile, $outfile) = setup_input_and_output();

while (<$infile>) {
  if (/^%[%!]/) {
    # still in comment section
    if (/^%%BoundingBox:/) {
      if (/^%%BoundingBox: +([\d.]+) +([\d.]+) +([\d.]+) +([\d.]+)$/) {
        $bbfound = 1;
        $llx = round($1); # accept doubles, but convert to int
        $lly = round($2);
        $urx = round($3);
        $ury = round($4);
      }
    } elsif (/^%%EndComments/) {
      # don't repeat %%EndComments
      last;
    } else {
      print $outfile $_;
    }
  } else {
    last;
  }
}

die("no %%BoundingBox:") unless $bbfound;

# put BB, followed by scale & translate
my ($xoffset, $yoffset) = ($fllx, $flly);
my ($width, $height) = ($urx - $llx, $ury - $lly);

$rotate = 1 if $maximize &&
  (($width > $height && $fury - $flly > $furx - $fllx) ||
   ($width < $height && $fury - $flly < $furx - $fllx));

my ($fwidth, $fheight) = ($furx - $fllx, $fury - $flly);
($fwidth, $fheight) = ($fheight, $fwidth) if $rotate;

my ($xscale, $yscale) = ($fwidth / $width, $fheight / $height);

$xscale = $yscale = min($xscale, $yscale) if !$aspect; # preserve aspect ratio?
$width *= $xscale; # actual width and height after scaling
$height *= $yscale;
if ($center) {
   if ($rotate) {
      $xoffset += ($fheight - $height) / 2;
      $yoffset += ($fwidth - $width) / 2;
   } else {
      $xoffset += ($fwidth - $width) / 2;
      $yoffset += ($fheight - $height) / 2;
   }
}
say $outfile "%%BoundingBox: " . int($xoffset) . " " . int($yoffset) . " " .
  int($xoffset + ($rotate ? $height : $width)) . " " .
  int($yoffset + ($rotate ? $width : $height));
if ($rotate) { # compensate for original image shift
   $xoffset += $height + $lly * $yscale; # displacement for rotation
   $yoffset -= $llx * $xscale;
} else {
   $xoffset -= $llx * $xscale;
   $yoffset -= $lly * $yscale;
}
say $outfile "%%EndComments";
if ($showpage) {
  say $outfile "save /showpage{}def /copypage{}def /erasepage{}def";
} else {
  say $outfile "%%BeginProcSet: epsffit 1 0";
}
say $outfile "gsave " . (sprintf "%.3f %.3f translate", $xoffset, $yoffset);
say $outfile "90 rotate" if $rotate;
say $outfile (sprintf "%.3f %.3f scale", $xscale, $yscale);
say $outfile "%%EndProcSet" unless $showpage;
while (<$infile>) {
   print $outfile $_;
}
say $outfile "grestore";
say $outfile "restore showpage" if $showpage; # just in case

1; # exit with a true value (value of previous statement may be false)
