#!/bin/perl -w
#+
# osimglog -- generate logsheet data from image headers
#
# Purpose: 
#       Given a list of images, parse the image headers and print
#       out a formatted list of data.  With no arguments, parse all of
#       the images in the current directory.
#
# Usage:
#       osimglog [n | images]
# 
# Arguments:
#       n       = number of latest images to parse.
#       images  = names of images to parse.  If no images are listed,
#                       then all images in the current directory will be read
#                       (EXCEPT for backup.fits).
# 
# Output:
#       to STDOUT
# 
# Restrictions
#       None
# 
# Note:
#       The output from this program is extra wide.     To print it, use
#       this command:
#               enscript -1r -c -f Courier9 -P lw4s
# 
# Exit values:
#        0 = normal completion
#        1 = wrong number of arguments
#
# Example:
#       1) Generate log data for all images in the current directory:
#               osimglog
# 
#       ) Generate log data for the last 5 images in the current directory:
#               osimglog 5
# 
#       3) Generate log data for all images in the directory
#       /s/sdata1001/deimos1/2003jan01: 
#               osimglog /s/sdata1001/deimos1/2003jan01/*.fits
#-
# Modification history:
#       2002-Dec-30     GDW     Original version (deeplog)
#       2003-Aug-27     GDW     Changed TTIME to EXPTIME
#       2004-Oct-10     GDW     Added "last n images" option
#	2004-Nov-09	jlyke	Adapted for NIRSPEC use (nspeclog)
#       2005-Sep-09     jlyke   Adapted for NIRC2 use (nirc2log)
#       2005-Oct-18     jlyke   Adapted for OSIRIS imager use (osimglog)
#-----------------------------------------------------------------------

use File::Basename;

# declarations...
$| = 1;
my( $observers, $date, $directory);
my( @images);
my( $i, $j);
my( $m, $n, $title_format);
my( %HeadValue);
my( $null) = 'INDEF';

# define logsheet fields...
&AddColumn( 'DATAFILE',  'File', '%-15s ');
&AddColumn( 'OBJECT', 'Object', '%-17s ');
&AddColumn( 'UTC', 'UTC', '%-12s ');
&AddColumn( 'AIRMASS',  '  AM', '%5.2f ');
&AddColumn( 'ITIME',  'Tint', '%7.2f ');
&AddColumn( 'COADDS', 'Coadd', '%5s ');
&AddColumn( 'IF1NAME',    'Filter', '%-4s ');
&AddColumn( 'IF2NAME',    '', '%-4s ');
&AddColumn( 'PONAME','PO', '%6s ');
&AddColumn( 'PA_IMAG','PA', '%5.1f ');
&AddColumn( 'LSPROP', 'Laser', '%5s ');
&AddColumn( 'WSFRRT',  'WFS Rate', '%8.2f ');
&AddColumn( 'ISSKY', 'Sky', '%4s ');

# check args...
die "Usage: $0 [images]\n" if ( @ARGV < 0 );

# build default image list...
@images = glob("*.fits*");

# expunge bad filenames from image list.
# NOTE: that we traverse the list BACKWARDS because we are removing elements from the list as we go...
for ( $i=@images-1 ; $i>=0 ; $i--){
  if( ($images[$i] =~ m/backup.fits/) or        # remove backup files
      ($images[$i] =~ m/^cam/) or               # remove cam files
      not ($images[$i] =~ m/.fits$/ or $images[$i] =~ m/.fits.gz$/)){
    splice( @images, $i, 1) 
    }
}

# sort images by dataset number
# format is syymmdd_s001002.fits where "001" is the dataset number
for ( $i=0 ; $i < @images ; $i++){
    $images[$i] =~ m/^.*_.(\d\d\d).*$/;
    $setnum[$i] = $1;
    $dataset{$images[$i]} = $setnum[$i];	
}
@images = sort bysetnum @images;

# parse args...
if ( @ARGV == 1 and $ARGV[0] =~ /^\d+$/ ) {
  $m = $ARGV[0];
  if ( $m > @images ) { $m = scalar(@images) };
  $m = -$m;
  @images = @images[ $m .. -1 ];        # extract last $m elements of image list
} elsif ( @ARGV > 0 ) {
  @images = @ARGV;
}

# verify number of images...
die "ERROR: No images found\n" 
  unless @images;

# get some information from the first OSIRIS imager image...
#for( $i=0 ; $i < @images ; $i++){
#  %HeadValue = &GetFitsHead( $images[$i]);
#  last if (defined($HeadValue{'CURRINST'})
#           and $HeadValue{'CURRINST'} =~ m/^OSIRIS/)
#}
#die "ERROR: No OSIRIS imager images found\n" 
#  unless $HeadValue{'CURRINST'} =~ m/^OSIRIS/;

# print header...
printf "\n";

printf "%-72s", "Project:";
printf "UT Date: %s", &BlankIfUndef($HeadValue{"DATE-OBS"});
printf "\n";

printf "%-72s", "Observers: " . &BlankIfUndef($HeadValue{"OBSERVER"});
printf "Weather:";
printf "\n";

printf "%-72s", "Data directory: " . &BlankIfUndef($HeadValue{"OUTDIR"});
printf "Seeing:";
printf "\n";

printf "\n";

