#------------------------------------------------------------
# Copyright (C) 2006 RoyaltyShare, Inc.   All Rights Reserved
#------------------------------------------------------------
package RPS::ArtistRoyalty::Utils;

use Data::Dumper;
use strict;
use warnings;

use lib '/app/tools/rps/lib';
use RPS::DB::Item::PriceLevel;
use RPS::DB::Item::ContractRateType;
use RPS::DB::Item::ContractTermSource;
use RPS::DB::Item::NewArtistContract;
use RPS::DB::Item::NewArtistContractTerm;
use RPS::DB::Item::TrackContract;
use RPS::DB::Item::AlbumContract;
use RPS::DB::Item::RegionCountryMap;


#
# This package is to contain some helpful functions that will be used
# by various scripts that deal with artist contracts.
# Basically, these (initially, anyway) are functions that used to be
# in the run_royalties.pl script that needed to be accessable by other
# scripts.
#


# GetMatchingContracts
# - Returns an array reference which contains all the RPS::DBItem::ArtistContracts
#   that match the given album and track ids
#
my %gCachedContracts;

sub GetMatchingContracts
{
    my ($albumID, $trackID, $payors) = @_;

    $trackID = 0 unless $trackID;

    my $payorsString = join(',', @$payors);

    # !!! Ultimately I'd like to build a data structure all in one go for everybody.
    # !!! But for now, let's see if caching lazily will speed things up some.
    #
    if (! $gCachedContracts{$payorsString}{$albumID}{$trackID})
    {
#        my @payors = split(',', $payorsString);

        my %payeeContractHash;


        # Transform the list of payor ids into an identity hash
        #
        my %payorIDMap;
        foreach my $payorID (@$payors)
        {
            $payorIDMap{$payorID} = 1;
        }


        # Matching rules:
        # If there is a trackID:
        #   get all the track contracts that match that track
        #   get all the album contracts that match that album, unless we already have a contract for that payee.
        # If there is not a track ID:
        #   get all the track contracts that match that album (are attached to tracks on that album). Can be multiple per payee.
        #   get all the album contracts that match that album, unless there are already contracts for that payee.

        # Note that the same contract can appear multiple times, and will need to be _paid_ multiple times.
        #
        my $trackContracts;
        if ($trackID)
        {
            $trackContracts = RPS::DB::Item::TrackContract->GetByTrackID($trackID);
        }
        else
        {
            $trackContracts = RPS::DB::Item::TrackContract->GetByAlbumID($albumID);
        }

        while (my $trackContract = $trackContracts->next())
        {
            # Skip the inactive contracts
            #
            next if (RPS::DB::Item::TrackContract::kStatusActive != $trackContract->status());

            my $artistContract = RPS::DB::Item::NewArtistContract->Lookup(artist_contract_id => $trackContract->artist_contract_id);

            # Does this contract 'belong' to one of the requested payors?
            #
            next unless ($payorIDMap{ $artistContract->payor_id });

            push @{$payeeContractHash{$artistContract->artist_payee_id}{$artistContract->artist_contract_id}},
            {
                artistContract => $artistContract,
                albumID => $albumID,
                trackID => $trackContract->track_id,
                prorateTrackCount => $trackContract->prorate_track_count,
            };

        }

        my $albumContracts = RPS::DB::Item::AlbumContract->GetByAlbumID($albumID);
        while (my $albumContract = $albumContracts->next())
        {
            # Skip the inactive contracts
            #
            next if (RPS::DB::Item::AlbumContract::kStatusActive != $albumContract->status());

            my $artistContract = RPS::DB::Item::NewArtistContract->Lookup(artist_contract_id => $albumContract->artist_contract_id);

            # Does this contract 'belong' to one of the requested payors?
            #
            next unless ($payorIDMap{ $artistContract->payor_id });

            push @{$payeeContractHash{$artistContract->artist_payee_id}{$artistContract->artist_contract_id}},
            {
                artistContract => $artistContract,
                albumID => $albumID,
            };
        }

        # Now flatten the hash into a simple array of contracts.
        #
        my @contracts;
        foreach my $payeeID (keys %payeeContractHash)
        {
            my $contractIDHash = $payeeContractHash{$payeeID};
            foreach my $contractID (%$contractIDHash)
            {
                my $arrayRef = $contractIDHash->{$contractID};
                foreach my $contract (@$arrayRef)
                {
                    push @contracts, $contract;
                }
            }
        }

        $gCachedContracts{$payorsString}{$albumID}{$trackID} = \@contracts;
    }

    return $gCachedContracts{$payorsString}{$albumID}{$trackID};
}


my $gSourceIDMap;
sub _GetContractTermSourceIDsForIncomeSourceID
{
    my ($incomeSourceID) = @_;

    if (! $gSourceIDMap)
    {
        $gSourceIDMap = RPS::DB::Item::ContractTermSource->GetAllContractTermIncomeSourceMap();
    }

    return $gSourceIDMap->{$incomeSourceID};
}


