#------------------------------------------------------------
# Copyright (C) 2009 RoyaltyShare, Inc.   All Rights Reserved
#------------------------------------------------------------

package RPS::Mechanical::CA::Process::CreateStatement;

use strict;

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

use POSIX qw(ceil);

use Common::Assert;
use Common::DB::Item::Client;
use Common::Log;
use Common::RSMath;
use Common::Util;
use Data::Dumper;
use Raptor::DB::Item::File;
use Raptor::DB::Item::Sale;
use RPS::DB::Item::Album;
use RPS::DB::Item::AlbumContract;
use RPS::DB::Item::Artist;
use RPS::DB::Item::BonusTrack;
use RPS::DB::Item::ControlledComposition;
use RPS::DB::Item::FinanceAccount;
use RPS::DB::Item::CALicenseReserve;
use RPS::DB::Item::CALicenseReserveRun;
use RPS::DB::Item::Master;
#use RPS::DB::Item::MechanicalCarryover;
use RPS::DB::Item::CAMechanicalRun;
#use RPS::DB::Item::CAMechanicalRunCarryover;
use RPS::DB::Item::CAMechanicalStatement;
use RPS::DB::Item::CAMechanicalStatementAdjustmentItem;
use RPS::DB::Item::CAMechanicalStatementCrossedLicenseTransaction;
use RPS::DB::Item::CAMechanicalStatementItem;
use RPS::DB::Item::CAMechanicalStatementLicense;
use RPS::DB::Item::CAMechanicalStatementLicenseTransaction;
use RPS::DB::Item::CAMechanicalStatementPublisher;
use RPS::DB::Item::CAMechanicalStatementPublisherTransaction;
use RPS::DB::Item::CAMechanicalStatementTrack;
use RPS::DB::Item::CAMechanicalStatementTransaction;
use RPS::DB::Item::CAPublisherIndirectBalanceAccount;
use RPS::DB::Item::CAPublisherTrackCrossedLicenseAccount;
use RPS::DB::Item::PendingTransaction;
use RPS::DB::Item::Product;
use RPS::DB::Item::ProductTrack;
use RPS::DB::Item::Publisher;
use RPS::DB::Item::PublisherAccount;
use RPS::DB::Item::PublisherTrackCrossedLicenseAccount;
use RPS::DB::Item::RegionCountryMap;
use RPS::DB::Item::ReserveLiquidation;
use RPS::DB::Item::SaleCAPublisherMap;
use RPS::DB::Item::SaleRunMap;
use RPS::DB::Item::Song;
use RPS::DB::Item::StatRate;
use RPS::DB::Item::Track;
use RPS::DB::Item::CATrackLicense;
use RPS::Mechanical::CA::MechanicalRun;
use RPS::Mechanical::Process::CreateStatement;
use RPS::Mechanical::Process::SaleException;

use RPS::Mechanical::Process::CreateStatement::Complex;
use base 'RPS::Mechanical::Process::CreateStatement::Complex';

#sub _defaultIssueStatRateID { return 9; }
sub _defaultIssueStatRateID { 

    my ($self, $licenseType) = @_;
    # This is the only possible value for CA (for now).
    #
    return 26; 
}

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

    return RPS::DB::Item::CATrackLicense->GetLicensesForPublisherStatement($self->_publisherID(), $self->_payorID());
}


sub _currencyCode
{
    my ($self) = @_;
    return 'CAD';
}

sub _getStatRates
{
    my ($self) = @_;
    return RPS::DB::Item::StatRate->GetRatesCA();
}

sub _createLicenseReserve
{
    my ($self, $statementItem, $units, $periodsRemaining) = @_;

    my $newReserve = RPS::DB::Item::CALicenseReserve->Create
    (
        ca_track_license_id => $statementItem->ca_track_license_id,
        original_statement_item_id => $statementItem->ca_mechanical_statement_item_id,
        product_id => $statementItem->product_id,
        sale_stat_rate_id => $statementItem->sale_stat_rate_id,
        issue_stat_rate_id => $statementItem->issue_stat_rate_id,
        units => $units,
        effective_rate => $statementItem->net_rate,
        periods_remaining => $periodsRemaining,
    );
    return $newReserve;
}

