#---------------------------------------------------------------
# ____                   _ _         ____  _
#|  _ \ ___  _   _  __ _| | |_ _   _/ ___|| |__   __ _ _ __ ___
#| |_) / _ \| | | |/ _` | | __| | | \___ \| '_ \ / _` | '__/ _ \
#|  _ < (_) | |_| | (_| | | |_| |_| |___) | | | | (_| | | |  __/
#|_| \_\___/ \__, |\__,_|_|\__|\__, |____/|_| |_|\__,_|_|  \___|
#            |___/             |___/
#
# Copyright (C) 2009 RoyaltyShare, Inc.   All Rights Reserved
# $Id$
#---------------------------------------------------------------
package BookPub::Sale::Report::FileSummary;
use strict;
use warnings;

use File::Path;

use lib '/app/tools/common/lib';
use lib '/app/tools/bookpub/lib';
use BookPub::DB::Item::File;
use BookPub::DB::Item::Service;
use BookPub::Config;
use BookPub::DB::Item::InputConversionRate;
use Common::Util;
use Common::Client;
use Common::Assert;

use base 'BookPub::Sale::Report';

# Notes:
# - seems to be more of a files based report.

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

    return 'BookPub::Sale::Report::FileSummary::Row';
}

sub _seperator {
    my ($self) = @_;
    return "\t";
}

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

    if ( !$self->{_fileName} ) {
        my $client = Common::Client::Current();

        $self->{_fileName} = $client->ClientNameClean() . '_File_Summary.txt';
    }
    return $self->{_fileName};
}

sub excelFileName {
    my ($self) = @_;
    return $self->{_periodID} . '_Summary.xls';
}

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

    if ( !$self->{_excelFilePath} ) {
        my $baseDir = $self->_baseDir();
        $self->{_excelFilePath} = $baseDir . '/' . $self->excelFileName();
    }
    return $self->{_excelFilePath};
}

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

    # Make sure we have a directory to write the final file into.
    #
    my $baseDir = $self->_baseDir();
    if ( !-d $baseDir ) {
        File::Path::mkpath($baseDir) || die "ERROR - make_path failed for $baseDir: $!";
    }

    # Open a file handle to the destination file.
    # Note that this WILL overwrite the file if it's currently there...
    #
    my $dest_file_path = $self->filePath();

    open( WRITE, ">" . $dest_file_path );
    binmode( WRITE, ':utf8' );

    # If this report is the current (open) period, we want to look at both open and closed
    # files.  Otherwise, just the closed files.
    my @fileStatus = ( BookPub::DB::Item::File::STATUS_CLOSED(), BookPub::DB::Item::File::STATUS_OPEN() );
    my $fileList =
      BookPub::DB::Item::File->GetByPeriodID( $self->periodID(), file_status => \@fileStatus, sort_by => 'service_name', no_parent => 1 );

    my $rowClass = $self->getRowClass();

    # Write out the header line.
    #
    my $fields = $rowClass->Fields();
    my $header = join( $self->_seperator, @$fields );
    print WRITE "$header\n";

    while ( my $file = $fileList->next() ) {

        # Instantiate the correct 'row' class.
        #
        my $row = $rowClass->new( file => $file );

        my @values = ();
        foreach my $fieldName (@$fields) {
            my $value = $row->{$fieldName};
            $value = '' unless defined $value;
            $value =~ s/\s/ /g;
            push @values, $value;
        }

        # Actually output the row.
        # Note that we determine which character to use as a delimeter via a private method.
        #
        print WRITE join( $self->_seperator(), @values ) . "\n";
    }

    close WRITE;

    return 1;

}

sub createExcel {
}

###
1;    #
###

package BookPub::Sale::Report::FileSummary::Row;
use strict;
use warnings;

use lib '/app/tools/common/lib';
use lib '/app/tools/bookpub/lib';
use BookPub::DB::Item::Service;
use BookPub::DB::Item::File;
use BookPub::DB::Item::Period;
use BookPub::Config;
use BookPub::Catalog::Imprint;
use BookPub::Matcher::Product;
use Common::Util;
use Common::Assert;
use Common::RSApp;
use Common::RSMath;
use Common::Client;

# Going to define these strings as constants, and use the constant internally.
# Since these are used as hash keys, and some are rather long, this will help
# prevent silly bugs related to misspellings...
#
use constant kService           => 'service';
use constant kFile              => 'file';
use constant kNotes             => 'notes';
use constant kReceived          => 'received';
use constant kUnits             => 'units';
use constant kRevenue           => 'revenue';
use constant kForeignRevenue    => 'foreign revenue';
use constant kForeignCurrency   => 'foreign currency';
use constant kRecords           => 'records';
use constant kExceptions        => 'exceptions';
use constant kCatalogExceptions => 'catalog exceptions';
use constant kPriceExceptions   => 'price exceptions';
use constant kStatus            => 'status';

sub new {
    my ( $class, %args ) = @_;

    my $self = bless {}, $class;
    return $self->_init(%args);
}

