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

package RPS::ArtistRoyalty::Fast::Final::ArtistRoyaltyStatement;

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

use lib '/app/tools/common/lib';
use lib '/app/tools/rps/lib';
use lib '/app/tools/raptor/lib';
use Common::RSApp;
use Common::Assert;
use Common::Log;

use Data::Dumper;
use DB_File;



use RPS::ArtistRoyalty::Fast::Static::ArtistPayeeAccounts;
use RPS::ArtistRoyalty::Fast::Static::ArtistAlbumContractAccountBalances;
use RPS::ArtistRoyalty::Fast::Mapped::Data;

use base 'RPS::ArtistRoyalty::Fast::Final';

use constant kArtistRoyaltyStatementID          => 0;
use constant kArtistRoyaltyRunID                => 1;
use constant kPayeeID                           => 2;
use constant kPreviousBalance                   => 3;
use constant kBalance                           => 4;
use constant kMinPayment                        => 5;
use constant kCrossCollateralizedPreviousBalance => 6;
use constant kCrossCollateralizedIncomeSubtotal => 7;
use constant kCrossCollateralizedExpenseSubtotal => 8;
use constant kCrossCollateralizedSubtotal       => 9;
use constant kTransactionSubtotal               => 10;
use constant kUncrossedSubtotal                 => 11;
use constant kTotal                             => 12;
use constant kLicenseIncomeSubtotal             => 13;
use constant kContractLevelLicenseIncomeSubtotal => 14;
use constant kContractLevelLicenseIncomePreviousBalance => 15;
use constant kContractLevelLicenseIncomeTotal   => 16;
use constant kAmountDue                         => 17;
use constant kPayorID                           => 18;
use constant kOnHold                            => 19;
use constant kStatus                            => 20;
use constant kJobID                             => 21;
use constant kError                             => 22;

# 'private' constants
use constant kBalanceData                       => 23;



my @gFields = 
(
'artist_royalty_statement_id',
'artist_royalty_run_id',
'payee_id',
'previous_balance',
'balance',
'min_payment',
'cross_collateralized_previous_balance',
'cross_collateralized_income_subtotal',
'cross_collateralized_expense_subtotal',
'cross_collateralized_subtotal',
'transaction_subtotal',
'uncrossed_subtotal',
'total',
'license_income_subtotal',
'contract_level_license_income_subtotal',
'contract_level_license_income_previous_balance',
'contract_level_license_income_total',
'amount_due',
'payor_id',
'on_hold',
'status',
'job_id',
'error',
);
sub Fields { return \@gFields; }


#root@localhost [C_WELK]> desc artist_royalty_statement;
#+------------------------------------------------+------------------+------+-----+---------+----------------+
#| Field                                          | Type             | Null | Key | Default | Extra          |
#+------------------------------------------------+------------------+------+-----+---------+----------------+
#| artist_royalty_statement_id                    | int(10) unsigned | NO   | PRI | NULL    | auto_increment | 
#| artist_royalty_run_id                          | int(10) unsigned | NO   | MUL | 0       |                | 
#| payee_id                                       | int(10) unsigned | NO   | MUL | 0       |                | 
#| previous_balance                               | decimal(16,4)    | NO   |     | 0.0000  |                | 
#| balance                                        | decimal(16,4)    | NO   |     | 0.0000  |                | 
#| min_payment                                    | decimal(16,4)    | NO   |     | 0.0000  |                | 
#| cross_collateralized_previous_balance          | decimal(16,4)    | NO   |     | 0.0000  |                | 
#| cross_collateralized_income_subtotal           | decimal(16,4)    | NO   |     | 0.0000  |                | 
#| cross_collateralized_expense_subtotal          | decimal(16,4)    | NO   |     | 0.0000  |                | 
#| cross_collateralized_subtotal                  | decimal(16,4)    | NO   |     | 0.0000  |                | 
#| transaction_subtotal                           | decimal(16,4)    | NO   |     | 0.0000  |                | 
#| uncrossed_subtotal                             | decimal(16,4)    | NO   |     | 0.0000  |                | 
#| total                                          | decimal(16,4)    | NO   |     | 0.0000  |                | 
#| license_income_subtotal                        | decimal(16,4)    | NO   |     | 0.0000  |                | 
#| contract_level_license_income_subtotal         | decimal(16,4)    | NO   |     | 0.0000  |                | 
#| contract_level_license_income_previous_balance | decimal(16,4)    | NO   |     | 0.0000  |                | 
#| contract_level_license_income_total            | decimal(16,4)    | NO   |     | 0.0000  |                | 
#| amount_due                                     | decimal(16,4)    | NO   |     | 0.0000  |                | 
#| payor_id                                       | int(10) unsigned | NO   |     | 0       |                | 
#| on_hold                                        | tinyint(3)       | NO   |     | 0       |                | 
#| status                                         | tinyint(3)       | YES  |     | NULL    |                | 
#| job_id                                         | int(10) unsigned | NO   |     | 0       |                | 
#| error                                          | text             | YES  |     | NULL    |                | 
#+------------------------------------------------+------------------+------+-----+---------+----------------+
#23 rows in set (0.00 sec)


# We're going to need to get the artist_payee_account data, for min payment
# and previous balance.
# And we will need all the account Transactions, in a MappedData
# representation.   I don't think I'll bother with mapping the min_payment and
# previous balance into the MappedData.  Let's just use a berkeley db file.
# Even if we have to eval the artist_payee_account, there's just one per
# statement.

my $gArtistPayeeAccounts;
my $gBalances;


sub FileName { 'artist_royalty_statement' }


