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

# Mechanical runs, no matter what country, have many elements in common.
# So we have this base class that serves to abstract away that stuff.
#
package RPS::Mechanical::Process::RunController::Complex;
use strict;
use Data::Dumper;
use File::Path;

use lib '/app/tools/common/lib';
use lib '/app/tools/rps/lib';
use lib '/app/tools/job/lib';
use Common::Assert;
use Common::RSApp;
use Common::Log;
use Common::DB::Item;

use RPS::Statement::Status;
use Job::Status;
use RPS::RoyaltyRun::Status;
use RPS::DB::Item::MechanicalRunTrackLicense;
use RPS::DB::Item::SalePublisherMap;
use RPS::DB::Item::ClientOptions;

use base 'RPS::Mechanical::Process::RunController';

sub _runType {
    my ($self) = @_;
    assert( 0, 'override this to return the correct SaleRunMap constant' );
}

sub _createUnlicensedTrackLogEntry {
    my ( $self, $track, $product, $upc, $productType, $missingShare, $totalOwed, $units, $year, $rate ) = @_;
    assert( 0, 'override this' );
}

sub _getMechanicalRunTrackLicenseItems {
    my ($self) = @_;
    assert( 0, 'override this' );
}

sub _deleteMechanicalRunTrackLicenseItems {
    my ($self) = @_;
    assert( 0, 'override this' );
}

sub _createReservePipelineReport {
    my ($self) = @_;
    assert( 0, 'override this' );
}

sub _createSalePublisherLicenseEntry {
    my ( $self, $saleID, $publisherID, $trackLicenses ) = @_;
    assert( 0, 'override this' );
}

sub _initializeSalePublisherLicenseMap {
    my ( $self ) = shift;
    assert( 0, 'override this' );
}

