#---------------------------------------------------------------
# ____                   _ _         ____  _                    
#|  _ \ ___  _   _  __ _| | |_ _   _/ ___|| |__   __ _ _ __ ___ 
#| |_) / _ \| | | |/ _` | | __| | | \___ \| '_ \ / _` | '__/ _ \
#|  _ < (_) | |_| | (_| | | |_| |_| |___) | | | | (_| | | |  __/
#|_| \_\___/ \__, |\__,_|_|\__|\__, |____/|_| |_|\__,_|_|  \___|
#            |___/             |___/                            
#
# Copyright (C) 2012 RoyaltyShare, Inc.   All Rights Reserved
#---------------------------------------------------------------

package RPS::ArtistRoyalty::Fast::Script::RunArtistRoyalties;

use strict;
use Data::Dumper;
use File::Path;

use lib '/app/tools/common/lib';
use lib '/app/tools/rps/lib';
use lib '/app/tools/raptor/lib';

use DB_File;

use Common::Log;
use Common::DB::AutoLock;

use Common::RSApp;
use RPS::DB::Item::ArtistRoyaltyRun;
use RPS::RoyaltyRun::Status;
use RPS::ArtistRoyalty::Job::CreateReservePipelineReport;
use RPS::ArtistRoyalty::Job::CreatePDFStatements;
use RPS::ArtistRoyalty::Job::CreateExcelStatements;
use RPS::Statement::Artist::PDF;
use RPS::ArtistRoyalty::Job::CreateCurrentPeriodExportReportText;
use RPS::ArtistRoyalty::Job::CreateCurrentPeriodExportReportExcel;
use RPS::ArtistRoyalty::Job::CreateAlbumBalancesExportReportText;
use RPS::ArtistRoyalty::Job::CreateAlbumBalancesExportReportExcel;

use base 'Common::Script';
use constant kLockTable => "artist_royalty_assemble_statements_semaphore";


sub _options {{
    client_id => 
    {
        short       => 'c',
        required    => 1,
        description => 'Limit to this client id',
        parameter    => 'i'
    },
    run_id =>
    {
        short       => 'r',
        required    => 1,
        description => 'The artist_royalty_run_id we are creating statements for.',
        parameter   => 'i',
    },
    verbosity =>
    {
        short       => 'V',
        required    => 0,
        description => 'Specify log level, old style',
        parameter   => 'i',
    },
}}



sub _process
{
    my ($self) = @_;

    my $runID = $self->param('run_id');

    Log->warn("Beginning royalty run $runID");

    # Read in the run record, so we can get the correct payor_id.
    #
    my $runData = RPS::DB::Item::ArtistRoyaltyRun->Lookup(artist_royalty_run_id => $runID);


    # JPK - For now, we'll assume that we're going to run everything on a single host.
    #

    # !!! These values should probably come from the config file system, but for the moment
    # !!! I will hard-code them.
    #
    my $staticDataPath = "/app/data/artist_royalty_run/".Common::RSApp::GetClientID()."/".$runID;
    my $outputDataPath = $staticDataPath . "/output";


    eval {
        $self->_runRoyalties($runData, $staticDataPath, $outputDataPath);
    };
    if ($@)
    {
        $runData->end_time(Common::DB::Item::kDateTimeNow);
        $runData->status(RPS::RoyaltyRun::Status::kError);
        $runData->error($@);
        Log->crit($@);
        $runData->save();
    }

    Log->warn("Finished royalty run $runID");
}

