#---------------------------------------------------------------
# ____                   _ _         ____  _                    
#|  _ \ ___  _   _  __ _| | |_ _   _/ ___|| |__   __ _ _ __ ___ 
#| |_) / _ \| | | |/ _` | | __| | | \___ \| '_ \ / _` | '__/ _ \
#|  _ < (_) | |_| | (_| | | |_| |_| |___) | | | | (_| | | |  __/
#|_| \_\___/ \__, |\__,_|_|\__|\__, |____/|_| |_|\__,_|_|  \___|
#            |___/             |___/                            
#
# 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 $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);
            $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;
