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

package RPS::LabelRoyalty::Fast::Script::AssembleStatements;

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

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

use DB_File;

use Common::Util;
use Common::Log;
use Common::Parser;
use Common::WriteXML;

use RPS::DB::Item::LabelRoyaltyRun;
use RPS::LabelRoyalty::Fast::Mapped::Data;
use RPS::LabelRoyalty::Fast::Final::DB::LabelRoyaltyStatement;
use RPS::LabelRoyalty::Fast::Final::DB::LabelRoyaltyLabelItem;
use RPS::LabelRoyalty::Fast::Final::DB::LabelRoyaltyTransactionItem;
use RPS::LabelRoyalty::Fast::Final::DB::SaleRunMap;
use RPS::LabelRoyalty::Fast::Final::File::LabelRoyaltySaleReportItem;

use base 'Common::Script';

sub _options {
    {
        client_id => {
            short       => 'c',
            required    => 1,
            description => 'Limit to this client id',
            parameter   => 'i'
        },
        static_data_path => {
            short       => 's',
            required    => 1,
            description => 'path to directory containing static data',
            parameter   => 's'
        },
        output_path => {
            short       => 'o',
            required    => 1,
            description => 'path to directory to write output files',
            parameter   => 's'
        },
        run_id => {
            short       => 'r',
            required    => 1,
            description => 'The label_royalty_run_id we are creating statements for.',
            parameter   => 'i',
        },
        index_range => {
            short       => 'i',
            required    => 0,
            description => 'First,Last data indexes to process.  Ex: -s0,10000',
            parameter   => 's',
        },
    };
}

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

    my $dataPath        = $self->param('static_data_path');
    my $outputDirectory = $self->param('output_path');
    my $runID           = $self->param('run_id');

    # Read in the run record, so we can get the correct payor_id.
    #
    my $runData = RPS::DB::Item::LabelRoyaltyRun->Lookup( label_royalty_run_id => $runID );
    my $payorID = $runData->payor_id();

    my %payeeToSalesMapCount = RPS::LabelRoyalty::Fast::Mapped::Data->GetPayeeToSalesMapCount($outputDirectory);
    my $inData = RPS::LabelRoyalty::Fast::Mapped::Data->GetMappedData($outputDirectory);

    RPS::LabelRoyalty::Fast::Final::DB::LabelRoyaltyStatement->Init( $outputDirectory, $dataPath );
    RPS::LabelRoyalty::Fast::Final::DB::LabelRoyaltyLabelItem->Init( $outputDirectory, $dataPath );
    RPS::LabelRoyalty::Fast::Final::DB::LabelRoyaltyTransactionItem->Init( $outputDirectory, $dataPath );
    RPS::LabelRoyalty::Fast::Final::DB::SaleRunMap->Init( $outputDirectory, $dataPath, $runID );

    # !!! This is new.  Not going to create LabelRoyaltyStatementSale records, since those are only
    # !!! used to later create the text report.  This class will instead just encapsulate lines in that
    # !!! report file directly.
    #
    RPS::LabelRoyalty::Fast::Final::File::LabelRoyaltySaleReportItem->Init( $outputDirectory, $dataPath, $runID );

    my $statement;
    my $label;
    my $lineItem;

    while ( my $data = $inData->nextLine() ) {
        Log->info( "\n\nDATA:", $data );

        # Note that we always destroy the objects opposite of how we build them.
        # This is because objects do stuff when they are destroyed:
        # - They write their accumulated values to their output files.
        # - They call methods in their container objects to update summary data.
        #
        # So we need to make sure the summary data is updated before the containers
        # are themselves destroyed.
        #
        if ( !$statement || !$statement->process($data) ) {
            $lineItem = undef;
            $label    = undef;

            $statement = RPS::LabelRoyalty::Fast::Final::DB::LabelRoyaltyStatement->new( $data, $runID, $payorID, \%payeeToSalesMapCount ) || next;
            $label = RPS::LabelRoyalty::Fast::Final::DB::LabelRoyaltyLabelItem->new( $data, $statement );

            # It seems best to be aware here that we produce one output file per statement and
            # we want to do this whether we see sales or not, so need a static method that sees to that.
            RPS::LabelRoyalty::Fast::Final::File::LabelRoyaltySaleReportItem->initReport($statement);

            # JPK - We don't really need to force the 'line item' class to keep track of it's last statement id.
            # We know right here that the statement has changed (or is the first one).
            # So let's just pass the statement as an optional parameter right here.
            # !!! We don't know whether or not the first line of data is a 'sale' line, so this current optional
            # !!! statement parameter is not going to work.
            # !!! We will need to pass it every time, and examine it inside the SaleReportItem class to see if it is different.
            #
            $lineItem = $self->_newLineItem( $data, $label, $statement );

            #            $lineItem = RPS::LabelRoyalty::Fast::Final::File::LabelRoyaltySaleReportItem->new($data, $label, $statement)
        } elsif ( !$label->process($data) ) {
            $lineItem = undef;

            $label = RPS::LabelRoyalty::Fast::Final::DB::LabelRoyaltyLabelItem->new( $data, $statement );

            # Notice that we are not passing the $statement reference, since the statement id will not have changed.
            #
            $lineItem = $self->_newLineItem( $data, $label, $statement );

            #            $lineItem = RPS::LabelRoyalty::Fast::Final::File::LabelRoyaltySaleReportItem->new($data, $label)
        } elsif ( !defined $lineItem || !$lineItem->process($data) ) {
            $lineItem = $self->_newLineItem( $data, $label, $statement );

            #            $lineItem = RPS::LabelRoyalty::Fast::Final::File::LabelRoyaltySaleReportItem->new($data, $label)
        }

        $self->_logSale( $data, $label, $statement );
    }

    # Explicitly release these references, so they write out immediately.
    #
    $lineItem  = undef;
    $label     = undef;
    $statement = undef;

    # The sale report class finishes reports as needed when it starts a new one. The last one doesn't
    # get that chance, so we'll help it along. There's a better solution here tied to objectifying
    # the output files themselves and hooking into that, but more upheaval than warranted right now...
    RPS::LabelRoyalty::Fast::Final::File::LabelRoyaltySaleReportItem->finalizeReport();
}

