#!/usr/bin/env perl

use warnings;
use strict;

use DBI;
use constant DB_SOCKET => '/var/run/mysqld/mysqld.sock'; # Socket for mysql
use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
use File::Temp qw( tempfile );
use IPC::Cmd qw( can_run run );
use Nebulous::Client;

my ($db_host, $db_name, $db_user, $db_pw); # Database details
my ($label);                               # Label
my ($verbose, $save_temps);                # Debugging

GetOptions(
    'dbhost=s' => \$db_host,    # Database host name
    'dbname=s' => \$db_name,    # Database name
    'dbuser=s' => \$db_user,    # Database user
    'dbpass=s' => \$db_pw,      # Database p/w
    'label=s@' => \$label,      # Label(s)
    'verbose' => \$verbose,     # Verbose?
    'save-temps' => \$save_temps, # Save temp files?
    ) or
    die "Unable to parse arguments.\n";
die "Unknown option: @ARGV\n" if @ARGV;
die "Required options: --dbhost --dbname --dbuser --dbpass --label\n"
    unless defined $db_host
    and defined $db_name
    and defined $db_user
    and defined $db_pw
    and defined $label;

# Database connection
my $db = DBI->connect( "DBI:mysql:database=$db_name;host=$db_host;mysql_socket=" . DB_SOCKET(),
                       $db_user,
                       $db_pw,
                       { RaiseError => 1, AutoCommit => 1 }
                       ) or die "Unable to connect to database: $DBI::errstr";
my $neb = Nebulous::Client->new( proxy => $ENV{NEB_SERVER} ) or die "Unable to connect to Nebulous: $!\n";

my $diffs;                      # Diffs to process
{
    my $sql = "SELECT diff_id, bothways FROM diffRun WHERE (label LIKE '" . join("' OR label LIKE '", @$label) . "')";
    $diffs = $db->selectall_arrayref( $sql, { Slice => {} } ) or die "Unable to execute SQL: $DBI::errstr";
}

my @commands;
foreach my $diff (@$diffs) {
    my $diff_id = $diff->{diff_id};
    my $bothways = $diff->{bothways};

    mopify($diff_id, 0);
    if ($bothways) {
        mopify($diff_id, 1);
    }
}

### Pau.


# Translate the outputs from a diff into MOPS format
sub mopify
{
    my $diff_id = shift;        # Difference identifier
    my $inverse = shift;        # Inverse diff?

    my $exposure = $db->selectrow_hashref("SELECT DISTINCT rawInput.exp_name, rawInput.exp_id, chipInput.chip_id, camInput.cam_id, fakeInput.fake_id, warpInput.warp_id, zpt_obs + 2.5*LOG10(rawTemplate.exp_time) AS zp, zpt_stdev, SQRT(sigma_ra*sigma_ra+sigma_dec*sigma_dec) AS astrom_rms FROM diffRun JOIN diffInputSkyfile USING(diff_id) JOIN warpRun AS warpTemplate ON warpTemplate.warp_id = warp1 JOIN fakeRun AS fakeTemplate ON fakeTemplate.fake_id = warpTemplate.fake_id JOIN camProcessedExp ON fakeTemplate.cam_id = camProcessedExp.cam_id JOIN camRun AS camTemplate ON camTemplate.cam_id = fakeTemplate.cam_id JOIN chipRun AS chipTemplate ON chipTemplate.chip_id = camTemplate.chip_id JOIN rawExp AS rawTemplate ON rawTemplate.exp_id = chipTemplate.exp_id JOIN warpRun AS warpInput ON warpInput.warp_id = " . ($inverse ? "warp2" : "warp1") . " JOIN fakeRun AS fakeInput ON fakeInput.fake_id = warpInput.fake_id JOIN camRun AS camInput ON camInput.cam_id = fakeInput.cam_id JOIN chipRun AS chipInput ON chipInput.chip_id = camInput.chip_id JOIN rawExp AS rawInput ON rawInput.exp_id = chipInput.exp_id WHERE diff_id = $diff_id") or die "Unable to execute SQL: $DBI::errstr";

    my $exp_name = $exposure->{exp_name};
    my $exp_id = $exposure->{exp_id};
    my $chip_id = $exposure->{chip_id};
    my $cam_id = $exposure->{cam_id};
    my $fake_id = $exposure->{fake_id};
    my $warp_id = $exposure->{warp_id};
    my $zp = $exposure->{zp};
    my $zp_err = $exposure->{zpt_stdev};
    my $astrom_rms = $exposure->{astrom_rms};

    my $inputs = $db->selectcol_arrayref("SELECT path_base FROM diffSkyfile WHERE diff_id = $diff_id AND fault = 0 AND quality = 0") or die "Unable to execute SQL: $DBI::errstr";

    my ($listFile, $listName) = tempfile("mops.XXXXX", UNLINK => !$save_temps, SUFFIX => ".list");
    foreach my $input (@$inputs) {
        my $name ="$input." . ($inverse ? "inv.cmf" : "cmf");
        if ($name =~ /^neb:/) {
            my $new = eval { $neb->find($name); };
            die "Unable to resolve $name" unless defined $new;
            $name = $new;
        }
        print $listFile "$name\n";
    }
    close $listFile;

    my $outName = "$diff_id." . ($inverse ? "neg" : "pos") . ".mops";

    my $command = "ppMops -exp_name $exp_name -exp_id $exp_id -chip_id $chip_id -cam_id $cam_id -fake_id $fake_id -warp_id $warp_id -zp $zp -zp_error $zp_err -astrom_rms $astrom_rms $listName $outName";
    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
        run(command => $command, verbose => $verbose);
    die "Unable to translate diff $diff_id" unless $success;

    return 1;
}
