#!/usr/bin/perl
#------------------------------------------------------------
# Copyright (C) 2009 RoyaltyShare, Inc.   All Rights Reserved
#------------------------------------------------------------
use strict;

use Data::Dumper;
use Getopt::Std;
use POSIX qw(ceil);
use POSIX qw(:sys_wait_h :signal_h :errno_h);

use IO::Handle;

use lib '/app/tools/common/lib';
use lib '/app/tools/rps/lib';
use Common::Assert;
use Common::Log;
use RPS::DB::Item::MechanicalRun;
use RPS::Mechanical::US::Process::RunController;
use RPS::RoyaltyRun::Status;

# Allow tuning of the verbosity of our output.
#
my $gVerbosityLevel = 1;

# Parse the command-line options.
#
my %gOptions;
_parseCommandLine( \%gOptions );

# Now, we're going to fork off a child process.
# This way I can tell (and therefore log) whether we exited cleanly or because
# of some exception
#
local $SIG{CHLD} = \&REAPER;
my $gChildIsRunning = 1;
my $gChildExitCode;

my $gChildPID = fork();
if ($gChildPID) {
    _parent();
} else {
    _child();
}

sub _child {

    # Install a signal handler to catch ctrl-c
    #
    $SIG{INT} = \&CTRL_C;

    # Instantiate the application singleton object.
    #
    my $appSingleton = Common::RSApp->new( clientID => $gOptions{clientID} );

    # Instantiate the run controller object, then let 'er rip.
    #
    my $controller = RPS::Mechanical::US::Process::RunController->new( runID => $gOptions{runID}, logLevel => $gVerbosityLevel );

    my $exitCode = $controller->commit();
    Common::Log::Print("------ IN CHILD PROCESS, CHILD EXIT CODE = $exitCode");
    exit($exitCode);
}

sub _parent {
    local $SIG{INT} = 'IGNORE';

    while ($gChildIsRunning) {

        # We don't want to go nuts polling for the child exit status.
        # Two seconds seems a reasonable interval.
        #
        sleep(2);
    }

    Common::Log::Print("------ CHILD EXIT CODE = $gChildExitCode");

    # The controller (within the child process) is generally responsible for
    # writing all state changes to the run db item.
    # However, if the process is killed externally, or something unexpected happened,
    # then we have a chance here to note that.
    #
    if ( 0 != $gChildExitCode ) {
        my $status;

        if ( 1 == $gChildExitCode ) {
            $status = RPS::RoyaltyRun::Status::kAborted;
        } else {
            $status = RPS::RoyaltyRun::Status::kError;
        }

        my $appSingleton = Common::RSApp->new( clientID => $gOptions{clientID} );
        my $obj = RPS::DB::Item::MechanicalRun->Lookup( mechanical_run_id => $gOptions{runID} );

        if ($obj) {
            $obj->status($status);
            $obj->save();
        }
    }

    exit(0);
}

sub REAPER {
    my $deadChildPID = waitpid( -1, &WNOHANG );

    if ( -1 == $deadChildPID ) {

        # no child - ignore this
    } elsif ( WIFEXITED($?) ) {

        # The child really exited.
        # Let's find out why.
        #
        $gChildExitCode  = $? >> 8;
        $gChildIsRunning = 0;
    }
    $SIG{CHLD} = \&REAPER;
}

sub CTRL_C {
    Common::Log::Print("caught a ctrl-c, aborting");
    exit(1);
}

# Pass dates in 'yyyy-mm-dd' format.
#
sub _parseCommandLine {
    my ($settings) = @_;

    my %opt;
    getopts( 'r:c:V:', \%opt );

    if ( !$opt{r} || !$opt{c} ) {
        _usage();
        exit(1);
    }
    $settings->{runID}    = $opt{r};
    $settings->{clientID} = $opt{c};

    if ( defined $opt{V} ) {
        $gVerbosityLevel = $opt{V};
    }
}

sub _usage {
    print "\nusage: $0 -c client_id -r run_id [-V n]\n";
    print "\n";
    print "Arguments:\n";
    print "\t-c <client_id>\t\tThe client_id of the client to delete\n";
    print "\t-r <run_id>\t\tThe id of the us mechanical run to delete\n";
    print "\t-V <N>\t\t\tVerbosity level - 0 means no output\n";
}