# This is a static class method! Invoke like so:
# BookPub::Sale::Report::Royalty::Row->Fields()
#
sub Fields {
    my ($class) = @_;

    my $appRamCache = Common::RSApp::GetRAMCache();

    if ( !$appRamCache->{$class}{Fields} ) {
        my @fields;

        # By using a second private method, we'll be able
        # to use inheritance - This provides a method that
        # subclasses can override or extend.
        #
        $class->_addFields( \@fields );

        $appRamCache->{$class}{Fields} = \@fields;
    }

    return $appRamCache->{$class}{Fields};
}

sub ServiceName {
    my ($serviceID) = @_;
    assert($serviceID);

    my $appRamCache = Common::RSApp::GetRAMCache();

    if ( !$appRamCache->{ServiceName} ) {

        # Fetch all the service names.
        #
        my $allServices = BookPub::DB::Item::Service->GetAll();
        while ( my $serviceItem = $allServices->next() ) {

            # I'll just stash the DB::Item::Service object.
            #
            $appRamCache->{ServiceName}{ $serviceItem->service_id } = $serviceItem->service_name;
        }
    }

    return $appRamCache->{ServiceName}{$serviceID};
}

sub _addFields {
    my ( $self, $fieldArray ) = @_;

    # What we're doing here is determining:
    # - The field order,
    # - The column names (i.e. the header labels)
    # - The accessor method name to provide that data.
    #
    push @$fieldArray, kService;
    push @$fieldArray, kFile;
    push @$fieldArray, kNotes;
    push @$fieldArray, kReceived;
    push @$fieldArray, kUnits;
    push @$fieldArray, kRevenue;
    push @$fieldArray, kForeignRevenue;
    push @$fieldArray, kForeignCurrency;
    push @$fieldArray, kRecords;

    # We only want to show price exceptions for clients who do price validation.
    #
    my $client = Common::Client::Current();
    if ( $client->isClientType(Common::Client::kSalePriceValidation) ) {
        push @$fieldArray, kCatalogExceptions;
        push @$fieldArray, kPriceExceptions;
    } else {
        push @$fieldArray, kExceptions;
    }

    push @$fieldArray, kStatus;
}

sub _init {
    my ( $self, %args ) = @_;
    my $file = $args{file};
    assert($file);

    my $periodID   = $file->period_id;
    my $childCount = BookPub::DB::Item::File->ChildCount( $file->file_id );

    $self->{ kService() } = ServiceName( $file->service_id );
    $self->{ kFile() }    = $file->orig_file_name;
    if ( $file->generation || $childCount ) {
        my $displayGeneration = $file->generation + 1;
        $self->{ kFile() } .= " (Sp" . $displayGeneration . ")";
    }
    $self->{ kNotes() }    = $file->notes;
    $self->{ kReceived() } = Common::Client::Current()->Locale()->formatDate( $file->date_created );
    $self->{ kUnits() }    = $file->units;

    if ( $file->currency_code() && $file->currency_code() ne Common::Client::Current()->Locale()->currencyFormat()->currencyCode() ) {

        my $convertedRevenue = 0;
        my $inputRates       = BookPub::DB::Item::InputConversionRate->GetAllByFileID( $file->file_id );
        if ( $inputRates->size ) {
            while ( my $item = $inputRates->next() ) {
                $convertedRevenue += $item->revenue * $item->conversion_rate;
            }
        }
        $self->{ kRevenue() }         = $convertedRevenue;
        $self->{ kForeignCurrency() } = $file->currency_code();
        $self->{ kForeignRevenue() }  = $file->revenue;
    } else {
        $self->{ kRevenue() }         = $file->revenue;
        $self->{ kForeignRevenue() }  = '';
        $self->{ kForeignCurrency() } = '';
    }

    $self->{ kRecords() } = Common::Client::Current()->Locale()->formatNumber( $file->records );

    # Let's set this here, and then we can add in the price exceptions if needed.
    #
    my $exceptionCount = $file->remaining_exceptions;

    my $client = Common::Client::Current();
    if ( $client->isClientType(Common::Client::kSalePriceValidation) ) {
        $self->{ kCatalogExceptions() } = Common::Client::Current()->Locale()->formatNumber( $file->remaining_exceptions );
        $self->{ kPriceExceptions() }   = Common::Client::Current()->Locale()->formatNumber( $file->price_exceptions );
        $exceptionCount += $file->price_exceptions;
    } else {
        $self->{ kExceptions() } = Common::Client::Current()->Locale()->formatNumber( $file->remaining_exceptions );
    }

    # 'status' is derived.

    # 'zero out' data fields to start.
    #
    my $status;
    if ( $file->file_status == 5 ) {
        $status = 'Pending';
    } elsif ( $file->records > $exceptionCount || $exceptionCount == 0 ) {
        $status = 'Finish';
    } else {
        $status = 'Open';
    }
    $self->{ kStatus() } = $status;

    return $self;
}

1;