# We're going to use some globals to manage this class.
# This method initializes those.
#
# If this was intended to live in the web app, I'd probably store these inside the App singleton.
# But for now I will just put this in the package's global scope.
#

sub _MaxIDSql { 'SELECT MAX(artist_royalty_statement_id) FROM artist_royalty_statement' }


sub Init
{
    my ($class, $outputDirectory, $dataPath) = @_;
    assert($dataPath, "MISSING dataPath");

    # Call the inherited method first.
    #
    $class->SUPER::Init($outputDirectory);


    # Initialize the artist payee account data.
    #
    $gArtistPayeeAccounts = RPS::ArtistRoyalty::Fast::Static::ArtistPayeeAccounts->GetArtistPayeeAccounts($dataPath);

    # Initialize the balance account data.
    #
    $gBalances = RPS::ArtistRoyalty::Fast::Static::ArtistAlbumContractAccountBalances->GetAccountBalances($dataPath);
}


sub new
{
    my ($class, $data, $runID, $payorID) = @_;

    # Basically, we'll bless the 'BlankItem' array reference into this class
    # Then we can invoke methods on it.
    #
    my $item = $class->BlankItem();
    $class->_IncrementID();

    $item->[kArtistRoyaltyStatementID] = $class->_CurrentID();
    $item->[kArtistRoyaltyRunID] = $runID;
    $item->[kPayeeID] = $data->[RPS::ArtistRoyalty::Fast::Mapped::Data::kPayeeID];
    $item->[kPayorID] = $payorID;


    my $accountData = $gArtistPayeeAccounts->{ int($data->[RPS::ArtistRoyalty::Fast::Mapped::Data::kPayeeID]) };
    if ($accountData)
    {
        my @bits = split("\t", $accountData);
        $item->[kMinPayment] = $bits[RPS::ArtistRoyalty::Fast::Static::ArtistPayeeAccounts::kMinPayment];
        $item->[kPreviousBalance] = $bits[RPS::ArtistRoyalty::Fast::Static::ArtistPayeeAccounts::kBalance];
        $item->[kContractLevelLicenseIncomePreviousBalance] = $bits[RPS::ArtistRoyalty::Fast::Static::ArtistPayeeAccounts::kContractLicenseIncomeBalance];
        $item->[kOnHold] = $bits[RPS::ArtistRoyalty::Fast::Static::ArtistPayeeAccounts::kOnHold];

        # Also seed the cross collateralized previous balance.
        # In theory every Album object will be incrementing this if it is carrying a crossed balance.
        #
        $item->[kCrossCollateralizedPreviousBalance] = $bits[RPS::ArtistRoyalty::Fast::Static::ArtistPayeeAccounts::kContractLicenseIncomeBalance];
    }

    # Pop a slot onto the array to hold a reference to this payee's album
    # account balances.
    #
    my $hashRef = eval($gBalances->{int($item->[kPayeeID])});
    Log->info("ALBUM BALANCE HASHREF FOR PAYEE: " . $item->[kPayeeID], $hashRef);

    push @$item, $hashRef;


    bless $item, $class;

    return $item;
}


sub process
{
    my ($self, $data) = @_;

    # Test whether we're still looking at data for 'this' object.
    #
    if ($self->[kPayeeID] != $data->[RPS::ArtistRoyalty::Fast::Mapped::Data::kPayeeID])
    {
        return undef;
    }

    return 1;
}


sub previousBalance
{
    my ($self, $albumID, $artistContractID) = @_;

    $albumID = int($albumID);
    $artistContractID = int($artistContractID);

    Log->info("STATEMENT SELF: ", $self);

    my $hashRef = $self->[kBalanceData];
    Log->info("previousBalance hashref:", $hashRef);

    my $previousBalance = $self->[kBalanceData]->{$albumID}{$artistContractID};
    Log->info("  previousBalance for '$albumID', '$artistContractID' = '$previousBalance'");
    return $previousBalance;
}

sub _output
{
    my ($self, $fd) = @_;

    # !!! Funny, we don't need this in this scope.
    # !!! But we need to remove it or we'll try to print it.
    #
    my $albumAccountBalances = pop @$self;

my $payeeID = $self->[kPayeeID];
Log->info(" DEBUG: PAYEE $payeeID 1:  ", $self);

    # !!! need to take the contract level license income into account here, too.
    # !!! need to calculate the total based on subtotal and previous balance - look at the old code's logic.
    #
    $self->[kContractLevelLicenseIncomeTotal] = $self->[kContractLevelLicenseIncomeSubtotal] + $self->[kContractLevelLicenseIncomePreviousBalance];
    $self->[kLicenseIncomeSubtotal] += $self->[kContractLevelLicenseIncomeSubtotal];

    # !!! This line may be the problem !!!
    # !!! The kContractLevelLicenseIncomeTotal already has the previous balance - Why add this twice?
#    $self->[kCrossCollateralizedSubtotal] += $self->[kContractLevelLicenseIncomePreviousBalance] + $self->[kContractLevelLicenseIncomeTotal];
    $self->[kCrossCollateralizedSubtotal] += $self->[kContractLevelLicenseIncomeTotal];

    $self->[kTotal] += $self->[kCrossCollateralizedSubtotal] 
     if $self->[kCrossCollateralizedSubtotal] > 0;

    $self->[kBalance] = $self->[kPreviousBalance] + $self->[kTotal] + $self->[kTransactionSubtotal];

    my $amountDue = $self->[kBalance];
    if ($self->[kOnHold] || $self->[kMinPayment] > $amountDue)
    {
        $amountDue = 0;
    }
    $self->[kAmountDue] = $amountDue;

Log->info(" DEBUG: 2:  ", $self);

    $self->SUPER::_output($fd);
}


1;

