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

package RPS::LabelRoyalty::Fast::Final::File::LabelRoyaltySaleReportItem;

use strict;
use Data::Dumper;
use File::Path;
use File::Copy;
use POSIX qw(ceil);

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

use Data::Dumper;
use DB_File;

use Common::Log;
use Common::Assert;
use Common::Client;
use Common::Locale;

use RPS::Statement::Label::Report;

use RPS::LabelRoyalty::Fast::Static::Products;
use RPS::LabelRoyalty::Fast::Static::Services;
use RPS::LabelRoyalty::Fast::Mapped::Data;
use RPS::LabelRoyalty::Fast::Final::DB::LabelRoyaltyLabelItem;
use RPS::LabelRoyalty::Fast::Final::DB::LabelRoyaltyStatement;

use base 'RPS::LabelRoyalty::Fast::Final::File';


# JPK - Going to use the fields from the final report file, rather than the LabelRoyaltyStatementSale table.

use constant kLabelName                     => 0;
use constant kServiceID                     => 1;
use constant kServiceName                   => 2;
use constant kDistributor                   => 3;
use constant kTerritory                     => 4;  # This is COUNTRY CODE, not REGION.  Region is NOT USED for label royalties...
use constant kPeriodBegin                   => 5;
use constant kPeriodEnd                     => 6;
use constant kProductType                   => 7;  # These two appear to be straight out of the sale table schema, so not the product type from product table.
use constant kProductFormat                 => 8;
use constant kCatalogID                     => 9;
use constant kUPC                           => 10;
use constant kAlbumID                       => 11;
use constant kAlbumName                     => 12;
use constant kAlbumArtist                   => 13;
use constant kReleaseDate                   => 14;
use constant kUPCAlt                        => 15;
use constant kAlbumCustom1                  => 16;
use constant kAlbumCustom2                  => 17;
use constant kAlbumCustom3                  => 18;
use constant kISRC                          => 19;
use constant kTrackID                       => 20;
use constant kDiscNo                        => 21;
use constant kTrackNo                       => 22;
use constant kTrackName                     => 23;
use constant kTrackArtist                   => 24;
use constant kTrackCustom1                  => 25;
use constant kTrackCustom2                  => 26;
use constant kTrackCustom3                  => 27;
use constant kUnits                         => 28;
use constant kUnitPrice                     => 29;
use constant kExtPrice                      => 30;
use constant kCurrencyCode                  => 31;
use constant kCurrencyConv                  => 32;
use constant kCurrencyUnitPrice             => 33;
use constant kCurrencyExtPrice              => 34;
use constant kFree                          => 35;
use constant kDistFee                       => 36;
use constant kCurrencyNetPrice              => 37;
use constant kMediaType                     => 38;

use constant kProductID                     => 39;
use constant kLabelReference                => 40;



# JPK - I'll use the same basic idea, but these will be the headers.
# Note that some of these will need to be modified to include the native currency code on output.
# I'll probably just use a regex, and embed a token (like 'CUR') to replace on.
#
my @gFields = 
(
'label-name',
'service-id',
'service-name',
'distributor',
'territory',
'period-begin',
'period-end',
'product-type',
'product-format',
'catalog-id',
'upc',
'album-id',
'album-name',
'album-artist',
'release-date',
'upc-alt',
'album-custom-1',
'album-custom-2',
'album-custom-3',
'isrc',
'track-id',
'disc-no',
'track-no',
'track-name',
'track-artist',
'track-custom-1',
'track-custom-2',
'track-custom-3',
'units',
'unit-price',
'ext-price',
'currency-code',
'currency-conv',
'CUR-unit-price',
'CUR-ext-price',
'free',
'dist-fee',
'CUR-net-price',
'media_type',
);


sub Fields { return \@gFields; }




# !!! We don't need nor HAVE an id, since we're not writing this stuff to a table anymore.
#
sub _MaxIDSql { '' }



my $gProducts;
my $gServices;
my $gRunID;
my $gLastPayeeID;
my $gOutputDirectory;
my $gFD;
my $gLines;