$line = '';
for ( $i=0 ; $i<@X::keyword ; $i++ ) {
  $X::format[$i] =~ m/^%-?(\d+)/;
  $n = $1;
  $X::format[$i] =~ m/(\s+)$/;
  $space = $1;
  $buf = sprintf "%-${n}s$space", $X::title[$i];
  print $buf;
  $buf =~ s/./_/g;
  $line .= $buf;
}
printf "\n";
printf "$line\n";

# loop over images...
for ( $j=0 ; $j<@images ; $j++ ) {

  # read image header...
  %HeadValue = &GetFitsHead( $images[$j]);

  # skip non-OSIRIS images...
#  next unless (defined($HeadValue{'CURRINST'})
#               and $HeadValue{'CURRINST'} =~ m/^OSIRIS/);

  # build filename field...
  $HeadValue{'DATAFILE'} = (fileparse( $images[$j], '\..*'))[0];

  # fix grating/wavelength fields...
  if ( not defined $HeadValue{'GRATEPOS'}) {
    undef $HeadValue{'WAVELEN'}
  } elsif ($HeadValue{'GRATEPOS'} eq '3' ){
    $HeadValue{'WAVELEN'} = $HeadValue{'G3TLTWAV'}
  } elsif ( $HeadValue{'GRATEPOS'} eq '4' ){
    $HeadValue{'WAVELEN'} = $HeadValue{'G4TLTWAV'}
  } else {
    $HeadValue{'WAVELEN'} = $null;
  }

  # fix lamps...
  if ( defined $HeadValue{'LAMPS'} ){
    $HeadValue{'LAMPS'} =~ s/ //g; # trim blanks from lamps...
    if ( $HeadValue{'LAMPS'} =~ m/^off/i ){$HeadValue{'LAMPS'} = ""}
    if ( defined $HeadValue{'FLIMAGIN'} and 
         $HeadValue{'FLIMAGIN'} !~ m/^off/i ){
      $HeadValue{'LAMPS'} .= "Dome/Im"
    }
    if ( defined $HeadValue{'FLSPECTR'} and 
         $HeadValue{'FLSPECTR'} !~ m/^off/i ){
      $HeadValue{'LAMPS'} .= "Dome/Sp"
    }
  }

  # print results...
  for ( $i=0 ; $i<@X::keyword ; $i++ ) {
    if ( defined $HeadValue{$X::keyword[$i]} and 
         $HeadValue{$X::keyword[$i]} ne $null ){
      $HeadValue{$X::keyword[$i]} =~ s/^\s+//; # remove leading whitespace
      $HeadValue{$X::keyword[$i]} =~ s/\s+$//; # remove trailing whitespace
      printf $X::format[$i], $HeadValue{$X::keyword[$i]}
    } else {
      $X::format[$i] =~ m/^%-?(\d+)/;
      $n = $1;
      if ( not defined $HeadValue{$X::keyword[$i]}){
        $buf = '?'
      } else {
        $buf = ''
      }
      printf "%-${n}s ", $buf;
    }
  }
  printf "\n";
}


#-----------------------------------------------------------------------
sub GetFitsHead {
#-----------------------------------------------------------------------
  
  # get file name to read header from
  my $infile = shift;
  my( $excess, $comment);
  
  # reset output hashes to null
  my %HeadValue = ();
  my %HeadComment = ();
  
  # open the file with a shared lock to prevent it being modified 
  # during reading...
  open TEST, "<$infile";
  flock TEST, 1;
  
  # open input file using appropriate method...
  if ($infile =~ /\.gz$/i) {
    open INFITS, "gunzip --stdout $infile |";
    $| = 1;     # enable autoflush on gunzip output
  } else {
    open INFITS, $infile;
  }  

  # initialize input variable to allow for end-of-header trapping
  $headline = "     ";
  
  # loop thru FITS file 80 bytes at a time until end-of-header mark found
  until (substr($headline,0,3) eq "END") {
    read INFITS, $headline, 80
      or die "unexpected end of file on read";
    chomp($headline);

    # identify keyword name from first 8 bytes
    $name = substr($headline, 0, 8);
    $rest = substr($headline,9);

    # strip extra spaces off of keyword names
    $name =~ s/\s//g;

    # test if value is a string, handle single quotes if it is
    if (substr($rest,0,2) eq " '") {
      $lastquote = index($rest, "'", 2);
      $value = substr($rest,2,$lastquote-2);
      ($excess, $comment) = split (/\//, substr($rest, $lastquote));

    } else {
      # otherwise split value from comment using / separator
      ($value, $comment) = split (/\//, $rest);
      $value =~ s/\s//g;
    }

    # add next value and comment to respective hashes
    unless ($name eq "END" or $name eq "") {
      $HeadValue{$name} = $value;
      $HeadComment{$name} = $comment;
    }
  }
  
  # close input FITS file
  close INFITS;
  close TEST;
  return %HeadValue;
}

#-----------------------------------------------------------------------
sub AddColumn {
#-----------------------------------------------------------------------
  my( $keyword, $title, $format) = @_;
  push( @X::keyword, $keyword);
  push( @X::title, $title);
  push( @X::format, $format);
}

#-----------------------------------------------------------------------
sub BlankIfUndef {
#-----------------------------------------------------------------------
  my( $value) = @_;
  if( defined $value){
    return $value
  } else {
    return ''
  }
}

#-----------------------------------------------------------------------
sub bysetnum {
#-----------------------------------------------------------------------
    $dataset{$a} <=> $dataset{$b};
}