#!/usr/bin/env perl

# this script is used to cleanup the files from the different ipp
# stages.  It can be called with one of two cleanup modes: clean and
# purge.  the former removes temporary data files, leaving behind
# enough information for the results to be rebuilt.  The latter
# removes all but basic logging data.

use warnings;
use strict;
use Carp;

use IPC::Cmd 0.36 qw( can_run run );
use File::Spec;
use PS::IPP::Config 1.01 qw( :standard );
use PS::IPP::Metadata::List qw( parse_md_list );
use Getopt::Long qw( GetOptions :config auto_help auto_version gnu_getopt );
use Pod::Usage qw( pod2usage );

my $ipprc = PS::IPP::Config->new(); # this is used for PATH, NEB filename conversions

# Parse the command-line arguments
my ($stage, $camera, $stage_id, $mode, $path_base, $dbname, $verbose, $no_op, $helplist);
GetOptions('stage=s'        => \$stage,     # which analysis stage to clean?
	   'camera|i=s'     => \$camera,    # user-supplied camera name
	   'stage_id=s'     => \$stage_id,  # id for this stage (only needed for certain stages)
	   'mode|m=s'       => \$mode,      # cleanup mode (clean / purge)
	   'path_base=s'    => \$path_base, # basename for files
	   'dbname|d=s'     => \$dbname,    # Database name
           'verbose'        => \$verbose,   # Print to stdout
	   'no-op'          => \$no_op,     # pretend but don't actually inject
	   'helplist'       => \$helplist   # give help listing
	   ) or pod2usage( 2 );

pod2usage( -msg => "remove temporary / all data files for an IPP analysis stage", 
	   -exitval => 2) if defined $helplist;

pod2usage( -msg => "Usage: $0 --camera (name) --stage (stage) --stage_id (stage_id) --mode (mode) [--path_base (path)] [--dbname dbname] [--no-op] [--help]", 
	   -exitval => 2 ) if scalar @ARGV;

pod2usage( -msg => "Required options:--camera (name) --stage (stage) --mode (mode)",
	   -exitval => 3) unless 
    defined $camera and
    defined $stage and
    defined $mode;

# $mode must be one of "goto_cleaned" or "goto_purged"
unless (($mode eq "goto_cleaned") || ($mode eq "goto_purged")) {
    die "invalid cleanup mode $mode\n";    
}

$ipprc->define_camera($camera);

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

my $fault = 0;

# choice of files to delete depends on the stage
if ($stage eq "chip") {
    
    ### select the imfiles for this entry

    # this stage uses 'chiptool'
    my $chiptool = can_run('chiptool') or die "Can't find chiptool";

    # Get list of component imfiles
    # XXX may need a different my_die for each stage
    my $imfiles;                      # Array of component files
    my $command = "$chiptool -pendingcleanupimfile -chip_id $stage_id"; # Command to run
    $command .= " -dbname $dbname" if defined $dbname;
    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 chiptool: $error_code", "chip", $stage_id, $error_code);
    }
    my $metadata = $mdcParser->parse(join "", @$stdout_buf) or
        &my_die("Unable to parse metadata config doc", "chip", $stage_id, $PS_EXIT_PROG_ERROR);

    # extract the metadata for the files into a hash list
    $imfiles = parse_md_list($metadata) or
        &my_die("Unable to parse metadata list", "chip", $stage_id, $PS_EXIT_PROG_ERROR);

    # loop over all of the imfiles, determine the path_base and class_id for each
    foreach my $imfile (@$imfiles) {
	my $class_id = $imfile->{class_id};
	my $path_base = $imfile->{path_base};

	# array of actual filenames to delete
	my @files = ();

	# delete the temporary image datafiles
	addFilename (\@files, "PPIMAGE.OUTPUT", $path_base, $class_id);
	addFilename (\@files, "PPIMAGE.OUTPUT.MASK", $path_base, $class_id);
	addFilename (\@files, "PPIMAGE.OUTPUT.WEIGHT", $path_base, $class_id);
	addFilename (\@files, "PPIMAGE.CHIP", $path_base, $class_id);
	addFilename (\@files, "PPIMAGE.CHIP.MASK", $path_base, $class_id);
	addFilename (\@files, "PPIMAGE.CHIP.WEIGHT", $path_base, $class_id);
	if ($mode eq "goto_purged") {
	    # additional files to remove for 'purge' mode
	    addFilename (\@files, "PPIMAGE.OUTPUT.FPA1", $path_base, $class_id);
	    addFilename (\@files, "PPIMAGE.OUTPUT.FPA2", $path_base, $class_id);
	    addFilename (\@files, "PPIMAGE.BIN1", $path_base, $class_id);
	    addFilename (\@files, "PPIMAGE.BIN2", $path_base, $class_id);
	    addFilename (\@files, "PPIMAGE.JPEG1", $path_base, $class_id);
	    addFilename (\@files, "PPIMAGE.JPEG", $path_base, $class_id);
	    addFilename (\@files, "PPIMAGE.STATS", $path_base, $class_id);
	}
	
	# actual command to delete the files
	my $status = &delete_files (\@files);

	if (! $status)  {
	    my $command = "$chiptool -updateimfile -chip_id $stage_id -class_id $class_id -code 1"; # Command to run
	    $command .= " -dbname $dbname" if defined $dbname;

	    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 chiptool: $error_code", "chip", $stage_id, $error_code);
	    }
	    
	    $fault = 1;
	}
    }

    if (! $fault) {
	# set the state of the chipRun entry to "cleaned" or "purged" as needed
	my $command = "$chiptool -updaterun -chip_id $stage_id";
	if ($mode eq "goto_purged") {
	    $command .= " -state purged";
	} else {
	    $command .= " -state cleaned";
	}
	$command .= " -dbname $dbname" if defined $dbname;

	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 chiptool: $error_code", "chip", $stage_id, $error_code);
	}
    }
    exit 0;
}

die "unknown stage for ipp_cleanup.pl\n";
exit 1;

sub delete_files 
{
    my $files = shift; # reference to a list of files to unlink
    
    # this script is, of course, very dangerous.  
    foreach my $file (@$files) {
	print STDERR "unlinking $file\n";
	unlink $file;
    }
    return 1;
}

sub addFilename 
{
    my $files      = shift; # reference to a list of files to unlink
    my $filerule   = shift; # filerule to add
    my $path_base  = shift; # base filename
    my $class_id   = shift; # class_id, if needed

    my $file = $ipprc->filename($filerule, $path_base, $class_id);

    push @$files, $file;
    return 1;
}

sub my_die
{
    my $msg = shift; # Warning message on die
    my $stage = shift; # Chiptool identifier
    my $stage_id = shift; # Chiptool identifier
    my $exit_code = shift; # Exit code to add
    # outputImage and outroot are globals

    carp($msg);
    exit $exit_code;
}

__END__