use constant kReportSubDirectory => 'sale_reports';

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

    $gLastPayeeID = 0;

    $gProducts = RPS::LabelRoyalty::Fast::Static::Products->GetProducts($dataPath);
    $gServices = RPS::LabelRoyalty::Fast::Static::Services->GetServices($dataPath);

    $gRunID = $runID;

    # We're going to extend the output directory and add another level.
    # This will make it easier to find all the files later.

    $gOutputDirectory = $outputDirectory . '/' . kReportSubDirectory;

    if (! -d $gOutputDirectory)
    {
        mkpath($gOutputDirectory) or die "ERROR: Unable to create path $gOutputDirectory: $!\n";
    }

    $class->SUPER::Init($gOutputDirectory);
}


# Going to overload this to behave a bit differently.
# We will be managing more than one file.
#

sub InitFD
{
    my ($class, $outputDirectory) = @_;

    # This logic kicks in when this method is called by the inherited Init method.
    # Basically, we don't want to ACTUALLY open the file yet.
    #
    return unless $gLastPayeeID;

    # JPK - We shouldn't have to explicitly call 'close' on the previous file descriptor.
    # In theory it will be closed magically when it goes out of scope.
    #
    $class->SUPER::InitFD($outputDirectory);

    
    # JPK - We also need to add in the header when we first open the file.
    # But I may just override the 'WriteFD' method since that returns the file descriptor.
}

sub WriteFD
{
    my ($class, $dataPath) = @_;

    my $fd = $class->SUPER::WriteFD($dataPath);
    if ($fd)
    {
        my $fields = $class->Fields();

        my $header = join("\t", @$fields);

        # Replace 'CUR' with native currency code.
        #
        my $locale = Common::Client::Current()->Locale();
        my $cc = lc($locale->currencyFormat()->currencyCode());
        $header =~ s/CUR/$cc/g;

        print $fd "$header\n";

        $gFD = $fd;
    }

    return $fd;
}


sub FileName 
{ 
    # !!! If we have this structured correctly, this should not get called unless we've seen a statement id.
    #
    assert($gLastPayeeID);
# We can't use this interface - It tries to look up the 'statement' record (which has not been created yet).
# So, just use the label_id aka payee_id (which is all it does).
#    return RPS::Statement::Label::Report::ReportFileNameFromID($gLastStatementID);

    return "$gLastPayeeID.txt";
}

sub initReport
{
    my ($class, $statement) = @_;

    assert($statement);
    assert($statement->[RPS::LabelRoyalty::Fast::Final::DB::LabelRoyaltyStatement::kPayeeID]);

    $class->finalizeReport();
    $gLastPayeeID = $statement->[RPS::LabelRoyalty::Fast::Final::DB::LabelRoyaltyStatement::kPayeeID];
    $gLines = 0;
    $class->InitFD($gOutputDirectory)
}

sub finalizeReport
{
    my ($class) = @_;

    if ($gLastPayeeID)
    {
        if (!$gLines)
        {
            print $gFD "There are no sales to report\n";
        }
    }
}



# We need to tie this to the Statement class.
# There should actually be a seperate file for each statement.
# I think the easiest way will be to keep track of the last statement_id, and have the 'new'
# method take a reference to the Statement object.
# 
sub new
{
    my ($class, $data, $label, $statement) = @_;

    my $item = $class->BlankItem();

#    $class->_IncrementID();

    # We can initialize the bulk of the state immediately.
    #
    my $productID = $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kProductID];
    my @product = split("\t", $gProducts->{$productID});

    my $startDate = substr($data->[RPS::LabelRoyalty::Fast::Mapped::Data::kStartDate], 0, 7);
    my $endDate   = substr($data->[RPS::LabelRoyalty::Fast::Mapped::Data::kEndDate], 0, 7);

    $item->[kLabelName] = $product[RPS::LabelRoyalty::Fast::Static::Products::kLabelName];
    $item->[kServiceID] = $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kServiceID];

    # !!! This is a bit of a hack in order to avoid adding another column
    # !!! We'll keep the distributor ID in the kDistributor column, and replace it with the
    # !!! distributor's name when we output.
    #
    $item->[kDistributor] = $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kDistributorID];
