#!/usr/bin/env perl

use strict;
use warnings;

# given an RA and DEC or a skycell_id find the LAP stack images containing them
# and display using ds9

# XXX: consider accepting a string of parameters to be passed to ds9
# add --fit set ds9 to fit to frame
# XXX if label is supplied by the user and it is like MD% 
# guess at the tess_id
# allow mask and variance images to be displayed as well

my $label   = 'LAP.ThreePi.20110809';
my $tess_id = 'RINGS.V3';

use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
use Pod::Usage qw( pod2usage );
use DBI;
use PS::IPP::Config 1.01 qw( :standard );

my $ipprc = PS::IPP::Config->new();
my $dbh = getDBHandle();

my ($requested_filter, $no_display, $skycell_id, $verbose, $ra, $dec, $convolved);
my ($singleframe);

GetOptions(
    'filter|f=s'    => \$requested_filter,  # restrict to a single filter 
    'skycell_id=s'  => \$skycell_id,        # don't bother with 
    'convolved'     => \$convolved,         # display convolved stack images instead of unconvolved
    'label=s'       => \$label,             # use a different label (careful!)
    'tess_id=s'     => \$tess_id,           # 
    'no-display|n'  => \$no_display,        # don't run ds9 just print the filenames
    'single'        => \$singleframe,
    'verbose|v'     => \$verbose,
) or pod2usage( 2 );

pod2usage( -msg => '<ra> and <dec> or --skycell_id is required', -exitval => 2)
    unless defined $skycell_id or scalar @ARGV == 2;

$ra = shift;
$dec = shift;

pod2usage( -msg => 'if ra is suplied <dec> must be supplied as well', -exitval => 2)
    if (defined $ra and ! defined $dec);

my $extension;
if ($convolved) {
    $extension = 'fits';
} else {
    $extension = 'unconv.fits';
}

# don't allow MD label unless it's a refstack.
# Nightly stacks have too many images
if (($label =~ /MD/) and !(uc($label) =~ /REF/)) {
    die "cannot use this program for label $label because we will probably too many matches. Talk to Bill\n";
}

my $whichimage_output;
if (!$skycell_id or (defined $ra and defined $dec)) {
    # run whichimage to find a list of skycells containing the given coordinates and the 
    # image coordinates of the requested sky coordinates
    $whichimage_output = `whichimage --listchipcoords --tess_id $tess_id $ra $dec`;

    print "Output from whichimage:\n$whichimage_output\n" if $verbose;

    my @results = split "\n", $whichimage_output;

    die "whichimage returned no output\n" if scalar @results == 0;
} else {
    # we were supplied a skycell create a fake whichimage_output that can be parsed below
    $whichimage_output = "0 0 dummy $skycell_id -1 -1\n";
}

my $query = "SELECT skycell_id, filter, stack_id, quality, state, path_base
    FROM stackRun join stackSumSkyfile USING(stack_id) 
    WHERE stackRun.state ='full' AND label = '$label' AND skycell_id = ?";

if ($requested_filter) {
    $requested_filter .= '%' if length($requested_filter) == 1;
}
$query .= " AND filter LIKE '$requested_filter'" if defined $requested_filter;

# This will "sort of" put the sets of images for skycells that were processed multiple times
# in temporal order
$query .= "ORDER BY stack_id";

my $stmt = $dbh->prepare($query) or die $dbh->errstr;

# @files will contain the list of skycells found in order of skycell_id, filter.
# The images will be displayed in this order so that the image frames are in order of increasing bandpass
my @files = ();

# give each filter an index value
my %index = ( 'g.00000' => 0, 'r.00000' => 1, 'i.00000', => 2, 'z.00000' => 3, 'y.00000' =>4 );
my $num_filters = scalar keys %index;

