#!/usr/bin/env perl

use warnings;
use strict;

use vars qw( $VERSION );
$VERSION = '0.01';

use IPC::Cmd 0.36 qw( can_run run );
use PS::IPP::Config 1.01 qw( :standard );
use PS::IPP::Metadata::Config;
use Sys::Hostname;

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

## report the program and machine
my $host = hostname();
print "\n\n";
print "Starting script $0 on $host\n\n";

# Parse the command-line arguments
my ( $uri, $filename, $compress, $bytes, $md5, $nebulous, $exp_name, $inst, $telescope, $class, $class_id, $end_stage, $workdir,
     $dbname, $verbose, $no_update, $no_op, $timeout, $copies );
GetOptions(
       'uri=s'          => \$uri,       # source location of file on data store
       'filename=s'     => \$filename, # target location of file on local system
       'compress'       => \$compress,  # request file in compressed format
       'bytes=s'        => \$bytes,     # reported file size in bytes
       'md5=s'          => \$md5,       # reported md5 checksum
       'nebulous'       => \$nebulous,  # use nebulous for the target file
       'exp_name=s'     => \$exp_name,  # Exposure name
       'inst=s'         => \$inst,      # Instrument
       'telescope=s'    => \$telescope, # Telescope
       'class=s'        => \$class,     # Class level
       'class_id=s'     => \$class_id,  # Class identifier
       'end_stage=s'    => \$end_stage, # end of processing
       'workdir=s'      => \$workdir,   # workdir
       'dbname=s'       => \$dbname,    # Database name
       'verbose'        => \$verbose,   # Print to stdout
       'no-update'      => \$no_update, # Don't update the database?
       'no-op'          => \$no_op,     # Don't do any operations?
       'timeout=s'      => \$timeout,   # passed through to dsget
       'copies=i'       => \$copies,    # passed through to dsget
) or pod2usage( 2 );

pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;
pod2usage( -msg => "Required options: --uri --filename --exp_name --inst --telescope --class --class_id",
       -exitval => 3)
    unless defined $uri
    and defined $filename
    and defined $exp_name
    and defined $inst
    and defined $telescope
    and defined $class
    and defined $class_id;

# Look for programs we need
my $missing_tools;
my $dsget = can_run('dsget')
    or (warn "Can't find dsget" and $missing_tools = 1);
my $pztool = can_run('pztool')
    or (warn "Can't find pztool" and $missing_tools = 1);
if ($missing_tools) {
    warn("Can't find required tools.");
    exit($PS_EXIT_CONFIG_ERROR);
}

# dsget command
my $command;
$command  = "$dsget --uri $uri --filename $filename";
$command .= " --compress"           if defined $compress;
$command .= " --bytes $bytes"       if defined $bytes;
$command .= " --nebulous"           if defined $nebulous;
$command .= " --md5 $md5"           if defined $md5;
$command .= " --timeout $timeout"   if defined $timeout;
$command .= " --copies $copies"     if defined $copies;

# run command
unless ($no_op) {
    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf )
        = run(command => $command, verbose => $verbose);
    unless ($success) {
        $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
        my_die("Unable to perform dsget: $error_code",
            $exp_name,
            $inst,
            $telescope,
            $class,
            $class_id,
            $uri,
            $error_code
        );
    }
} else {
    print "skipping command: $command\n";
}

# command to update database
$command  = "$pztool -copydone";
$command .= " -row_lock";
$command .= " -exp_name $exp_name";
$command .= " -inst $inst";
$command .= " -telescope $telescope";
$command .= " -class $class";
$command .= " -class_id $class_id";
$command .= " -uri $filename";
# $command .= " -workdir $workdir";
$command .= " -hostname $host";
# $command .= " -end_stage $end_stage" if defined $end_stage;
$command .= " -dbname $dbname" if defined $dbname;

# update the database
unless ($no_update) {
    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf )
        = run(command => $command, verbose => $verbose);
    unless ($success) {
        $error_code = (($error_code >> 8) or $PS_EXIT_PROG_ERROR);
        warn("Unable to perform $command: $error_code\n");
        exit($error_code);
    }
} else {
    print "skipping command: $command\n";
}

sub my_die
{
    my $msg       = shift; # Warning message on die
    my $exp_name  = shift; # Chiptool identifier
    my $inst      = shift; # Chiptool identifier
    my $telescope = shift; # Class identifier
    my $class     = shift; # Class identifier
    my $class_id  = shift; # Class identifier
    my $uri       = shift; # Class identifier
    my $exit_code = shift; # Exit code to add

    $exit_code = $PS_EXIT_PROG_ERROR unless defined $exit_code;

    warn $msg;
    unless ($no_update) {
        # command to update database
        my $command;
        $command  = "$pztool -copydone";
        $command .= " -exp_name $exp_name";
        $command .= " -inst $inst";
        $command .= " -telescope $telescope";
        $command .= " -class $class";
        $command .= " -class_id $class_id";
        $command .= " -uri $uri";
        $command .= " -fault $exit_code";
        $command .= " -dbname $dbname" if defined $dbname;

        system ($command);
    }

    exit $exit_code;
}

# XXX: I don't think that we need this - JH
#END {
#    my $status = $?;
#    system("sync") == 0
#        or die "failed to execute sync: $!" ;
#    $? = $status;
#}

__END__
