#!/bin/env perl

use strict;
use warnings;
use DBI;
use IPC::Cmd 0.36 qw( can_run run );
use PS::IPP::Metadata::Config;
use PS::IPP::Config 1.01 qw( :standard );

use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
use Pod::Usage qw( pod2usage );
use File::Basename;


my ($field, $filter, $label, $data_group, $dist_group, $tess_id, $workdir, $reduction, $end_stage);
my ($verbose);

# parameters with default values
my $date_begin = '2009-04-01';
my $date_end;
my $fwhm_min = 3;
my $fwhm_max;
my $n_inputs_min = 60;
my $n_inputs_max = 100;
my $tess_version = 'V2';
my $input_data_group;
my $object;

my $dbname = "gpc1";

my $list = 0;
my $pretend = 0;
my $queue = 0;

GetOptions(
    'list'          => \$list,
    'queue'         => \$queue,
    'pretend'       => \$pretend,
    'field=s'       => \$field,
    'filter=s'      => \$filter,
    'fwhm_min=s'    => \$fwhm_min,
    'fwhm_max=s'    => \$fwhm_max,
    'input_data_group=s'=> \$input_data_group,
    'n_inputs_min=i'=> \$n_inputs_min,
    'n_inputs_max=i'=> \$n_inputs_max,
    'date_begin=s'  => \$date_begin,
    'date_end=s'    => \$date_end,
    'label=s'       => \$label,
    'data_group=s'  => \$data_group,
    'dist_group=s'  => \$dist_group,
    'tess_version=s'=> \$tess_version,
    'tess_id=s'     => \$tess_id,
    'object=s'      => \$object,
    'workdir=s'     => \$workdir,
    'reduction=s'   => \$reduction,
    'end_stage=s'   => \$end_stage,
    'verbose'       => \$verbose,
) or pod2usage( 2 );

pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
pod2usage( -msg => "--field and --filter are required", -exitval => 2 ) if !$field or !$filter;

pod2usage( -msg => "Only one of --queue and --pretend may be supplied ", -exitval => 2 ) if $queue and $pretend;

$n_inputs_min = $n_inputs_max if ($n_inputs_max < $n_inputs_min);

my ($d, $m, $y) = (gmtime) [3,4,5];
my $today = sprintf "%d%02d%02d", $y + 1900, $m + 1, $d;
print "today is $today\n" if $verbose;

if (!$date_end) {
    # default date_end is 30 days ago
    my $then = time() - 30 * 86400;
    my ($td, $tm, $ty) = (gmtime($then)) [3, 4, 5];
    $date_end = sprintf "%d-%02d-%02d", $ty + 1900, $tm + 1, $td;
    print "date_end: $date_end\n" if $verbose;
}
    

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

my $selection_args = " fwhm_major >= $fwhm_min";

$selection_args .= " AND fwhm_major <= $fwhm_max" if $fwhm_max;
$selection_args .= " AND dateobs >= '$date_begin'";
$selection_args .= " AND date(dateobs) <= '$date_end'" if $date_end;
$selection_args .= " AND object like '$object'" if $object;

$input_data_group = "'$field.%'";

my $query = "SELECT exp_id, exp_name, dateobs, fwhm_major, object, comment FROM camRun join camProcessedExp USING(cam_id) JOIN chipRun using(chip_id, data_group) join rawExp using(exp_id) where data_group like $input_data_group AND filter LIKE '$filter%' AND $selection_args ORDER BY fwhm_major, cam_id DESC LIMIT $n_inputs_max";

print STDERR "$query\n" if $verbose;

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

if (!$stmt->execute()) {
    die "query failed\n";
}

my @exps;
my $n_exps = 0;
my $exp_id_last = 0;
while (my $exp = $stmt->fetchrow_hashref()) {
    # avoid exposures processed multiple times
    my $exp_id = $exp->{exp_id};
    next if $exp_id_last == $exp_id;
    $exp_id_last = $exp_id;

    $n_exps++;
    push @exps, $exp;
}

if ($list) {
    print "  i   exp_id   exp_name          dateobs        fwhm_major   comment\n";
    print "-------------------------------------------------------------------------------------------\n";
}
my $max_fwhm = 0;
my $min_fwhm = 100000;
for (my $i = 0; $i < $n_exps; $i++) {
    my $exp = $exps[$i];
    my $exp_id = $exp->{exp_id};
    my $exp_name = $exp->{exp_name};
    my $dateobs = $exp->{dateobs};
    my $fwhm_major = $exp->{fwhm_major};
    my $object = $exp->{object};
    my $comment = $exp->{comment};
    $max_fwhm = $fwhm_major if $fwhm_major > $max_fwhm;
    $min_fwhm = $fwhm_major if $fwhm_major < $min_fwhm;

    printf "%3d %8d %12s %20s %10f     %s\n", $i+1, $exp_id, $exp_name, $dateobs, $fwhm_major, $comment if $list;
}
print "Found $n_exps exposures for $field $filter.\n";
print "Range of fhwm_major: $min_fwhm - $max_fwhm\n";

if ($n_exps < $n_inputs_min) {
    print "Number of exposures is less than the minimum required: $n_inputs_min\n";
    exit 1;
}

