#!/usr/bin/perl

use strict;
use POSIX;

#  Animates graph of lineshape data.
my $data_file = 'sample.xdist.txt';
my $master_file = 'graph_template.eps';
my $file_stem = 'sample.xdist';
my $nfade = 0; # number of transition frames between different alphas
my $nsame = 1; # number of frames to stay static between transitions
my $tlabel = ''; # label to append after each time
my $delay = 0.08; # delay between frames, in seconds

my $pi = 4.0*atan2(1.0,1.0);
my $xmin = -6.4;
my $xmax =  6.4;


### get bounding box for frame conversion
my $size_x = 72*8.5;
my $size_y = 72*11;
my ($cmd);
die ("Error: cannot open file $master_file for input") unless  
  open (masterfile, "<$master_file");  
while(<masterfile>) {  
  if (/^%%BoundingBox:\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)/) {
    $size_x = $3-$1;   
    $size_y = $4-$2; 
  }
}
close masterfile;


### load distribution data (first line of file contains x-axis, rest are data)
print STDERR "Loading data...\n";
my (@data_arr, @t, $row, $col, $numrows, $numcols);
my $data_max = 0;
die ("Error: cannot open file $data_file") unless
  open (file, "<$data_file");

# Read and parse first line from file
die("File '$data_file' contains no lines!") unless
  ($_ = <file>);
m/((\S+))/g;
$row = 0;
$col = 0;
$t[$row] = $1;
while(m/[\t\s*|\s+]((\S+))/g) {
  $data_arr[$row][$col] = $1;
  $col++;
}
$numcols = $col;
$row++;

# Loop through file
while(<file>) {
  if (! m/^\s*$/) {
    m/((\S+))/g;
    $t[$row] = $1;
    for ($col = 0; $col < $numcols; $col++) {
      m/[\t\s*|\s+]((\S+))/g;
      $data_arr[$row][$col] = $1;
      if ($1 > $data_max) {$data_max = $1;}
    }
    $row++;
  }
}

$data_max = $data_max*1.05;
$numrows = $row;
close file;



### convert eps to gif
my ($j, $k, $master_file_temp, $master_file_gif, @master_gif_array);
my ($master_file_biggif);
# find boundaries for plotting
my $xilo = 0;
my $xihi = $numcols-1;
for ($k = 1; $k < $numcols; $k++) {
  if ( $data_arr[0][$k-1]<$xmin && $data_arr[0][$k]>=$xmin ) { $xilo = $k; }
  if ( $data_arr[0][$k-1]<=$xmax && $data_arr[0][$k]>$xmax ) { $xihi = $k-1; }
}
for ($j = 1; $j < $numrows; $j++) {
  print STDERR "Creating basis frame $j of $numrows...\n";
  $master_file_temp = $file_stem . ".$j.temp.eps";
  $master_file_biggif = $file_stem . ".$j.big.gif";
  $master_file_gif = $file_stem . ".$j.gif";
  push @master_gif_array, $master_file_gif;

  # make patches to eps file
  die ("Error: cannot open file $master_file_temp for output") unless
    open (temp, ">$master_file_temp");
  die ("Error: cannot open file $master_file for input") unless
    open (master, "<$master_file");
  while(<master>) {
    if (/^%%%%%%%%%%perl_binding_point_1/) {
      print temp;
      print  temp "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
      print  temp "% This code block inserted by animation utility         %\n";
      print  temp "%   (nothing special to see here)                       %\n";
      print  temp "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
    } elsif (/^%%%%%%%%%%perl_binding_point_2/) {
      print temp;
      print  temp "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
      print  temp "% This code block inserted by animation utility         %\n";
      printf temp "  /tstr (%.2f$tlabel) def\n", $t[$j];
      print  temp "  /npoints $xihi $xilo sub 1 add def\n";
      for ($k = $xilo; $k <= $xihi; $k++) {
       print temp ($data_arr[0][$k] - $xmin) / ($xmax - $xmin);
       print temp "  ";
       print temp $data_arr[$j][$k] / $data_max;
       print temp "\n";
      }
      print  temp "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n";
    } else {
      print temp;
    }
  }
  close master;
  close temp;

  ### convert frame to gif (do at high density first for better antialiasing)
  my $cmd = "convert -antialias -density 144x144" . 
     " $master_file_temp " . "$master_file_biggif";
  print STDERR "$cmd\n\n";
  system($cmd);
  unlink $master_file_temp;

  my $cmd = "convert -resize " . $size_x . 'x' . $size_y . 
     " $master_file_biggif " . "$master_file_gif";
  print STDERR "$cmd\n\n";
  system($cmd);
  unlink $master_file_biggif;
}

### loop over frames
my ($j, $k, $l, $cur_frame, @frame_array, $frame_name, $nframes);
$cur_frame = 0;
$nframes = $nsame * ($#master_gif_array + 1) + $nfade * $#master_gif_array;

# first do initial stationary frames
for ($k = 1; $k <= $nsame; $k++) {
  $cur_frame++;
  print STDERR "Creating frame $cur_frame of $nframes...\n";
  $frame_name = "$file_stem.frame.$cur_frame.gif";
  push @frame_array, $frame_name;
  my $cmd = "cp $master_gif_array[0] $frame_name";
  print STDERR "$cmd\n\n";
  system($cmd);
}

# loop over the rest of the master files
for ($j = 1; $j <= $#master_gif_array; $j++) {
  # transition
  for ($k = 1; $k <= $nfade; $k++) {
    $cur_frame++;
    print STDERR "Creating frame $cur_frame of $nframes...\n";
    $frame_name = "$file_stem.frame.$cur_frame.gif";
    push @frame_array, $frame_name;
    my $cmd = "convert -average ";
    for ($l = $k; $l <= $nfade; $l++) {$cmd .= $master_gif_array[$j-1] . ' ';}
    for ($l = 1; $l <= $k; $l++) {$cmd .= $master_gif_array[$j] . ' ';}
    $cmd .= $frame_name;
    print STDERR "$cmd\n\n";
    system($cmd);
  }
  # hold on pure frame
  for ($k = 1; $k <= $nsame; $k++) {
    $cur_frame++;
    print STDERR "Creating frame $cur_frame of $nframes...\n";
    $frame_name = "$file_stem.frame.$cur_frame.gif";
    push @frame_array, $frame_name;
    my $cmd = "cp $master_gif_array[$j] $frame_name";
    print STDERR "$cmd\n\n";
    system($cmd);
  }
}
  

### combine frames into movie
my $gifsicle = sprintf('gifsicle -O2 --colors 256 --no-loopcount -d %d', $delay*100);
$gifsicle .= ' ';
$gifsicle .= (join ' ', @frame_array);
$gifsicle .= " > $file_stem" . '.gif';
print STDERR "\n$gifsicle\n\n";
system($gifsicle);

### clean up all frames, regenerate the first
unlink @frame_array;
unlink @master_gif_array;
my $frame_name_gif = $file_stem . '.frame.' . 1 . '.gif';
$gifsicle = "gifsicle $file_stem.gif '#0' > $frame_name_gif";
print STDERR "\n$gifsicle\n\n";
system($gifsicle);