sub GetMatchingTerm
{
    my ($contract, $countryCode, $channelID, $incomeSourceID, $priceLevelID, $wholesalePrice, $retailPrice) = @_;


    # Need to translate incomeSourceID into a set of contract_term_source_ids.
    #
    my $contractTermSourceIDs = _GetContractTermSourceIDsForIncomeSourceID($incomeSourceID);

    my $terms = RPS::DB::Item::NewArtistContractTerm->GetMatchingTerms
    (
        artist_contract_id  => $contract->artist_contract_id(),
        country_code        => $countryCode,
        channel_id          => $channelID,
        contract_term_source_id    => $contractTermSourceIDs,
        price_level_id      => $priceLevelID,
    );

#Common::Log::Print("GetMatchingTerm:  number of terms returned:" . $terms->size());

    my $matchingTerm;
    while (my $possibleTerm = $terms->next())
    {
        if ($possibleTerm->contract_rate_type_id == RPS::DB::Item::ContractRateType::kRateTypePercentDocumentRetail && (!$retailPrice || $retailPrice == 0))
        {
            next;
        }
        if ($possibleTerm->contract_rate_type_id == RPS::DB::Item::ContractRateType::kRateTypePercentDocumentWholesale && (!$wholesalePrice || $wholesalePrice == 0))
        {
            next;
        }

        $matchingTerm = $possibleTerm;
#Common::Log::Print("  selected a term");
        last;
    }

    if (! $matchingTerm)
    {
        # Try and fetch the default term.
        # !!! Suitable for caching, probably.
        #

#Common::Log::Print("  getting the default term");
        $matchingTerm = RPS::DB::Item::NewArtistContractTerm->GetActiveDefault($contract->artist_contract_id());
    }

#Common::Log::Print("-- selected this term:", $matchingTerm);
    return $matchingTerm;
}


sub OLD_GetMatchingTerm
{
    my ($contract, $countryCode, $channelID, $incomeSourceID, $priceLevelID, $wholesalePrice, $retailPrice) = @_;

#print STDERR "--- GetMatchingTerm : contract_id " . $contract->artist_contract_id . " , region $regionID channel $channelID Source $incomeSourceID  priceLevel $priceLevelID\ wholesalePrice $wholesalePrice retailPrice $retailPrice n";

    # Find the term in this contract that best matches this sale.
    #
    my $terms = RPS::DB::Item::NewArtistContractTerm->GetActiveByArtistContractID($contract->artist_contract_id);
#    my $defaultTerm = $terms->next();

    my $defaultTerm;
    my $matchingTerm;
    while (my $possibleTerm = $terms->next())
    {
        if (0 == $possibleTerm->priority)
        {
            $defaultTerm = $possibleTerm;
            next;
        }

#        print STDERR "------ looking at term: " . Dumper($possibleTerm) . "\n";
#        if (_regionIDMatches($regionID, $possibleTerm->region_id)
        if (_countryCodeMatches($countryCode, $possibleTerm->region_id)
            && _channelIDMatches($channelID, $possibleTerm->channel_id)
            && _incomeSourceMatches($incomeSourceID, $possibleTerm->contract_term_source_id)
            && _priceLevelMatches($priceLevelID, $possibleTerm->price_level_id)
            )
        {

            # If we found a match with a document price term,
            # let's make sure we have the right data for it.

            if ($possibleTerm->contract_rate_type_id == RPS::DB::Item::ContractRateType::kRateTypePercentDocumentRetail && (!$retailPrice || $retailPrice == 0))
            {
                next;
            }
            if ($possibleTerm->contract_rate_type_id == RPS::DB::Item::ContractRateType::kRateTypePercentDocumentWholesale && (!$wholesalePrice || $wholesalePrice == 0))
            {
                next;
            }


            $matchingTerm = $possibleTerm;
            last;
        }
    }

    if (! $matchingTerm)
    {
Common::Log::Print("  getting the default term");
        $matchingTerm = $defaultTerm;
    }

Common::Log::Print("-- selected this term:", $matchingTerm);
    return $matchingTerm;
}


sub _countryCodeMatches
{
    my ($countryCode, $regionID) = @_;

    return 1 if (0 == $regionID);

    # Does this region contain this country?
    #
    my $mapEntry = RPS::DB::Item::RegionCountryMap->Lookup(region_id => $regionID, country_code => $countryCode);
    return (defined $mapEntry);
}

sub _defaultFieldMatch
{
    my ($field1, $field2) = @_;

    if (! $field2)
    {
#        print STDERR "----------- match (term 2 not defined)\n";
        return 1;
    }

    # (XXX) Disable wildcard matching for the moment.
    #
    if ($field1 == $field2)
    {
#        print STDERR "----------- match\n";
        return 1;
    }

# jpk - We had initially thought we were going to support wildcard matching...
#       But it now appears we have backed away from that somewhat.
#       Going to leave this code in here in case we change our minds...
#
#    if (RPS::DB::Item::ArtistContractTerms::kAll == $field2
#     || $field1 == $field2)
#    {
#        return 1;
#    }

#    print STDERR "----------- no match\n";
    return 0;
}

sub _regionIDMatches
{
    my ($r1, $r2) = @_;
#    print STDERR "--------- regionIDMatches $r1 == $r2 \n";
    return _defaultFieldMatch($r1, $r2);
}

sub _channelIDMatches
{
    my ($c1, $c2) = @_;
#    print STDERR "---------channelIDMatches $c1 == $c2 \n";
    return _defaultFieldMatch($c1, $c2);
}

sub _incomeSourceMatches
{
    my ($incomeSourceID, $contractTermSourceID) = @_;

#    print STDERR "---------incomeSourceMatch IS: $incomeSourceID, CTS: $contractTermSourceID\n";
    return RPS::DB::Item::ContractTermSource->containsIncomeSource( $incomeSourceID, $contractTermSourceID );
}

sub _priceLevelMatches
{
    my ($p1, $p2) = @_;
#    print STDERR "---------priceLevelMatches $p1 == $p2 \n";
    return _defaultFieldMatch($p1, $p2);
}


1;