#    $item->[kServiceName] = $gServices->{ $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kServiceID] };
#    $item->[kDistributor] = $gServices->{ $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kDistributorID] };

    $item->[kTerritory] = $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kCountryCode];
    $item->[kPeriodBegin] = $startDate;
    $item->[kPeriodEnd] = $endDate;
    $item->[kProductType] = $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kProductType];
    $item->[kProductFormat] = $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kFormatType];
    $item->[kCatalogID] = $product[RPS::LabelRoyalty::Fast::Static::Products::kCatalogID];
    $item->[kUPC] = $product[RPS::LabelRoyalty::Fast::Static::Products::kUPC];
    $item->[kAlbumID] = $product[RPS::LabelRoyalty::Fast::Static::Products::kAlbumID];
    $item->[kAlbumName] = $product[RPS::LabelRoyalty::Fast::Static::Products::kAlbumName];
    $item->[kAlbumArtist] = $product[RPS::LabelRoyalty::Fast::Static::Products::kAlbumArtist];
    $item->[kReleaseDate] = $product[RPS::LabelRoyalty::Fast::Static::Products::kReleaseDate];
    $item->[kUPCAlt] = $product[RPS::LabelRoyalty::Fast::Static::Products::kUPCAlt];
    $item->[kAlbumCustom1] = $product[RPS::LabelRoyalty::Fast::Static::Products::kAlbumCustom1];
    $item->[kAlbumCustom2] = $product[RPS::LabelRoyalty::Fast::Static::Products::kAlbumCustom2];
    $item->[kAlbumCustom3] = $product[RPS::LabelRoyalty::Fast::Static::Products::kAlbumCustom3];
    $item->[kISRC] = $product[RPS::LabelRoyalty::Fast::Static::Products::kISRC];
    $item->[kTrackID] = $product[RPS::LabelRoyalty::Fast::Static::Products::kTrackID];
    $item->[kDiscNo] = $product[RPS::LabelRoyalty::Fast::Static::Products::kDiscNo];
    $item->[kTrackNo] = $product[RPS::LabelRoyalty::Fast::Static::Products::kTrackNo];
    $item->[kTrackName] = $product[RPS::LabelRoyalty::Fast::Static::Products::kTrackName];
    $item->[kTrackArtist] = $product[RPS::LabelRoyalty::Fast::Static::Products::kTrackArtist];
    $item->[kTrackCustom1] = $product[RPS::LabelRoyalty::Fast::Static::Products::kTrackCustom1];
    $item->[kTrackCustom2] = $product[RPS::LabelRoyalty::Fast::Static::Products::kTrackCustom2];
    $item->[kTrackCustom3] = $product[RPS::LabelRoyalty::Fast::Static::Products::kTrackCustom3];
    $item->[kUnits] = $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kUnits]; # <- this field will accumulate
    $item->[kUnitPrice] = $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kPrice];
    $item->[kCurrencyCode] = $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kCurrencyCode];
    $item->[kCurrencyConv] = $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kConversionRate]; 
    $item->[kFree] = $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kFree];
    $item->[kDistFee] = $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kDistributionFee];
    $item->[kMediaType] = $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kMediaType];
    $item->[kExtPrice] = 0; # !!! This is calculated ?
    $item->[kCurrencyNetPrice] = 0; # !!! This is calculated
    $item->[kCurrencyExtPrice] = 0; # !!! This is calculated

    $item->[kCurrencyUnitPrice] = Common::RSMath::round($item->[kUnitPrice] * $item->[kCurrencyConv], 8);

    $item->[kProductID] = $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kProductID];


    # Any extra crap we need 'secretly', we'll just push onto the end of the array.
    #
    push @$item, $label;

    return bless($item, $class);
}


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


    # !!! We don't seem to actually care about label ID or label contract ID at this level, which is weird...
    # !!! Presumably we'll check those in the LabelRoyaltyLabel object?

