#!/bin/env perl

# pstamp_finish.pl

use warnings;
use strict;

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

use Sys::Hostname;
use IPC::Cmd 0.36 qw( can_run run );
use File::Temp qw( tempfile );
use File::Copy;

use PS::IPP::Metadata::Config;
use PS::IPP::Metadata::Stats;
use PS::IPP::Metadata::List qw( parse_md_list );

use PS::IPP::Config qw($PS_EXIT_SUCCESS
		       $PS_EXIT_UNKNOWN_ERROR
		       $PS_EXIT_SYS_ERROR
		       $PS_EXIT_CONFIG_ERROR
		       $PS_EXIT_PROG_ERROR
		       $PS_EXIT_DATA_ERROR
		       $PS_EXIT_TIMEOUT_ERROR
		       metadataLookupStr
		       metadataLookupBool
		       caturi
		       );


my ( $req_id, $req_name, $product, $dbname, $verbose, $save_temps );

# the char to the right of the bar may be used as a single - alias for the longer name
# for example --input and -i are equivalent
GetOptions(
           'req_id=s'   => \$req_id,
           'req_name=s' => \$req_name,
           'product=s'  => \$product,
	   'dbname=s'   => \$dbname,
	   'verbose'    => \$verbose,
	   'save-temps' => \$save_temps,
) or pod2usage( 2 );

pod2usage( -msg => "Unknown option: @ARGV", -exitval => 2 ) if @ARGV;

my $missing_tools;

my $pstamptool  = can_run('pstamptool')  or (warn "Can't find pstamptool"  and $missing_tools = 1);
my $dsreg  = can_run('dsreg')  or (warn "Can't find dsreg"  and $missing_tools = 1);
my $pstamp_results = can_run('pstamp_results_file.pl') 
                            or (warn "Can't find pstamp_results_file.pl" and $missing_tools = 1);
if ($missing_tools) {
    warn("Can't find required tools.");
    exit ($PS_EXIT_CONFIG_ERROR);
}

my $ipprc = PS::IPP::Config->new(); # IPP Configuration

my $outputDataStoreRoot = metadataLookupStr($ipprc->{_siteConfig}, 'DATA_STORE_ROOT');
exit ($PS_EXIT_CONFIG_ERROR) unless defined $outputDataStoreRoot; # lookup failure outputs a message

my $mdcParser = PS::IPP::Metadata::Config->new; # Parser for metadata config files