my $total_files = 0;
my $skycells = 0;
# loop over the list of skycells returned by whichimage
foreach (split "\n", $whichimage_output) {
    chomp;

    my ($radeg, $decdeg, undef, $skycell, $x, $y) = split " ";

    print "skycell: $skycell RA (deg): $radeg DEC (deg): $decdeg (X,Y): ($x, $y)\n" if $verbose;

    $stmt->execute($skycell) or die $stmt->errstr;
    my $files_found = 0;
    while (my $f = $stmt->fetchrow_hashref()) {
        next if $f->{quality};
        next if $f->{state} ne 'full';

        my $filter = $f->{filter};
        my $stack_id = $f->{stack_id};
        my $path_base = $f->{path_base};

        # save the skycell coordinates so we can pan efficiently below
        $f->{X} = $x;
        $f->{Y} = $y;

        # Find where this filter goes in the array of files
        my $i = $index{$filter};
        if (!defined $i) {
            print STDERR "stack_id $stack_id has unknown filter $filter! Skipping\n";
            next;
        }
        # if multiple skycells match the coordinates bump the index by $num_filters
        $i += $skycells * $num_filters;
        $files[$i] = $f;
        $files_found++;
    }
    if ($files_found) {
        $total_files += $files_found;
        $skycells++;
    }
}

if (!$total_files) {
    print "no matching stacks found\n";
    exit 1;
}


if (!$no_display) {
    my $imagesize;
    if ($singleframe) {
        $imagesize = 1024;
    } else {
        # estimate of image size for the case where we have 5 frames
        $imagesize = 680;
    }
    # Build the ds9 argument list
    my @args;
    my $panargs = "";
    foreach my $f (@files) {
        next if ! $f;
        my $filename = $f->{path_base} . ".$extension";
        my $resolved = $ipprc->file_resolve($filename);
        next if !$resolved;

        if ($f->{X} > 0) {
            $panargs = "-pan to $f->{X} $f->{Y}";
        } else {
            $panargs = "";
        }

        # The following is an attempt put the filter name in the image using a region with text a label.
        my $xlabel = $f->{X} + $imagesize / 2;
        my $ylabel = $f->{Y} + $imagesize / 2;

        # I couldn't make this work. The circle would appear but without the text
        # my $label = " -regions command  'circle($xlabel,$ylabel,1)' # text={ $f->{filter} }";

        # This didn't work either. Generates an X Errror "RenderBadPicture (invalid Picture parameter)"
        # we could easily create a temporary region file and load that with -regions filename
        my $label = " -regions command  text $xlabel $ylabel {$f->{filter}}";
        # $panargs .= $label;

        # I used to pan each frame but it turns out to be quicker to wait until the last image is
        # loaded. pan thatone and then matching the wcs for the frames.
        # Also that allows V0 and V3 skycells to have east to the left orientation
        # push @args, ($resolved, $panargs);
        push @args, $resolved;
    }
    my $ds9cmd = "ds9 -geom 1024x1024 @args $panargs";
    $ds9cmd .= " -single" if $singleframe;
    $ds9cmd .= " -match frames wcs";
    print "$ds9cmd\n" if $verbose;
    system $ds9cmd;
} else {
    # no-display option Just print out some information
    print "\n" if $verbose;
    print "Skycell ID        stack_id filter   path_base\n";
    print "------------------------------------------------------------------------------------------\n";
    foreach my $f (@files) {
        next if !$f;
        print "$f->{skycell_id}  $f->{stack_id}   $f->{filter}  $f->{path_base}\n";
    }
}

exit 0;

#############################################################################

sub getDBHandle {
    my $dbuser = metadataLookupStr($ipprc->{_siteConfig}, "DBUSER");
    my $dbpassword = metadataLookupStr($ipprc->{_siteConfig}, "DBPASSWORD");
    my $dbserver = metadataLookupStr($ipprc->{_siteConfig}, "DBSERVER");
    my $dbname = 'gpc1';

    die "database configuration set up" unless defined($dbserver) and defined($dbuser)
        and defined($dbpassword) and defined($dbname);

    my $dsn = "DBI:mysql:host=$dbserver;database=$dbname";

    my $dbh = DBI->connect($dsn, $dbuser, $dbpassword) 
        or die "Cannot connect to database.\n";

    return $dbh;
}