#    if ($self->[kLabelID]           != $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kLabelID]
#     || $self->[kLabelContractID]   != $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kLabelContractID]

    my $startDate = substr($data->[RPS::LabelRoyalty::Fast::Mapped::Data::kStartDate], 0, 7);
    my $endDate   = substr($data->[RPS::LabelRoyalty::Fast::Mapped::Data::kEndDate], 0, 7);

    if ($self->[kAlbumID]           != $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kAlbumID]
     || $self->[kTrackID]           != $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kTrackID]
     || $self->[kServiceID]         != $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kServiceID]
     || $self->[kDistributor]       != $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kDistributorID]
     || $self->[kProductType]       ne $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kProductType]
     || $self->[kProductFormat]     ne $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kFormatType]
     || $self->[kMediaType]         ne $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kMediaType]
     || $self->[kTerritory]         ne $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kCountryCode]
     || $self->[kCurrencyConv]      != $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kConversionRate]
     || $self->[kDistFee]           != $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kDistributionFee]
     || $self->[kProductID]         != $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kProductID]
     || $self->[kFree]              != $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kFree]
     || $self->[kUnitPrice]         != $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kPrice]
     || $self->[kPeriodBegin]       ne $startDate
     || $self->[kPeriodEnd]         ne $endDate
     || $self->[kCurrencyCode]      ne $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kCurrencyCode]
    )
    {
        Log->info("RPS::LabelRoyalty::Fast::Final::File::LabelRoyaltySaleReportItem::process - returning UNDEF");
        return undef;
    }


    $self->[kUnits] += $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kUnits]; 

    Log->info("RPS::LabelRoyalty::Fast::Final::File::LabelRoyaltySaleReportItem::process - returning UNDEF");
    return 1;
}




# Override _output to do some final calculations.
#
sub _output
{
    my ($self, $ITEMS) = @_;

    my $label = pop @$self;

    # Don't need the product_id in the output file.
    #
    my $productID = pop @$self;

    $self->[kServiceName] = $gServices->{ $self->[kServiceID] };
    $self->[kDistributor] = ($self->[kDistributor] == $self->[kServiceID]) ? '' : $gServices->{ $self->[kDistributor] };

    $self->[kTrackID] = '' unless ($self->[kTrackID]);
    $self->[kDiscNo]  = '' unless ($self->[kDiscNo]);
    $self->[kTrackNo] = '' unless ($self->[kTrackNo]);
    $self->[kFree]    = $self->[kFree] ? 'Y' : 'N';

    # The 'ext_price' is essentially the gross sale amount.
    #
    my $price = $self->[kUnitPrice];
    my $units = $self->[kUnits];
    my $conversionRate = $self->[kCurrencyConv];
    my $grossSales = Common::RSMath::round($units * $price, 8);
    my $feePercent = $self->[kDistFee] / 100;


    my $fee = Common::RSMath::round($grossSales * $feePercent, 8);
    my $netSales = $grossSales - $fee;
    my $baseNetSales = Common::RSMath::round($netSales * $conversionRate, 8);
    my $baseFee = Common::RSMath::round($fee * $conversionRate, 8);
    my $basePrice = Common::RSMath::round($price * $conversionRate, 8);
    my $baseGrossSales = Common::RSMath::round($grossSales * $conversionRate, 8);


    $self->[kDistFee] = $feePercent;
    $self->[kExtPrice] = $grossSales;
    $self->[kCurrencyExtPrice] = $baseGrossSales;
    $self->[kCurrencyNetPrice] = $baseNetSales;


    $label->[RPS::LabelRoyalty::Fast::Final::DB::LabelRoyaltyLabelItem::kGrossSales] += $baseGrossSales;
    $label->[RPS::LabelRoyalty::Fast::Final::DB::LabelRoyaltyLabelItem::kNetSales] += $baseNetSales;
    $label->[RPS::LabelRoyalty::Fast::Final::DB::LabelRoyaltyLabelItem::kFee] += $baseFee;


    $self->SUPER::_output($ITEMS);

    $gLines++;
}


sub Commit
{
    my ($class, $sourceBasePath, $runID) = @_;

    # JPK - Where do we get the final location of the file from?
    # Well, we might as well use the same interface the old code dose (the config file).
    #
    my $outFilePath = RPS::Statement::Label::Report::ReportPathFromRunID($runID);
    if (! -d $outFilePath)
    {
        mkpath($outFilePath) or die "ERROR: Unable to create path $outFilePath: $!\n";
    }

# !!! Actually, we're going to copy a whole lotta files.
#    my $fileName = RPS::Statement::Label::Report::ReportFileNameFromID($statementID);
#    my $filePath = $outFilePath . $fileName;

    my $sourceFullPath = $sourceBasePath . '/' . kReportSubDirectory;

    # Now, in theory, we can copy the files.
    # JPK - Not going to make this 'portable' - just going to let the shell do the work.
    #
    my $cmd = "cp $sourceFullPath/*.txt $outFilePath";
    my $status = system($cmd);
    die "ERROR EXECUTING '$cmd': ($?) $!" unless 0 == $status;
}



1;

