#!/bin/env perl
#
# pstamp_queue_reqests.pl
#
# Query registered data stores for new postage stamp requests and add them to
# the database of pending requests.
#

use warnings;
use strict;

use Getopt::Long qw( GetOptions );

use Sys::Hostname;
my $host = hostname();

my $verbose;
my $dbname;
my $limit;

GetOptions(
    'verbose'       =>  \$verbose,
    'dbname=s'      =>  \$dbname,
    'limit=s'       =>  \$limit,
);

if ($verbose) {
    print STDERR "\n\n";
    print STDERR "Starting script $0 on $host\n\n";
}

use IPC::Cmd 0.36 qw( can_run run );

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 $missing_tools;

my $pstamptool  = can_run('pstamptool')  or (warn "Can't find pstamptool"  and $missing_tools = 1);
my $dsproductls = can_run('dsproductls') or (warn "Can't find dsproductls" and $missing_tools = 1);
my $dsfilesetls = can_run('dsfilesetls') or (warn "Can't find dsfilesetls" and $missing_tools = 1);

if ($missing_tools) {
    warn("Can't find required tools.");
    exit ($PS_EXIT_CONFIG_ERROR);
}

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

my @dataStores;
#Look up the list of data stores to monitor
{
    my $command = "$pstamptool -datastore";
    $command .= " -dbname $dbname" if $dbname;

    my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
        run(command => $command, verbose => $verbose);
    unless ($success) {
        my $rc = $error_code >> 8;
        die("Unable to perform pstamptool -datastore: $rc");
    }

    if (@$stdout_buf == 0) {
        print STDERR "no data stores registered\n" if $verbose;
        exit 0;
    }
    my $metadata = $mdcParser->parse(join "", @$stdout_buf) or
        die("Unable to parse metdata config doc");

    my $ds = parse_md_list($metadata);

    @dataStores = @$ds;
}

if (! @dataStores) {
    print STDERR "no postage stamp data stores found\n";
    exit 1;
}

# loop over the data stores
foreach my $ds (@dataStores) {
    my $lastFileset;

    # skip any data stores that aren't enabled

    if ($ds->{state} ne "enabled") {
        next;
    }

    my $outProduct = $ds->{outProduct};
    my $ds_id = $ds->{ds_id};
    my @lines;
    {
        my $command = "$dsproductls --uri $ds->{uri}/index.txt";
        $command .= " --last_fileset $ds->{lastFileset}" if $ds->{lastFileset};
        my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
            run(command => $command, verbose => $verbose);
        unless ($success) {
            die("Unable to perform $command: $error_code");
        }

        if (@$stdout_buf == 0) {
            print STDERR "no new request files in data store $ds_id\n";
            next; # next data store
        }
        my $out_buf = join("", @$stdout_buf);
        # split raw output into lines
        # XXX: why do I think that i need the map?
        #my @lines = map {split "\n"} $raw_output;
        @lines = split /^/, $out_buf;
    }

    #
    # each line contains a fileset
    #
    # XXX: we probably should set a limit on the number of these we process
    # otherwise this could take a long time and the task could time out
    foreach my $line (@lines) {
        # parse the line into fields split by whitespace
        my ($uri, $fs_name, $date, $type) = split " ", $line;

        next if ( $uri =~ /^#.*/);

        my @files;
        {
            my $command = "$dsfilesetls --uri $uri";
            my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
                    run(command => $command, verbose => $verbose);
            unless ($success) {
                die("Unable to perform $command: $error_code");
            }

            if (@$stdout_buf == 0) {
                print STDERR "no file sets found\n";
                next;
            }
            my $out_buf = join "", @$stdout_buf;
            @files = split /^/, $out_buf;
        }

        #
        # For each file in the fileset add a request
        #
        foreach my $file (@files) {
            my ($req_uri, $fn, $size, $md5sum, $type, $chipname) = split " ", $file;

            # skip comment lines
            next if $req_uri =~ (/^#.*/);
            {
                my $command = "$pstamptool -addreq -uri $req_uri -ds_id $ds_id";
                $command .= " -dbname $dbname" if $dbname;
                my ( $success, $error_code, $full_buf, $stdout_buf, $stderr_buf ) =
                        run(command => $command, verbose => $verbose);
                    unless ($success) {
                        # XXX: what do we do now?
                        die("Unable to perform $command: $error_code");
                    }
            }
            $lastFileset = $fs_name;
        }
    }

    ## now update the last_fileset column in pstampDataStore
    ## XXX: we should probably do this before we process the fileset. Otherwise 
    ## if we get an error from pstamptool we'll get stuck processing it over and over.
    if ($lastFileset) {
        # print "last fileset: $lastFileset\n";
        {
        my $command = "$pstamptool -ds_id $ds_id -moddatastore -last_fileset $lastFileset";
        $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 pstamptool -moddatastore: $error_code");
            }
        }
    }
}

exit 0;
