#!/usr/bin/env perl

# Read and parse a fits table containing a MOPS_DETECTABILITY_QUERY Extension
# and optionally print out the contents

# by default prints out the keywords in the exension header followed by the rows of the table
# with labels
# -l omits the labels
# -h omits the header
# -r omits the rows
# so -lhr will print nothing

use warnings;
use strict;

use Astro::FITS::CFITSIO qw( :constants );
Astro::FITS::CFITSIO::PerlyUnpacking(1);
use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
use Pod::Usage qw( pod2usage );
use Math::Trig;
use Data::Dumper;

use constant EXTNAME => 'MOPS_DETECTABILITY_QUERY'; # Extension name for table

my $no_print_label  = 0;    # omit the labels
my $no_print_header = 0;    # omit the header keywords
my $no_print_rows   = 0;    # omit the rows
my $version = 0;

my ( $input,			# Name of input text file
     $output,			# Name of output table
     $save_temps,		# Save temporary files?
     );

GetOptions(
	   'input|i=s'    => \$input,
	   'output|o=s'   => \$output,
           'nolabel|l'    => \$no_print_label,
           'noheader|h'   => \$no_print_header,
           'norows|r'     => \$no_print_rows
) or pod2usage( 2 );

pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
pod2usage( -msg => "Required options: --input",
           -exitval => 3) unless defined $input;

if ($output && ($output ne "-")) {
    die "cannot open $output for output\n" unless open OUTFILE, ">$output";
    select OUTFILE;
}

my $status = 0;

# Read the input file

my $inFits = Astro::FITS::CFITSIO::open_file( $input, READONLY, $status ); # FITS file handle
check_fitsio($status);

$inFits->movnam_hdu(BINARY_TBL, EXTNAME, 0, $status) and check_fitsio($status);

my $inHeader = $inFits->read_header(); # Header for input

my $numRows;			# Number of rows in table
$inFits->get_num_rows($numRows, $status) and check_fitsio($status);

# The keywords found in the header
# my $header = {
#         'EXTVER'   => { name => 'EXTVER',
# 		       writetype => TSTRING,
# 		       comment => 'Extension version',
# 		       value => undef
#                       },
#         'EXTNAME'  => { name => 'EXTNAME',
# 		       writetype => TSTRING,
# 		       comment => 'name of this binary table extension',
# 	  	       value => undef
# 		      },
#         'QUERY_ID' => { name => 'QUERY_ID', 
#                         writetype => TSTRING, 
#                         comment => 'MOPS Query ID for this batch query',
#                         value => undef
#                       },
#         'FPA_ID'   => { name => 'FPA_ID', 
#                         writetype => TSTRING, 
#                         comment => 'orginal FPA_ID used at ingest',
#                         value => undef
#                       }, 
#         'MJD_OBS'  => { name => 'MJD-OBS', 
#                         writetype => TDOUBLE, 
#                         comment => 'starting time of the exposure, MJD',
#                         value => undef
#                       },
#         'FILTER'   => { name => 'FILTER', 
#                         writetype => TSTRING, 
#                         comment => 'effective filter use for the exposure',
#                         value => undef
#                       },
#         'OBSCODE'  => { name => 'OBSCODE', 
#                         writetype => TSTRING, 
#                         comment => 'site identifier (MPC observatory code)',
#                         value => undef
#                       },
#  	'STAGE'    => { 
# 	                name => 'STAGE',
# 			writetype => TSTRING,
# 			comment => 'processing stage to examine',
# 			value => undef
# 	              }
# };

my $parse_error = 0;
# Parse the header to determine what we expect to find.
foreach my $header_key (keys %{ $inHeader }) {
    $inHeader->{$header_key} =~ s/\s+//g;
    $inHeader->{$header_key} =~ s/\'//g;
}
my ($EXTVER,$headerEXTNAME,$QUERY_ID,$FPA_ID,$MJD_OBS,$FILTER,$OBSCODE,$STAGE) = 
    ($inHeader->{EXTVER},$inHeader->{EXTNAME},$inHeader->{QUERY_ID},$inHeader->{FPA_ID},
     $inHeader->{'MJD-OBS'},$inHeader->{FILTER},$inHeader->{OBSCODE},$inHeader->{STAGE});
unless(defined($EXTVER) && defined($headerEXTNAME) &&
       (($EXTVER == 1)||($EXTVER == 2)) && 
       ($headerEXTNAME eq EXTNAME)) {
    $parse_error = 1;
}
unless(($EXTVER == 2)||
       ((defined($QUERY_ID))&&(defined($FPA_ID))&&(defined($MJD_OBS))&&
	(defined($FILTER))&&(defined($OBSCODE)))) {
    $parse_error = 2;
}