sub _getLicensesWithPendingTransactions
{
    my ($self) = @_;
    return RPS::DB::Item::CATrackLicense->GetLicensesWithPendingTransactionsForMechanicalStatement($self->_publisherID(), $self->_payorID());
}

sub _reserveType
{
    my ($self) = @_;
    return RPS::DB::Item::ReserveLiquidation::kTypeCAPublishingLicense;
}

sub _ringtoneStatRateType
{
    my ($self) = @_;
    return RPS::DB::Item::StatRate::kCARingStatRateType;
}

sub _lookupTrackLicense
{
    my ($self, $id) = @_;
    return RPS::DB::Item::CATrackLicense->Lookup(ca_track_license_id => $id);
}

sub _createStatementItem
{
    my ($self, $statementID, $trackLicenseID, $productID, $upc, $isrc, $saleStatRateID, $issueStatRateID) = @_;
    my $item = RPS::DB::Item::CAMechanicalStatementItem->Create
    (
        ca_mechanical_statement_id => $self->{_statementID},
        ca_track_license_id => $trackLicenseID,
        product_id => $productID,
        upc => $upc,
        isrc => $isrc,
        sale_stat_rate_id => $saleStatRateID,
        issue_stat_rate_id => $issueStatRateID,
    );
    return $item;
}

sub _createStatementLicense
{
    my ($self, $trackLicense) = @_;

    my $item = RPS::DB::Item::CAMechanicalStatementLicense->Create
    (
        ca_mechanical_statement_id => $self->_statementID(),
        ca_track_license_id => $trackLicense->ca_track_license_id(),
        region_id => $trackLicense->region_id(),
    );
    return $item;
}

sub _getStatementLicenseItemsByStatementID
{
    my ($self, $statementID) = @_;
    return RPS::DB::Item::CAMechanicalStatementLicense->GetByMechanicalStatementID($statementID);
}

sub _getStatementTrackItemsByStatementID
{
    my ($self, $statementID) = @_;
    return RPS::DB::Item::CAMechanicalStatementTrack->GetByMechanicalStatementID($statementID);
}

sub _getFileLabel
{
    my ($self, $run) = @_;
    return RPS::Mechanical::CA::MechanicalRun::GenerateFileLabel($run);
}

sub _lookupPublisher
{
    my ($self, $publisherID) = @_;
    return RPS::DB::Item::CAPublisher->Lookup(ca_publisher_id => $publisherID);
}

sub _lookupPublisherAccount
{
    my ($self, $publisherID, $payorID) = @_;
    return RPS::DB::Item::CAPublisherAccount->Lookup(ca_publisher_id => $publisherID, payor_id => $payorID);
}

sub _createPublisherAccount
{
    my ($self, $publisherID, $payorID) = @_;
    return RPS::DB::Item::CAPublisherAccount->Create
    (
        ca_publisher_id => $publisherID,
        payor_id => $payorID,
    );
}

sub _lookupStatementPublisherAccount
{
    my ($self, $publisherID, $payorID, $indirectPublisherID) = @_;
    return RPS::DB::Item::CAPublisherIndirectBalanceAccount->Lookup(ca_publisher_id => $publisherID, payor_id => $payorID, indirect_publisher_id => $indirectPublisherID);
}

sub _createStatementPublisherAccount
{
    my ($self, $publisherID, $payorID, $indirectPublisherID) = @_;
    return RPS::DB::Item::CAPublisherIndirectBalanceAccount->Create
    (
        ca_publisher_id => $publisherID,
        payor_id => $payorID,
        indirect_publisher_id => $indirectPublisherID,
    );
}

sub _getStatementTransactionItemsByStatementID
{
    my ($self, $statementID) = @_;
    return RPS::DB::Item::CAMechanicalStatementTransaction->GetByMechanicalStatementID($statementID);
}

sub _getStatementPublisherTransactionItems
{
    my ($self, $statementID, $publisherID) = @_;
    
    return RPS::DB::Item::CAMechanicalStatementPublisherTransaction->GetByMechanicalStatementAndPublisherID($statementID, $publisherID);
}

sub _publisherIDFromStatementTrackItem
{
    my ($self, $trackItem) = @_;
    return $trackItem->ca_publisher_id;
}

sub _publisherIDFromTrackLicense
{
    my ($self, $trackLicense) = @_;
    return $trackLicense->ca_publisher_id;
}