if ($queue or $pretend) {
    if (!$label) {
        $label = "$field.refstack.$today";
    }
    $dist_group = $field if !$dist_group;
    $tess_id = "$field.$tess_version" if !$tess_id;
    $workdir = 'neb://@HOST@.0/gpc1/' . $label if !$workdir;
    $end_stage = 'warp' if !$end_stage;

    my $command = "chiptool -dbname $dbname -definebyquery -set_label $label -set_workdir $workdir";
    $command .= " -set_dist_group $dist_group";
    $command .= " -set_data_group $data_group" if $data_group;
    $command .= " -set_tess_id $tess_id";
    $command .= " -set_end_stage $end_stage";
    $command .= " -set_reduction $reduction" if $reduction;

    $command .= " -pretend -simple" if $pretend;
    for (my $i = 0; $i < $n_inputs_max and $i < $n_exps; $i++) {
        my $exp = $exps[$i];
        my $c = "$command -exp_id $exp->{exp_id}";
        print "$c\n" if $verbose;
        my $status = system $c;
        if ($status) {
            my $exit_status = $status >> 8;
            die "chiptool returned $exit_status";
        }
    }
}

exit 0;

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

    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;
}

=pod

=head1 NAME

refstacktool - queue processing of selected exposures for input to a reference stack.

=head1 SYNOPSIS

    refstacktool --field <field> --filter <filter> [--list] [--queue | --pretend] [selection options] [run options]

=head1 DESCRIPTION

Executes a query of IPP database to select exposures from a given field to be queued for chip processing
based on various selection parameters. 

There are three modes of operation. By default it the number of matching
exposures and the range of fwhm_major values is listed.

For example:

    % refstacktool --field MD05 --filter y
    Found 99 exposures for MD05 y.
    Range of fhwm_major: 3.133 - 4.97175

If the option --queue is supplied, chiptool is invoked to queue chipRuns for the selected exposues.
The image quality and date range for selected exposures may be controlled using the selection options
described below.

The parameters for the chipRun may be controlled with the run options.

=head1 OPTIONS

=over 4

=item * --field <field>

The PS1 field to search for exposures. For example, MD05, STS, or M31. This value is used to construct
default values for various other parameters. In particular exposures are selected where data_group LIKE '$field%'
(XXX: should we use rawExp.comment?)

Required.

=item * --filter <filter>

The filter. The supplied value is appended with a SQL wild card '%' and selection is performed with a "LIKE"
comparision.

Required.

=item * --list

If supplied certain parameters of the selected exposures are displayed.

Optional.


=item * --queue

If the number of exposures is less than the value for n_inputs_min chiptool is run to
insert chipRuns for the selected exposures.

Optional.

=item * --pretend

Like --queue but the arguments "--pretend --simple" are appended to the chiptool command.
(Only one of --queue or --pretend may be supplied.)

Optional.

=head1 SELECTION OPTIONS

=item * --fwhm_max <fwhm_max>

Select exposures where the value of fwhm_major for a previous camRun for the expousre is less than or
equal to the supplied value. fwhm_major is measured in pixels.

Optional.

=item * --fwhm_min <fwhm_min>

Select exposures where the value of fwhm_major for a previous camRun for the expousre is greater than or
equal to the supplied value.

Optional. The default value is 3 pixels.

=item * --date_begin <date_begin>

Select exposures taken after 00:00:00 UTC on the given date. The date format is YYYY-MM--DD style.

Optional. The default value is '2009-04-01'.

=item * --date_end <date_end>

Select exposures taken on or before the given date.

Optional. The default value is 30 days prior to the current date.

=item * --input_data_group <input_data_group>

Select exposures which were previously processed with chipRun and camRun that match the supplied data_group.

Optional. The default value is "field.%. For example 'MD05%'

=item * --object <object>

Select exposures whose "object" matches the supplied value. (The SQL wild
chard character '%' is useful here.

Optional.

=item * --n_inputs_min <n_inputs_min>

With --queue or --pretend only run the chiptool commands if the number of selected exposures is greater than
or equal to the supplied value.

Optional. The default value is 60 exposures.

=item * --n_inputs_max <n_inputs_max>

Limit the query to the supplied value.

Note: The number of rows returned by the query is based on the number of camRuns that match the selection
parameters. If an exposure has been processed multiple times, multiple rows will be returned for the same
exposure. Before running the chiptool command duplicates are ignored so the number of runs queued could be
less than the requested value.

Optional. The default value is 100 exposures.

=head1 RUN OPTIONS

The following options may be used to control the parameters of the chipRuns. All are RUN OPTIONS are optional

=item * --label <label> 

Value for chipRun.label Default: "$field.refstack.$current_date

=item * --data_group <data_group> 

Value for chipRun.data_group Default: label

=item * --dist_group <dist_group> 

Value for chipRun.dist_group Default: field

=item * --tess_version <tess_version> 

Value for the tessellation version. (Not used if tess_id is supplied.)
Default: '.V2'

=item * --tess_id <tess_id> 

Value for chipRun.tess_id. Default: $field.$tess_version

=item * --workdir <workdir> 

Value for chipRun.workdir. Default: 'neb://@HOST@.0/gpc1/' . $label

=item * --reduction <reduction>

Value for chipRun.reduction. Default: NULL.

=item * --end_stage <end_stage>

Value for chipRun.end_stage. Default: warp.




=head1 SEE ALSO
L<chiptool>

=cut