sub _clearLicenseCache {
    my ( $self ) = shift;
    assert( 0, 'override this' );
}

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

    # call the inherited method first.
    #
    $self->SUPER::delete();

    # Make sure any 'temporary' data is deleted from the database.
    # Usually this happens automatically for a normal run, but if the run
    # errored out then this data might still be hanging around.
    #
    $self->_deleteMechanicalRunTrackLicenseItems();

    return 0;
}

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

    # Probably the easiest thing would be to read in the whole table, and
    # hash it appropriately.
    #
    my %missingShareMap;

    # !!! If we extend the table to include country code, then we can abstract this access method to just return
    # !!! the rows from the country or contries we care about.
    #
    #    my $allItems = RPS::DB::Item::MechanicalRunTrackLicense->GetByRunIDAndType($self->{_runID}, $self->_runType);
    my $allItems = $self->_getMechanicalRunTrackLicenseItems();
    while ( my $item = $allItems->next() ) {
        my $productID     = $item->product_id;
        my $product       = $self->_getProduct($productID);
        my $productTypeID = $product->product_type_id;
        my $productType   = $self->_getProductType($productTypeID);
        $productType = $productType->description;

        # Look at the track license - If it's a RINGTONE license, then set productType to 'RING'
        #
        my $trackLicenseID = $item->track_license_id();
        if ($trackLicenseID) {
            my $trackLicense = $self->_trackLicenseFromID($trackLicenseID);
            if ( $trackLicense && 5 == $trackLicense->type ) {
                $productType = 'RING';
            }
        }

        push @{ $missingShareMap{ $item->track_id }{ $item->product_id }{$productType}{ $item->track_license_id } },
          {
            share => $item->share,
            units => $item->units,
            rate  => $item->base_rate,
            year  => $item->year,
          };
    }

    $self->_report( "_createRetentionReport", 4 );
    $self->_report( \%missingShareMap,        4 );

    # Now build the report
    #
    foreach my $trackID ( keys %missingShareMap ) {
        my $track = $self->_getTrack($trackID);
        if ( defined($track) ) {
            my $album    = $self->_getAlbum( $track->album_id );
            my $master   = $self->_getMaster( $track->master_id );
            my $duration = $master->duration;

            #next if ($track->mechanical_exempt);

            my $productIDHash = $missingShareMap{$trackID};
            foreach my $productID ( keys %$productIDHash ) {
                my $product = $self->_getProduct($productID);
                my $upc     = $product->upc_ean;

                my $productTypeHash = $productIDHash->{$productID};
                foreach my $productType ( keys %$productTypeHash ) {
                    my %rateUnitHash;
                    my $totalShare;

                    my $trackLicenseIDHash = $productTypeHash->{$productType};
                    my $nLicenses          = keys %$trackLicenseIDHash;

                    foreach my $trackLicenseID ( keys %$trackLicenseIDHash ) {
                        my $share;

                        my $dataArray = $trackLicenseIDHash->{$trackLicenseID};
                        foreach my $data (@$dataArray) {
                            my $units = $data->{units};

                            # !!! Making an assumption here, that this is the same for all data items that
                            # !!! hashed to this location.
                            #
                            $rateUnitHash{ $data->{rate} }{ $data->{year} } += $data->{units};

                            $share = $data->{share};
                        }

                        $totalShare += $share;
                    }

                    if ( $totalShare < 99 ) {
                        my $missingShare = 100 - $totalShare;
                        foreach my $baseRate ( keys %rateUnitHash ) {
                            my %totalOwedHash;    # keep track of accrual by date range

                            my $yearUnitHash = $rateUnitHash{$baseRate};
                            foreach my $year ( keys %$yearUnitHash ) {
                                # Note: Correct the unit count by dividing by the number of licenses looked at (RSD-4819).
                                my $units = $yearUnitHash->{$year} / $nLicenses;
                                $totalOwedHash{$year}{accrual} += $units * $baseRate;
                                $totalOwedHash{$year}{units} += $units;

                            }


                            foreach my $year ( keys %$yearUnitHash ) {
                                if ($totalOwedHash{$year}{units} || $totalOwedHash{$year}{accrual}) {
                                    $self->_createUnlicensedTrackLogEntry(
                                        $track, $product, $upc, $productType, $missingShare,
                                        $totalOwedHash{$year}{accrual},
                                        $totalOwedHash{$year}{units},
                                        $year, $baseRate
                                    );
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    # Now delete everything in the temporary table.
    #
    $self->_deleteMechanicalRunTrackLicenseItems();

    #    my $allItems = $self->_getMechanicalRunTrackLicenseItems();
}    # _createRetentionReport

sub _logPublicDomainShare {
    my ( $self, $sale, $trackID, $trackLicense, $share ) = @_;

    my $runID          = $self->{_runID};
    my $runType        = $self->_runType();
    my $productID      = $sale->product_id;
    my $saleStatRateID = $self->_getStatRateID( $sale->date_end );
    my $duration       = $self->_getTrackDuration($trackID);
    my $trackLicenseID = $self->_idFromTrackLicense($trackLicense);

    my $countryCode = $sale->country_code;
    my $units       = $sale->units;
    my $numSales    = $sale->sales;
    my $numReturns  = $sale->returns;

    my $year = $self->_getYear($sale);

    my $product = $self->_getProduct($productID);
    if ( $self->_productIsDigital($product) ) {
        if ( $units < 0 ) {
            $numReturns = ( -1 * $units );
        } else {
            $numSales = $units;
        }
    } else {
        $units = $numSales - $numReturns;
    }

    # Here's the trick part: _calculateEffectiveRate !!!
    # This is defined in CreateStatement::Complex, so not in our current scope.
    # !!! But, I believe we can move that to the base class.

    # Calculate what the rate would be, assuming the worst.
    #
    my ($rate) = $self->_calculateEffectiveRate(
        $self->_defaultIssueStatRateID(RPS::DB::Item::TrackLicense::kPublicDomain),
        $saleStatRateID, RPS::License::RateBasis::kSale,
        RPS::License::RateType::kFull, 0, 100, $duration, 100, 0, $trackLicense
    );

    RPS::DB::Item::MechanicalRunTrackLicense->updateUnits(
        run_id           => $runID,
        run_type         => $runType,
        track_license_id => $trackLicenseID,
        product_id       => $productID,
        track_id         => $trackID,
        base_rate        => $rate,
        units            => $units,
        share            => $share,
        country_code     => $countryCode,
        year             => $year,
    );
}

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

    $self->_report( "_createSalePublisherMapping", 3 );

    # To speed this up, we're going to cache a few tables.
    #
    my %productCache;
    my $allProducts = RPS::DB::Item::Product->GetAll();
    while ( my $product = $allProducts->next() ) {
        $productCache{ $product->product_id() } = $product;
    }

    my %productTrackCache;
    my $allProductTracks = RPS::DB::Item::ProductTrack->GetAll();
    while ( my $productTrack = $allProductTracks->next() ) {
        push @{ $productTrackCache{ $productTrack->product_id() } }, $productTrack->track_id;
    }

    # Limit this using our payor id
    my %trackLicenseCache;
    my $allTrackLicenses = $self->_getAllTrackLicenses();
    while ( my $tl = $allTrackLicenses->next() ) {

        # Skip inactive licenses.
        #
        next if $tl->inactive();

        # Skip licenses attached to tracks that are exempt from mechanicals...
        #
        my $track = $self->_getTrack( $tl->track_id );

        next if ( $self->_trackIsMechanicalExempt($track) );

        if ( $tl->payor_id == $self->{_payorID} || RPS::DB::Item::TrackLicense::kPublicDomain == $tl->type() ) {
            push @{ $trackLicenseCache{ $tl->track_id() } }, $tl;
        }
    }

    # Fetch all the publishers too.
    # We'll want to know their admin/agent ids.
    #
    my %publisherCache;
    my $allPublishers = $self->_getAllPublishers();
    while ( my $pub = $allPublishers->next() ) {
        my $publisherID = $self->_publisherIDFromPublisher($pub);
        $publisherCache{$publisherID} = $pub;
    }

    # We'll use this hash to keep track of any track sales that are totally unlicensed.
    #
    my %unlicensedTracks;

    my $run      = $self->_getRunDBItem();
    my $t1 = Time::HiRes::gettimeofday(); # XXX

    my $allSales = $self->_getAllUnprocessedSales( $run->ending_sale_date() );
    my $t2 = Time::HiRes::gettimeofday(); # XXX
    print STDERR " >> Process/Runcontroller/Complex/_createSalePublisherMapping - retrieved ". $allSales->size() . " sales in ". ($t2 - $t1) . " second(s)\n"; # XXX
    $self->_report( "_createSalePublisherMapping - scanning sales: count= " . $allSales->size(), 3 );
    while ( my $sale = $allSales->next() ) {
        my %salePublisherHash;

        $self->_report( "looking at sale id " . $sale->sale_id, 3 );
        $self->_report( $sale,                                  4 );

        if ( !$sale->product_id() ) {
            $self->_report( "  skipping - no product id", 4 );
            next;
        }
        my $product = $productCache{ $sale->product_id() };
        if ( !$product ) {
            $self->_report( "  skipping - product not in cache", 4 );
            next;
        }

        # Going to need to know how many units for the unlicensed report.
        #
        my $units = $sale->units;
        if ( !$units ) {
            $units = $sale->sales - $sale->returns;
        }

        # FB14251 - save the year so that it can be surfaced on the accrual report
        #
        my $year = $self->_getYear($sale);

        # !!! A hack for now...
        #
        my $saleStatRateID;

        # JPK - Restore when we're ready for RINGBACK
        #        if ($sale->format_type eq 'R' || $sale->format_type eq '1')
        if ( $sale->format_type eq 'R' ) {
            $saleStatRateID = $self->_getRingStatRateID( $sale->date_end );
        } else {
            $saleStatRateID = $self->_getStatRateID( $sale->date_end );
        }

        # We'll attempt to grab the upc from the parent product first.
        my $upc;
        if ( $product->parent_product_id && $productCache{ $product->parent_product_id } ) {
            my $parentProduct = $productCache{ $product->parent_product_id };
            $upc = $parentProduct->upc_ean;
        } else {
            $upc = $product->upc_ean;
        }

        my $productTypeID = $product->product_type_id;
        my $productType   = $self->_getProductType($productTypeID);

        # !!! This never made it to the CA mechanicals.
        #
        # One off to change product type label to RING for the report. CASE #10576
        # JPK - Restore when we're ready for RINGBACK
        $productType = $sale->format_type eq 'R' ? 'RING' : $productType->description;

        my $tracks;
        if ( RPS::DB::Item::Product::kProductTypeDigitalTrack == $product->product_type_id ) {
            $tracks = [ $product->asset_id() ];
        } else {
            $tracks = $productTrackCache{ $product->product_id() };
        }

        # We'll count the number of track licenses encountered for each track associated with this sale.
        # If there aren't _any_ found for any of the tracks on this sale, then we'll log this sale
        # as totally unlicensed.
        #
        my $saleLicenseCount = 0;

        foreach my $trackID (@$tracks) {

            # !!! At some point, we will be able to skip tracks that have a license for an other payor.
            # The theory being that we will associate payor at the ALBUM level, so we won't be able to
            # have multiple payors on a single product.
            #
            # However, as of right now (11/2009), we have at least one client (Madacy) where this is not true.
            #
            $self->_report( "  product track $trackID", 4 );

            # !!! Ok, so here's the trick.
            # !!! Let's just look at the licenses that WILL ACTUALLY apply.
            #
            my $licenses = $self->_getLicensesThatMatchSale( $sale, $trackLicenseCache{$trackID} );

            foreach my $trackLicense (@$licenses) {
                $self->_report( "     track license " . $self->_idFromTrackLicense($trackLicense), 4 );

                if ( RPS::DB::Item::TrackLicense::kPublicDomain == $trackLicense->type ) {

                    # JPK - We'll put the country test inside the override of _logPublicDomainShare, so we can stay abstract here.
                    #
                    $self->_logPublicDomainShare( $sale, $trackID, $trackLicense, $trackLicense->share );
                    next;
                }

                # Which publisher ID to use?
                # If it is not a direct license, use the agent/admin if there is one.
                #
                my $publisherID = $self->_publisherIDFromTrackLicense($trackLicense);
                my $publisher   = $publisherCache{$publisherID};
                my $indirectID  = $publisher->agent_id;
                $indirectID = $publisher->admin_id unless $indirectID;

                if ( !$trackLicense->publisher_direct() && $indirectID ) {
                    $self->_report( "   indirect id = $indirectID", 4 );
                    $salePublisherHash{$indirectID} = 1;
                } else {
                    $self->_report( "   direct id = $publisherID", 4 );
                    $salePublisherHash{$publisherID} = 1;
                }
            }

            # If there weren't _any_ licenses for that track, in theory that's an accrual, right?
            #
            if ( 0 != scalar @$licenses ) {
                $self->_report( "  incrementing saleLicenseCount", 4 );
                $saleLicenseCount++;
            } else {
                $self->_report(
                    "  NO LICENSES FOUND FOR SALE_ID " . $sale->sale_id . " : PRODUCT_ID : " . $product->product_id . " TRACK ID $trackID",
                    4
                );

                # Don't bother logging accrual for non US or CA digital sales.
                # JPK - No... don't bother logging accrual for any sale outside of the US, no matter what kind.
                # !!! We'll need a 'native country code' method to make this abstract.
                #
                if ( $self->_nativeCountryCode() eq $sale->country_code ) {
                    my $productID = $product->product_id;
                    $self->_report( " incrementing units by $units", 4 );

                    # FB14251 - store the date range information with the stat rate ID
                    # The units will be aggregated for each statRateID by year.
                    #
                    # Depending on the format types of the matched sales, it's possible to have
                    # accruals for different product types even though they're matched to the same
                    # product.  For example, RING and DT sales matched to a DT product.
                    #
                    $unlicensedTracks{$trackID}{$productID}{$productType}{STATRATE}{$saleStatRateID}{$year}{units} += $units;

                    $unlicensedTracks{$trackID}{$productID}{$productType}{upc} = $upc;
                } else {
                    $self->_report( " sale country is " . $sale->country_code . ", so we ignore the accrual. Not logging.", 4 );
                }
            }
        }    # foreach trackID

        foreach my $publisherID ( keys %salePublisherHash ) {
            $self->_report( "  creating SalePublisherMap for publisher $publisherID", 4 );
            $self->_createSalePublisherMapEntry(
                run_id       => $self->{_runID},
                sale_id      => $sale->sale_id(),
                publisher_id => $publisherID,
            );

            #            my $newMapItem = RPS::DB::Item::SalePublisherMap->Create
            #            (
            #                run_id => $self->{_runID},
            #                sale_id => $sale->sale_id(),
            #                publisher_id => $publisherID,
            #            );
            #            $newMapItem->save();
        }
    }    # while sale
    my $t3 = Time::HiRes::gettimeofday(); # XXX
    print STDERR " >> Process/Runcontroller/Complex/_createSalePublisherMapping - scanned ". $allSales->size() . " sales in ". ($t3 - $t2) . " second(s)\n"; # XXX

    $self->_report( "_createSalePublisherMapping - creating log entries for unlicensed tracks", 3 );
    $self->_report( \%unlicensedTracks,                                                         4 );
    foreach my $trackID ( keys %unlicensedTracks ) {
        my $track = $self->_getTrack($trackID);
        if ($track) {
            my $master   = $self->_getMaster( $track->master_id );
            my $duration = $master->duration;

            next if ( $self->_trackIsMechanicalExempt($track) );

            # !!! FLIP THIS AROUND:
            # !!! We want to accumulate across stat rates.
            # So, {trackID}{productID}{statRateID}, instead of {trackID}{statRateID}{productID}
            foreach my $productID ( keys %{ $unlicensedTracks{$trackID} } ) {
                my $product = $self->_getProduct($productID);

                foreach my $productType ( keys %{ $unlicensedTracks{$trackID}{$productID} } ) {

                    my $accrual = 0;

                    # FB14251: For each statRateID, we want to calculate the accrual for each
                    # date range that was covered by the statRateID
                    #
                    my $upc = $unlicensedTracks{$trackID}{$productID}{$productType}{upc};

                    foreach my $statRateID ( keys %{ $unlicensedTracks{$trackID}{$productID}{$productType}{STATRATE} } ) {

                        # Calculate the actual rate.
                        # The rate will be the same across all date ranges that were associated to the statRateID
                        #
                        my ( $statRate, $minuteRate ) = $self->_getStatRate($statRateID);
                        my $rate;

                        # If the duration is less or equal to 5 minutes, or if this is a ringtone (no minute
                        # rate) just use the rate associated with the statRateID.  Otherwise use the
                        # minute rate.
                        #
                        if ( $duration <= 300 || !$minuteRate ) {
                            $rate = $statRate;
                        } else {
                            my $numMinutes = int( $duration / 60 ) + 1;
                            $rate = $numMinutes * $minuteRate;
                        }

                        foreach my $year ( keys %{ $unlicensedTracks{$trackID}{$productID}{$productType}{STATRATE}{$statRateID} } ) {
                            my $units = $unlicensedTracks{$trackID}{$productID}{$productType}{STATRATE}{$statRateID}{$year}{units};
                            $accrual = ( $units * $rate );

                            # FB14251 - save the units, date range and rate info along with the accrual
                            #
                            if ($units || $accrual){
                                $self->_createUnlicensedTrackLogEntry( $track, $product, $upc,
                                  $productType, 100, $accrual, $units, $year, $rate );
                            }
                        }
                    }

                }    # foreach productType

            }    # foreach productID
        }
    }    # foreach trackID


    $self->_initializeSalePublisherLicenseMap() if ( $self->{_RSD7859} );

}    # _createSalePublisherMapping


sub _getLicensesThatMatchSale {
    my ( $self, $sale, $trackLicenses ) = @_;

    $self->_report( "_getLicensesThatMatchSale:  incoming licenses:", 4 );
    $self->_report( $trackLicenses,                                   4 );

    my $matchingRegions = $self->_findRegionsForCountryCode( $sale->country_code );
    if ( !$matchingRegions || 0 == scalar @$matchingRegions ) {
        $self->_report( "No matching region found for country code '"
              . $sale->country_code
              . "', in sale "
              . $sale->sale_id
              . " - returning no licenses" );
        return [];
    }

    # Create a hash of matching region_ids, to speed up comparisons later.
    #
    my %validRegions;
    foreach my $regionID (@$matchingRegions) {
        $validRegions{$regionID} = 1;
    }
    $self->_report( "_getLicensesThatMatchSale:  valid regions:", 4 );
    $self->_report( \%validRegions,                               4 );

    my $productID = $sale->product_id;
    my $product   = $self->_getProduct($productID);

    if ( !$product ) {
        die RPS::Mechanical::Process::SaleException::NoProduct->new( $sale,
            ( $productID ? "Sale had invalid ProductID $productID" : 'Sale had no Product ID!' ) );
    }

    my $productTypeID = $product->product_type_id;
    my $digitalFlag   = $self->_productIsDigital($product);

    my $startDate = $sale->date_begin;
    my $endDate   = $sale->date_end;

    my $ringtoneFlag = 0;

    # JPK - Restore when we're ready for RINGBACK
    #    if ($sale->format_type eq 'R' || $sale->format_type eq '1')
    if ( $sale->format_type eq 'R' ) {
        $ringtoneFlag = 1;
    }

    # Ok,let's get organized here.
    # We have an array of all the track licenses, from everybody imaginable, that were on this track.
    # Just for our payor, though, which is nice.
    # So, we want to return the best license for each publisher
    #
    my %winningTrackLicenseHash;
    my %winningTrackLicenseRegionHash; # keep track of winning licenses per region

    foreach my $tl (@$trackLicenses) {
        $self->_report( " looking at track license id " . $self->_idFromTrackLicense($tl), 3 );

        # Public domain licenses don't have regions...
        #
        next unless ( $validRegions{ $tl->region_id } || RPS::DB::Item::TrackLicense::kPublicDomain == $tl->type );

        # Only _1_ track license for a given track and region can go on.
        # But the query may return more than 1, because we have the 'all product' and 'all digital product' types.
        # So I will filter that out here (rather than try and do that in a single query)

        my $licensePublisherID = $self->_publisherIDFromTrackLicense($tl);

        if (
               ( $tl->product_type_id == RPS::DB::Item::Product::kProductTypeRingtone && $ringtoneFlag == 1 )
            || ( !$tl->product_type_id && ( $ringtoneFlag == 0 ) )
            || ( 255 == $tl->product_type_id && ( $digitalFlag == 0 && $ringtoneFlag == 0 ) )    # All physical products
            || ( 254 == $tl->product_type_id && ( $digitalFlag == 1 && $ringtoneFlag == 0 ) )    # All digital products (except ringtones)
            || ( $tl->product_type_id == $productTypeID && $ringtoneFlag == 0 )
          )    # Prevent ringtone sales from hitting DT licenses
        {

            my $termStart = $tl->term_start;
            my $termEnd   = $tl->term_end;
            my $saleID    = $sale->sale_id;
            my $licenseID = $self->_idFromTrackLicense($tl);

            if ( $termStart && $termStart gt $endDate ) {
                $self->_report( "D: sale $saleID skipping license ". $licenseID . " type ". $tl->product_type_id .
                    " tStart($termStart) > sEnd($endDate)", 3 );
                next;
            }
            if ( $termEnd && $termEnd lt $endDate ) {
                $self->_report( "D: sale $saleID skipping license ". $licenseID . " type ". $tl->product_type_id .
                    " tEnd($termEnd) <= sEnd($endDate)", 3 );
                next;
            }

            # The following keeps track of winning license by publisher by region.
            my $_regionID = $tl->region_id;
            my $skipRegionLicense=0;

            if ( $winningTrackLicenseRegionHash{$licensePublisherID}{$_regionID} ) {
                my $licenseID = $self->_idFromTrackLicense($winningTrackLicenseRegionHash{$licensePublisherID}{$_regionID});

                # more specific beats less specific.
                #
                if ( !$tl->product_type_id ||
                    255 != $winningTrackLicenseRegionHash{$licensePublisherID}{$_regionID}->product_type_id ||
                    254 != $winningTrackLicenseRegionHash{$licensePublisherID}{$_regionID}->product_type_id ) {
                    $self->_report("_getLicensesThatMatchSale: skipping license ".  $self->_idFromTrackLicense($tl)
                        . " region $_regionID, winner is $licenseID" , 3 );
                    $skipRegionLicense = 1;
                } else {
                    $skipRegionLicense = 0;
                }
                if ( $tl->product_type_id &&
                     $tl->product_type_id == $winningTrackLicenseRegionHash{$licensePublisherID}{$_regionID}->product_type_id ) {

                    $self->_report("REGION OVERLAP WARNING: license ".  $self->_idFromTrackLicense($tl)
                        . ", may be dupe of $licenseID", 2 );
                }
            }
            $winningTrackLicenseRegionHash{$licensePublisherID}{$_regionID} = $tl if ( !$skipRegionLicense );

            # The following keeps track of winning license by publisher across regions
            #
            if ( $winningTrackLicenseHash{$licensePublisherID} ) {
                my $licenseID = $self->_idFromTrackLicense($winningTrackLicenseHash{$licensePublisherID});

                # more specific beats less specific.
                #
                if ( !$tl->product_type_id ||
                    255 != $winningTrackLicenseHash{$licensePublisherID}->product_type_id ||
                    254 != $winningTrackLicenseHash{$licensePublisherID}->product_type_id ) {
                    $self->_report("skipping license ". $self->_idFromTrackLicense($tl) . ", winner is $licenseID", 3);
                }

                next if ( !$tl->product_type_id );
                next if ( 255 != $winningTrackLicenseHash{$licensePublisherID}->product_type_id );
                next if ( 254 != $winningTrackLicenseHash{$licensePublisherID}->product_type_id );

                if ( $tl->product_type_id &&
                      $tl->product_type_id == $winningTrackLicenseHash{$licensePublisherID}->product_type_id ) {
                    $self->_report("OVERLAP WARNING: license ". $self->_idFromTrackLicense($tl)
                        . ", may be dupe of $licenseID", 2 );
                }
            }

            $self->_report( "becoming the current winner...", 4 );
            $winningTrackLicenseHash{$licensePublisherID} = $tl;
        }
    }

    my @matchingLicenses;
    foreach my $licensePublisherID ( keys %winningTrackLicenseHash ) {
        my $winningTrackLicense = $winningTrackLicenseHash{$licensePublisherID};
        $self->_report( " WINNING TRACK LICENSE ID FOR PUBLISHER $licensePublisherID : " . $self->_idFromTrackLicense($winningTrackLicense),
            4 );

        push @matchingLicenses, $winningTrackLicense;

    }

    if ( $self->{_RSD7859} ) {
        foreach my $licensePublisherID ( keys %winningTrackLicenseRegionHash ) {
            my $regionHash = $winningTrackLicenseRegionHash{$licensePublisherID};
            foreach my $regionID ( keys %$regionHash ) {
                my $winningTrackLicense = $winningTrackLicenseRegionHash{$licensePublisherID}{$regionID};
                push @{$self->{_publisherMatchingLicenses}{$licensePublisherID}{$sale->sale_id}}, $self->_idFromTrackLicense($winningTrackLicense);
            }
        }
    }

    $self->_report( "______ returning this list of licenses:", 4 );
    $self->_report( \@matchingLicenses,                        4 );

    return \@matchingLicenses;
}


1;