sub _publisherIDFromStatementItem
{
    my ($self, $statement) = @_;
    return $statement->ca_publisher_id();
}

sub _publisherIDFromStatementPublisher
{
    my ($self, $statementPublisher) = @_;
    return $statementPublisher->ca_publisher_id();
}

sub _idFromTrackLicense
{
    my ($self, $trackLicense) = @_;
    return $trackLicense->ca_track_license_id();
}

sub _idFromStatementItem
{
    my ($self, $statementItem) = @_;
    return $statementItem->ca_mechanical_statement_item_id();
}

sub _idFromStatement
{
    my ($self, $statement) = @_;
    return $statement->ca_mechanical_statement_id();
}

sub _publisherIDFromStatement
{
    my ($self, $statement) = @_;
    return $statement->ca_publisher_id();
}

sub _idFromStatementLicense
{
    my ($self, $statementLicense) = @_;
    return $statementLicense->ca_mechanical_statement_license_id();
}

sub _lookupPublisherTrackCrossedLicenseAccount
{
    my ($self, $publisherID, $trackID, $payorID) = @_;

    return RPS::DB::Item::CAPublisherTrackCrossedLicenseAccount->Lookup
    (
        ca_publisher_id => $publisherID,
        track_id => $trackID,
        payor_id => $payorID,
    );
}

sub _createPublisherTrackCrossedLicenseAccount
{
    my ($self, $publisherID, $trackID, $payorID, $accountID) = @_;

    return RPS::DB::Item::CAPublisherTrackCrossedLicenseAccount->Create
    (
        ca_publisher_id => $publisherID, 
        track_id => $trackID,
        payor_id => $payorID,
        finance_account_id => $accountID,
    );
}

sub _getStatementCrossedLicenseTransactions
{
    my ($self, $statementID, $publisherID, $trackID) = @_;

    return RPS::DB::Item::CAMechanicalStatementCrossedLicenseTransaction->GetByMechanicalStatementIDPublisherIDTrackID($statementID, $publisherID, $trackID);
}

sub _idFromStatementLicenseItem
{   
    my ($self, $licenseItem) = @_;
    return $licenseItem->ca_mechanical_statement_license_id();
}

sub _trackLicenseIDFromStatementLicenseItem
{
    my ($self, $licenseItem) = @_;
    return $licenseItem->ca_track_license_id();
}

sub _getStatementLicenseTransactionsByStatementLicenseID
{
    my ($self, $statementLicenseID) = @_;
    return RPS::DB::Item::CAMechanicalStatementLicenseTransaction->GetByMechanicalStatementLicenseID($statementLicenseID);
}

sub _createStatementLicenseTransaction
{
    my ($self, $licenseItemID) = @_;
    return RPS::DB::Item::CAMechanicalStatementLicenseTransaction->Create
    (
	    'ca_mechanical_statement_license_id'   => $licenseItemID,
    );
}

sub _getAllCommittedLicenseReservesByTrackLicenseID
{
    my ($self, $trackLicenseID) = @_;
    return RPS::DB::Item::CALicenseReserve->GetAllCommittedByTrackLicenseID($trackLicenseID);
}

sub _createLicenseReserveRunItem
{
    my ($self, $reserve) = @_;
    return RPS::DB::Item::CALicenseReserveRun->Create
    (
        ca_license_reserve_id => $reserve->ca_license_reserve_id,
        ca_mechanical_run_id => $self->_runID(),
    );
}

# !!! I am NOT going to implement this.
# !!! We don't want to have _any_ carryover in canadian mechanicals.
#
sub _getAllMechanicalCarryoverByTrackLicenseID
{
}

#
#sub _createMechanicalRunCarryover
#{
#    my ($self, $carryover) = @_;
#
#    my $mechanicalRunCarryoverItem = RPS::DB::Item::MechanicalRunCarryover->Create
#    (
#        mechanical_carryover_id => $carryover->mechanical_carryover_id,
#        mechanical_run_id => $self->_runID(),
#    );
#}

sub _getLicensesForPublisherStatementWithTrackAndRegion
{
    my ($self, $trackID, $regionID, $startDate, $endDate, $publisherID) = @_;
    return RPS::DB::Item::CATrackLicense->GetLicensesForPublisherStatementWithTrackAndRegion($trackID, $regionID, $startDate, $endDate, $publisherID, $self->_payorID());
}