# Specification of columns
my $column_defs = [ 
        # matching rownum from detectability original request
        { name => 'ROWNUM',   type => '20A', writetype => TSTRING, version => 1 }, 
        # coordinate at start of exposure, in degrees
        { name => 'RA1_DEG',  type => 'D',   writetype => TDOUBLE, version => 1 },
        # coordinate at start of exposure, in degrees
        { name => 'DEC1_DEG', type => 'D',   writetype => TDOUBLE, version => 1 },
        # coordinate at end of exposure, in degrees
        { name => 'RA2_DEG',  type => 'D',   writetype => TDOUBLE, version => 1 },
        # coordinate at end of exposure, in degrees
        { name => 'DEC2_DEG', type => 'D',   writetype => TDOUBLE, version => 1 },
        # apparent magnitude
        { name => 'MAG',      type => 'D',   writetype => TDOUBLE, version => 1 },
    # v2 query_id: MOPS query ID for this batch query
    { name => 'QUERY_ID', type => '20A', writetype => TSTRING, version => 2, default => $QUERY_ID },
    # v2 fpa_id: original FPA_ID used at ingest
    { name => 'FPA_ID', type => '20A', writetype => TSTRING, version => 2, default => $FPA_ID },
    # v2 mjd obs: starting time of the exposure, MJD
    { name => 'MJD-OBS', type => 'D', writetype => TDOUBLE, version => 2, default => $MJD_OBS },
    # v2 filter: effective filter used for the exposure as a string, allowed values of g, r, i, z, y, B, V, w
    { name => 'FILTER', type => '3A', writetype => TSTRING, version => 2, default => $FILTER },
    # v2 obscode: site identifier (MPC observatory code)
    { name => 'OBSCODE', type => '3A', writetype => TSTRING, version => 2, default => $OBSCODE },
    # v2 stage: stage name to perform query on, allowed values of 'chip', 'warp', 'stack', and 'diff'
    { name => 'STAGE', type => '20A', writetype => TSTRING, version => 2, default => $STAGE },
];

# Parse the list of columns
my @colNames;			# Names of columns
my @colTypes;			# Types of columns
my @colWriteType;               # type to use to write
my %colData;			# Data for each column referenced by name
foreach my $colSpec ( @$column_defs) {
    push @colNames, $colSpec->{name};
    push @colTypes, $colSpec->{type};
    push @colWriteType, $colSpec->{writetype};
}

foreach my $col (@$column_defs) {
    my ($col_num, $col_type, $col_data);

    if ($col->{version} > $EXTVER) {
	@{ $colData{$col->{name}} } = map { $col->{default} } (0 .. $numRows);
	next;
    }
    $inFits->get_colnum(0, $col->{name}, $col_num, $status) and check_fitsio($status);
    $inFits->get_coltype($col_num, $col_type, undef, undef, $status) and check_fitsio($status);
    $inFits->read_col($col_type, $col_num, 1, 1, $numRows, 0, $col_data, undef, $status)
                                                                    and check_fitsio($status);
    $colData{$col->{name}} = $col_data;
    if ($col->{name} eq 'MJD-OBS') {
	print @{ $col_data } . "\n";
    }
}

# Verify uniqueness of important columns:
my @unique_fields = ('QUERY_ID','OBSCODE','STAGE');
foreach my $colName (@unique_fields) {
    my %counter = ();
    foreach my $row (@{ $colData{$colName} }) {
	$counter{$row} = 1;
    }
    if (scalar(keys(%counter)) != 1) {
	$parse_error = 3;
    }
}
if ($parse_error) {
    die "Unable to parse detectability query: $parse_error " . &error_message($parse_error) . "\n";;
}

# # Now produce the output


if (!$no_print_label) {
    print "# ";
    foreach my $col (@$column_defs) {
	printf "%-12s ", $col->{name};
    }
    print "\n";
}

for (my $i = 0; $i < $numRows; $i++) {
    foreach my $col (@$column_defs) {
	printf "%-12s ", $colData{$col->{name}}->[$i];
        #foreach my $aref (@col_arrays) {
	#printf "%-12s ", $aref->[$i];
    }
    print "\n";
}

exit 0;

### Pau.

# From Astro::FITS::CFITSIO demo
sub check_fitsio
{
    my $status = shift;		# Status of FITSIO calls

    if ($status != 0) {
	my $msg;		# Message to output
	Astro::FITS::CFITSIO::fits_get_errstatus( $status , $msg );
	die "CFITSIO error: $msg\n";
    }
}

sub error_message {
    my $error = shift;
    if ($error == 1) {
	return("Unknown EXTVER/EXTNAME");
    }
    if ($error == 2) {
	return("Required header field not found");
    }
    if ($error == 3) {
	return("Unique column not uniquely specified");
    }
    else {
	return("Unknown fault.");
    }
}



__END__