sub _runRoyalties
{
    my ($self, $runData, $staticPath, $outputPath) = @_;


    my $binDir = '/app/tools/rps/lib/RPS/ArtistRoyalty/Fast/bin';

    $runData->status(RPS::RoyaltyRun::Status::kRunning);
    $runData->start_time(Common::DB::Item::kDateTimeNow);
    $runData->pid($$);
    $runData->save();

    my $runID = $runData->artist_royalty_run_id();
    my $clientID = Common::RSApp::GetClientID();

    # JPK - This should probably be a config file item.
    # Let's set it relatively low to avoid too much contention.
    #
    my $salesMapProcessCount = 6;

    # ES - Setup an alternate temporary directory for sort.
    #
    my $tmpPath = $staticPath . "/tmp";
    if (! -d $tmpPath)
    {
        mkpath($tmpPath);
    }

    my @commands = (
        "$binDir/stageData.pl -c $clientID -r $runID -d $staticPath",
        "$binDir/mapSales.pl  -c $clientID -d $staticPath -o $outputPath -p$salesMapProcessCount",
        "$binDir/mapReserves.pl -c $clientID -d $staticPath -o $outputPath",
        "$binDir/mapExpenses.pl -c $clientID -d $staticPath -o $outputPath",
        "$binDir/mapLicenseIncomeSales.pl  -c $clientID -d $staticPath -o $outputPath",
        "$binDir/mapPendingTransactions.pl  -c $clientID -d $staticPath -o $outputPath",
        "$binDir/mapPayees.pl  -c $clientID -d $staticPath -o $outputPath",
        "$binDir/mapAlbumContractAccounts.pl  -c $clientID -d $staticPath -o $outputPath",
        "sort -T $tmpPath -n -k1 -k2 -k3 -k4 -k5 -k6 -k7 -k8 -k9 -k10 -k11 -k12 -k13 $outputPath/mapped_items_* > $outputPath/mapped_items.sorted",
        "sort -T $tmpPath -n " . '-t$'."'\t' -k1 -k2 -k3 -k4 $outputPath/missed_sales_* > $outputPath/missed_sales.sorted",
    );

    foreach my $cmdString(@commands)
    {
        Log->warn("executing: $cmdString");
        my $status = system($cmdString);
        die "ERROR EXECUTING '$cmdString': ($?) $!" unless 0 == $status;
    }


    # These commands need to execute 'atomically' at the process level.  We are creating new database records, and will be making
    # certain assumptions about what table ids are available.   So we will use a lock on a special table as a semaphore so that only
    # one process (across the entire system) is allowed to do these at a time.
    #
    my @lockedCommands = (
        "$binDir/assembleStatements.pl -c $clientID -r $runID -d $staticPath -o $outputPath",
        "$binDir/assembleMissedSaleLog.pl -c $clientID -r $runID -d $staticPath -o $outputPath",
        "$binDir/commitFinalData.pl -c $clientID -r $runID -o $outputPath",
    );

    Log->warn("ATTEMPTING TO GET TABLE LOCK ON TABLE " . kLockTable);
    my $lock = Common::DB::AutoLock->new(Common::RSApp::GetClientDB(), kLockTable);
    Log->warn("  OBTAINED THE LOCK");
    foreach my $cmdString(@lockedCommands)
    {
        Log->warn("executing: $cmdString");
        my $status = system($cmdString);
        die "ERROR EXECUTING '$cmdString': ($?) $!" unless 0 == $status;
    }
    Log->warn("   RELEASING THE LOCK");
    $lock = undef;  


    $runData->status(RPS::RoyaltyRun::Status::kComplete);
    $runData->end_time(Common::DB::Item::kDateTimeNow);
    $runData->save();


    # Clean up the local extracted data.
    # Seems a bit lazy to shell out for this, but it's frankly the easiest way to do it.
    # And dangerous...
    # JPK - For the short-term, let's leave the filse around.
#
#    `rm -rf $outputPath`;
#    `rm -rf $staticPath`;


    # Things to do at the end:
    # - Create reserve pipeline report
    # - Create PDFs
    # - Create export reports
    #
    my $jobArgs = RPS::ArtistRoyalty::Job::CreateReservePipelineReport->new
    (
        runID 		=> $runID,
        clientID 	=> $clientID,
    );
    my $job = $jobArgs->enqueue();
    Log->warn("added reserve pipeline job to queue, job id: " . $job->id());


    # Make sure the path exists
    #
    my $filePath = RPS::Statement::Artist::PDF::StatementPathFromRunID($runID);
    if (! -d $filePath)
    {
        mkpath($filePath) or die("Unable to create path $filePath: $!");
    }


    $jobArgs = RPS::ArtistRoyalty::Job::CreatePDFStatements->new
    (
        runID       => $runID,
        clientID 	=> $clientID,
        filePath 	=> $filePath,
    );
    $job = $jobArgs->enqueue();
    Log->warn("added PDF statement job to queue, job id: " . $job->id());

    $jobArgs = RPS::ArtistRoyalty::Job::CreateExcelStatements->new
    (
        runID       => $runID,
        clientID    => $clientID,
        filePath    => $filePath,
    );
    $job = $jobArgs->enqueue();
    Log->warn("added Excel statement job to queue, job id: " . $job->id());


    # Create the export reports.
    #
    $jobArgs = RPS::ArtistRoyalty::Job::CreateCurrentPeriodExportReportText->new
    (
        runID     => $runID,
        clientID  => $clientID,
        filePath  => $filePath,
    );
    $job = $jobArgs->enqueue();


    $jobArgs = RPS::ArtistRoyalty::Job::CreateCurrentPeriodExportReportExcel->new
    (
        runID     => $runID,
        clientID  => $clientID,
        filePath  => $filePath,
    );
    $job = $jobArgs->enqueue();


    $jobArgs = RPS::ArtistRoyalty::Job::CreateAlbumBalancesExportReportText->new
    (
        runID     => $runID,
        clientID  => $clientID,
        filePath  => $filePath,
    );
    $job = $jobArgs->enqueue();


    $jobArgs = RPS::ArtistRoyalty::Job::CreateAlbumBalancesExportReportExcel->new
    (
        runID     => $runID,
        clientID  => $clientID,
        filePath  => $filePath,
    );
    $job = $jobArgs->enqueue();
}



1;