sub _getPaidSaleRunMapForLicense
{
    my ($self, $license) = @_;

    return RPS::DB::Item::SaleRunMap->GetPaidCAMechanicalsWithTrackLicense($license->ca_track_license_id);
}

sub _lookupMechanicalStatementItem
{
    my ($self, $statementItemID) = @_;
    return RPS::DB::Item::CAMechanicalStatementItem->Lookup(ca_mechanical_statement_item_id => $statementItemID);
}

sub _getLastStatementAdjustmentItem
{
    my ($self, $statementItemID) = @_;
    return RPS::DB::Item::CAMechanicalStatementAdjustmentItem->GetLastStatementAdjustment($statementItemID);
}

sub _idFromStatementAdjustmentItem
{
    my ($self, $lastAdjustment) = @_;
    return $lastAdjustment->ca_mechanical_statement_adjustment_item_id;
}

sub _idFromRunItem
{
    my ($self, $run) = @_;
    return $run->ca_mechanical_run_id;
}

sub _getStatementPublisherFromAccount
{
    my ($self, $account) = @_;
    my $publisherID = $account->ca_publisher_id;
    my $publisher;
    
    my $statementPublishers =  RPS::DB::Item::CAMechanicalStatementPublisher->GetByMechanicalStatementAndPublisherID($self->_statementID(),$publisherID);
    while (my $statementPublisher = $statementPublishers->next())
    {
        $publisher = $statementPublisher;
    }   
    
    if (! $publisher)
    {
        $publisher =  $self->_createStatementPublisher($publisherID);  
    }
    
    return $publisher;
}

sub _getSubPublisherIDs
{
   my ($self, $statementID) = @_;
   
#   my @ids = RPS::DB::Item::CAMechanicalStatementPublisherTransaction->GetSubPublisherIDs($statementID);
    my @ids;
    my $allPublishers = RPS::DB::Item::CAMechanicalStatementPublisher->GetByMechanicalStatementID($statementID);
    while (my $p = $allPublishers->next())
    {
        push @ids, $p->ca_publisher_id;
    }
    
   return @ids; 
}
    

sub _getPublisherStatement
{
    my ($self, $statementID, $publisherID) = @_;
    
    my $publisherStatement;
    
    $publisherStatement = RPS::DB::Item::CAMechanicalStatementPublisher->Lookup(ca_mechanical_statement_id => $statementID, ca_publisher_id => $publisherID); 
    
    return $publisherStatement;
}

sub _getIndirectAccountByPayorIndirectPublisherID
{
    my ($self, $payorID, $publisherID) = @_;
    my $indirectAccounts = RPS::DB::Item::CAPublisherIndirectBalanceAccount->GetByPayorIndirectPublisherID($payorID, $publisherID);
    
    return $indirectAccounts;
}

sub _createStatementAdjustmentItem
{
    my ($self, $license, $originalStatementItemID, $lastAdjustmentID, $adjustmentAmount, $total) = @_;

    return RPS::DB::Item::CAMechanicalStatementAdjustmentItem->Create
    (
        ca_mechanical_statement_id => $self->_statementID(),
        ca_track_license_id => $license->ca_track_license_id(),
        original_ca_mechanical_statement_item_id => $originalStatementItemID,
        previous_ca_mechanical_statement_adjustment_item_id => $lastAdjustmentID,
        amount => $adjustmentAmount,
        new_total => $total,
        adjustment_type_code => RPS::DB::Item::CAMechanicalStatementAdjustmentItem::kAdjustmentTypeCCompNewLicense, #!!! is this really accurate?
    );
}

sub _createStatementPublisher
{
    my ($self, $publisherID) = @_;
    return RPS::DB::Item::CAMechanicalStatementPublisher->Create
    (
        ca_mechanical_statement_id => $self->_statementID(),
        ca_publisher_id => $publisherID,
    );
}

sub _createStatementTrack
{
    my ($self, $publisherID, $trackID, $albumID, $songTitle) = @_;
    return RPS::DB::Item::CAMechanicalStatementTrack->Create
    (
        ca_mechanical_statement_id => $self->_statementID(),
        ca_publisher_id => $publisherID,
        track_id => $trackID,
        album_id => $albumID,
        song_title => $songTitle,
    );
}