sub _newLineItem {
    my ( $self, $data, $label, $statement ) = @_;

    my $type = $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kTypeCode];

    return RPS::LabelRoyalty::Fast::Final::File::LabelRoyaltySaleReportItem->new( $data, $label, $statement )
      if ( RPS::LabelRoyalty::Fast::Mapped::Data::kDataSale == $type );

    # !!! Do I need to also write transactions into the sale report file?
    # !!! Doesn't appear so, but we do need to update the Statement item with subtotals.
    # !!! Makes me wonder whether we should just pass that through the Label object, since we
    # !!! currently have this set up to not always be passed a Statement reference.
    # !!! JPK - The Label does have a statement() interface, so that ought to work.
    #
    return RPS::LabelRoyalty::Fast::Final::DB::LabelRoyaltyTransactionItem->new( $data, $label )
      if ( RPS::LabelRoyalty::Fast::Mapped::Data::kDataTransaction == $type );

    # Return undef if we don't recognize the type.  This sort of 'no-op' is not actually an error, and
    # we're going to take advantage of this to allow us to create Statements for payees with no activity.
    #
    # !!! However, I will still want to feed the statement the min_payment, balance, and on_hold info.
    # !!! So if I stuff that data into a normal line?  Or should I just update the Statement object right now?
    # !!! I can't guarantee that we will always start every statement with Payee balance data.
    # !!! I think the best approach, actually, is to go ahead and put the min_payment, balance, and on_hold stuff in
    # !!! their own slots at the end of the 'regular' data, and let the Statement find it there.
    #
    #
    return undef;
}

sub _logSale {
    my ( $self, $data, $label, $statement ) = @_;

    my $type = $data->[RPS::LabelRoyalty::Fast::Mapped::Data::kTypeCode];

    RPS::LabelRoyalty::Fast::Final::DB::SaleRunMap->new( $data, $label, $statement )
      if ( RPS::LabelRoyalty::Fast::Mapped::Data::kDataSale == $type );
}

1;