{
    # set the output fileset's name to the request name.
    my $fileset = $req_name;

    # Here we invoke the assumption that the output for the request is placed in the
    # fileset directory directly
    my $out_dir = "$outputDataStoreRoot/$product/$fileset";

    print STDERR "product: $product  REQ_NAME: $req_name $out_dir\n" if $verbose;

    if (!-e $out_dir) {
        # something must have gone wrong parsing the request
        print STDERR  "output fileset directory $out_dir does not exist\n";

        # XXX TODO: if this fails fault the request so we pstamp_finish 

        mkdir $out_dir or die "cannot create output directory $out_dir";

    } elsif (! -d $out_dir ) {
        # XXX TODO: fault the request so we pstamp_finish doesn't keep trying to process the
        # request
        die "output fileset directory $out_dir exists but is not a directory";
    }


    # at this point we need to find out what kind of request type it is and
    # split the processing depending on the request type
    # the only processing required for a detectabilty query is to build the output fileset.

    # the following is for a postage stamp request

    my ($rlf, $reglist_name) = tempfile ("$out_dir/reglist.XXXX", UNLINK => !$save_temps);
    print $rlf "results.fits|||table|\n";
    my $err_file = "$out_dir/parse_error.txt";
    if (-e $err_file ) {
        print $rlf "$err_file|||text|\n";
    }

    my ($tdf, $table_def_name) = tempfile ("$out_dir/tabledef.XXXX", UNLINK => !$save_temps);


    # data for the header
    print $tdf "$req_name|$req_id|\n";
    my @jobs;
    {
        my $command = "$pstamptool -listjob -req_id $req_id";
        $command   .= " -dbname $dbname" if $dbname;
        my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
            run(command => $command, verbose => $verbose);
        unless ($success) {
            die("Unable to perform $command error code: $error_code");
        }
        my $output = join "", @$stdout_buf;
        if (!$output) {
            if ($verbose) {
                print STDERR "Request $req_id produced no jobs.\n"
            }
            # No Jobs. 
            # XXXX Ouch. We need results for each rownum (each request specification) in the request file 
            # including those that produced no jobs.
            # for now add an entry for rownum 1 and a phony error code.
            # we've included parse_results.txt to the fileset if it exists
            #
            my $rownum = 1;
            my $fault = 42; # get a real error code
            print $tdf "$rownum|$fault|0|0|";
            print $tdf "0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|\n";
        } else {
            my $metadata = $mdcParser->parse($output) or die("Unable to parse metdata config doc");

            my $jobs = parse_md_list($metadata);

            @jobs = @$jobs;
        }
    }

    foreach my $job (@jobs) {
        my $job_id = $job->{job_id};
        my $job_type = $job->{jobType};
        my $rownum = $job->{rownum};
        my $fault = $job->{fault};
        # rownum fault img_name job_id
        if (($job_type eq "stamp") || ($job_type eq "get_image")) {
            my $jreglist = "$out_dir/reglist$job_id";
            if (open JRL, "<$jreglist") {;
                # process the reglist file to get the list of files produced by this job
                foreach my $line (<JRL>) {
                    # add line to the requests's reglist
                    print $rlf $line;

                    chomp $line;
                    my ($img_name, undef) = split '\|', $line;

                    # add line to the table definition file
                    print $tdf "$rownum|$fault|$img_name|$job_id|";
                    # XXX TODO: need to lookup the rest of this stuff
                    print $tdf "0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|0|\n";
                }
                close JRL;
            } else {
                print STDERR "no reglist file for job $job_id\n" if $verbose;
                print $tdf "$rownum|$fault|0|$job_id|";
            }
        } else {
            print STDERR "Unknown jobType: $job_type";
            next;
        }
    }
    close $rlf;
    close $tdf;
    my $request_fault = 0;
    # make the results file
    {
        my $command = "$pstamp_results --input $table_def_name --output $out_dir/results.fits";
        my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
            run(command => $command, verbose => $verbose);
        unless ($success) {
            print STDERR "Unable to perform $command error code: $error_code\n";
            $request_fault = $error_code >> 8;
        }
    }
    if (!$request_fault) {
        # register the fileset
        # Note that we are assuming that the fileset's files are already in the fileset directory.
        # We could put them somewhere else and copy them in but for now we set the output directory
        # to the fileset directory at parse time
        my $command = "$dsreg --list $reglist_name --add $fileset --product $product --type PSRESULTS";
        $command .= " --dbname $dbname" if $dbname;

        my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
            run(command => $command, verbose => $verbose);
        unless ($success) {
            #die("Unable to perform $command error code: $error_code");
            print STDERR "Unable to perform $command error code: $error_code\n";
            $request_fault = $error_code >> 8;
        }
    }
    # set the request's state to stop
    {
        my $command = "$pstamptool -processedreq -req_id $req_id -state stop -fault $request_fault";
        $command   .= " -dbname $dbname" if $dbname;
        my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
            run(command => $command, verbose => $verbose);
        unless ($success) {
            die("Unable to perform $command error code: $error_code");
        }
    }
}
sub stop_request {
    my $req_id = shift;
    my $fault  = shift;
    my $dbname = shift;

    my $command = "$pstamptool -processedreq -req_id $req_id -state stop -fault $fault";
    $command   .= " -dbname $dbname" if $dbname;

    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
        run(command => $command, verbose => $verbose);
    unless ($success) {
        die("Unable to perform $command error code: $error_code");
    }
}