sub _createStatementCrossedLicenseTransaction
{
    my ($self, $statementLicense, $publisherID, $trackID, $pendingTrans) = @_;

    return RPS::DB::Item::CAMechanicalStatementCrossedLicenseTransaction->Create
    (
        #ca_mechanical_statement_license_id => $statementLicense->ca_mechanical_statement_license_id,
        ca_mechanical_statement_id => $self->_statementID(),
        ca_publisher_id => $publisherID,
        track_id => $trackID,
        amount => $pendingTrans->amount,
        memo => $pendingTrans->memo,
        check_number => $pendingTrans->check_number,
        pending_transaction_id => $pendingTrans->pending_transaction_id,
        transaction_date => $pendingTrans->transaction_date,
        type_code => $pendingTrans->type_code,
    );
}

sub _createStatementTransactionFromPendingTransaction
{
    my ($self, $pendingTrans) = @_;
    return RPS::DB::Item::CAMechanicalStatementTransaction->Create
    (
        ca_mechanical_statement_id => $self->_statementID(),
        amount                  => $pendingTrans->amount(),
        memo                    => $pendingTrans->memo(),
        check_number            => $pendingTrans->check_number(),
        pending_transaction_id  => $pendingTrans->pending_transaction_id(),
        transaction_date        => $pendingTrans->transaction_date(),
        type_code               => $pendingTrans->type_code(),
    );
}

sub _createPublisherStatementTransactionFromPendingTransaction
{
    my ($self, $pendingTrans, $account) = @_;
    return RPS::DB::Item::CAMechanicalStatementPublisherTransaction->Create
    (
        ca_mechanical_statement_id => $self->_statementID(),
        ca_publisher_id            => $account->ca_publisher_id(),
        amount                     => $pendingTrans->amount(),
        memo                       => $pendingTrans->memo(),
        check_number               => $pendingTrans->check_number(),
        pending_transaction_id     => $pendingTrans->pending_transaction_id(),
        transaction_date           => $pendingTrans->transaction_date(),
        type_code                  => $pendingTrans->type_code(),
    );
}

sub _getLicensesByTrackIDAndDate
{
    my ($self, $trackID, $startDate, $endDate) = @_;
    return RPS::DB::Item::CATrackLicense->GetLicensesByTrackIDAndDate($trackID, $startDate, $endDate);
}

sub _getLicensesByTrackID
{
    my ($self, $trackID) = @_;
    return RPS::DB::Item::CATrackLicense->GetLicensesByTrackID($trackID);
}

sub _testAlreadyPaidSaleWithLicense
{   
    my ($self, $sale, $trackLicense) = @_;

    return RPS::DB::Item::SaleRunMap->HavePaidCAMechanicalsForSaleWithTrackLicense($sale->sale_id, $trackLicense->ca_track_license_id);
}

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

    my $statement = RPS::DB::Item::CAMechanicalStatement->Lookup(ca_mechanical_statement_id => $self->{_statementID});
    return $statement;
}

sub _runType
{
    my ($self) = @_;
    return RPS::DB::Item::SaleRunMap::kRunTypeCAMechanical;
}

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

    my $statement = $self->_getStatementDBItem();
    my $runID = $statement->ca_mechanical_run_id;
    my $run = RPS::DB::Item::CAMechanicalRun->Lookup(ca_mechanical_run_id => $runID);
    return $run;
}

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

    # Read the sales to process from the SalePublisherMap table
    # !!! Actually, I am going to put this interface into Raptor::Sale, so it makes more sense.
    #
    my $statement = $self->_getStatementDBItem();

    return RPS::DB::Item::SaleCAPublisherMap->GetPublisherMappedSaleIDs($statement->ca_publisher_id, $statement->ca_mechanical_run_id);
}

sub _getControlledCompContractByAlbumID
{
	my ($self, $albumID) = @_;
	return RPS::DB::Item::AlbumContract->GetCACComp($albumID);
}


sub _trackIsExemptFromMechanicals
{
	my ($self, $trackID) = @_;

	my $track = $self->_getTrack($trackID);
	return $track->ca_mechanical_exempt;
}

1;
