#!/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::Statement::Status;
use RPS::DB::Item::ArtistRoyaltyStatement;
use RPS::ArtistRoyalty::Process::CreateStatement;



# 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});

    
    # We're using the same script for all sorts of statements.
    # But we need to determine the correct Controller subclass to use.
    #
    my $obj = RPS::DB::Item::ArtistRoyaltyStatement->Lookup(artist_royalty_statement_id => $gOptions{statementID});

    my $controller = RPS::ArtistRoyalty::Process::CreateStatement->new(statementID => $gOptions{statementID}, logLevel => $gVerbosityLevel);

    my $exitCode = $controller->execute();
    Common::Log::Print("EXIT CODE: $exitCode\n");
    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);
    }


    # 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::Statement::Status::kAborted;
        }
        else
        {
            $status = RPS::Statement::Status::kError;
        }

        my $appSingleton = Common::RSApp->new(clientID => $gOptions{clientID});
        my $obj = RPS::DB::Item::ArtistRoyaltyStatement->Lookup(artist_royalty_statement_id => $gOptions{statementID});
        $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('s:c:V:', \%opt);

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

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


sub _usage
{
    print "\nusage: $0 -c client_id -s statement_id [-V n]\n";
    print "\n";
    print "Arguments:\n";
    print "\t-c <client_id>\t\tThe client_id of the client to process\n";
    print "\t-s <statement_id>\t\tThe id of the artist royalty statement to process\n";
    print "\t-V <N>\t\t\tVerbosity level - 0 means no output\n";
}

