package Support::Implementation::USPublisherPayeeTransaction;
# 5/4/10a- Added logic to set currency code for client
# 12/9/10 - Changed to new template per FB12915
# 12/22/10 - Cleaned up amount processing
# 1/13/11 - Fixed amount validation.  Added code to handle situation
#   where publisher_account doesn't have a finance account setup.
# 2/3/11 - Adjusted code to generate exception when duplicate
#   publisher found.  Made transactionDate optional.  Added check
#   for blank publisher.
# 5/19/11 - Initial release of refactored codea per FBFB14013.
# 5/22/11 - Updated _findPublisher logic per FB14013.
use strict;
use warnings;

#*AUTOLOAD = \&BasePublisherPayeeTransaction::AUTOLOAD;

use lib '/app/tools/common/lib';

use Common::DB::ItemCollection;

use lib '/app/tools/rps/lib';

use IO::File;
use Data::Dumper;
use Date::Calc qw(Add_Delta_Days Days_in_Month);

use Spreadsheet::ParseExcel;

use Common::Assert;
use Common::UTF8;
use Common::RSApp;
use Common::Consts;
use Common::CurrencyFormat;
use Common::Util qw( clean trimspaces);

#use RPS::DB::Item::Publisher;
#use RPS::DB::Item::PublisherAccount;
#use RPS::DB::Item::FinanceAccount;
#use RPS::DB::Item::PendingTransaction;

use Support::Implementation::ExcelReader;
use Support::Implementation::TabDelimitedReader;

use Support::Implementation::ImplementationUtil qw( report appendString checkMissingColumn printNull );

use RPS::DB::Item::Publisher;
use RPS::DB::Item::PublisherAccount;
use RPS::DB::Item::PublisherIndirectBalanceAccount;
#use RPS::DB::Item::CAPublisher;
#use RPS::DB::Item::CAPublisherAccount;
use RPS::DB::Item::FinanceAccount;
use RPS::DB::Item::PendingTransaction;

#use base 'Support::Implementation::Template';
use base 'Support::Implementation::BasePublisherPayeeTransaction';

use constant kQuiet  => 0;
use constant kNormal => 1;
use constant kDebug  => 3;
my $gReportLevel = kNormal;

use constant kOriginUndefined     => 0;
use constant kOriginUnitedStates  => 1;
use constant kOriginCanada        => 2;
use constant kOriginUK            => 3;

binmode STDOUT, ":utf8";

#-----------------------------------------------------------------------
# templateHeader maps column names to their default column number.
# The actual column number-header name map is stored in columnMap.
# Note(s):
# 1) Column names are case sensitive
# 2) Spaces are ignored; you must manually remove spaces from the names
#    stored in templateHeader
#-----------------------------------------------------------------------
my %gTemplateHeader = (
   "*US Publisher Name"   => 0,   # A
   "Client Account #"     => 1,   # B
   "RS US Publisher ID"   => 2,   # C
   "US Admin Name"        => 3,   # D
   "US Agent Name"        => 4,   # E
   "*Payor Name"          => 5,   # F
   "Client Payor #"       => 6,   # G
   "RS Payor ID"          => 7,   # H
   "*Type of Transaction" => 8,   # I
   "*Amount"              => 9,   # J
   "*Transaction Date"    => 10,  # K
   "Check #"              => 11,  # L
   "Memo"                 => 12,  # M
);

use constant kDB => Common::DB::Item::kClientDB();

#--------------------------------------------------------------
# Maps column #'s to a unique key (headername).  The reverse of
# templateHeader, but with actual column #.
#--------------------------------------------------------------
my %gColumnMap = ();


#----------------------------------
# excount keeps track of exceptions
#----------------------------------
my %gExCount;

#--------------------------------------
# gCount keeps track of entities created
#--------------------------------------
my %gCount;

my $gDefaultPayorID;
my %gPayorMap = (); # maps names to ID

my $clientID;
my $execMode;

my $dbo;
my $dbh;
my $cdbo;

sub new {
   my ($class, %args) = @_;
   my $self = bless {}, $class;
   return $self->_init(%args);
}


sub _init {
   my( $self, %args ) = @_;

   report("PublisherTemplate::_init -- args = ". Dumper(\%args));

   $self->SUPER::_init(%args);

   $execMode = $self->exec_mode if ( $self->exec_mode );

   return $self;
}

sub parseHeader {
   my $self = shift;
}

sub _getPublisherIDColumnName {
    return 'RS US Publisher ID';
}

sub _getPublisherColumnName {
    return '*US Publisher Name';
}

sub _getAdminColumnName {
    return 'US Admin Name';
}

sub _getAgentColumnName {
    return 'US Agent Name';
}

sub _getPublisherByID {
    my($self,$id) = @_;
    assert($id);
    return RPS::DB::Item::Publisher->Lookup( publisher_id => $id );
}

sub _getPublisherID {
    my($self,$o) = @_;
    return $o->publisher_id;
}

sub _getPublisherAdminID {
    my($self,$o) = @_;
    return $o->admin_id;
}

sub _getPublisherAgentID {
    my($self,$o) = @_;
    return $o->agent_id;
}

sub _getPublisherClientAccountID {
    my($self,$o) = @_;
    return $o->client_account_id;
}

#sub _getPublisherTableKeyName {
#    return 'publisher_id';
#}

sub _getPublisherMap {
    my($self) = @_;
    my %m;
    my $sql = "SELECT publisher_id, publisher_name from publisher";
    #my $sth = $dbo->DoCmd($sql);
    my $sth = $self->{dbo}->DoCmd($sql);
    while( my($id,$name) = $sth->fetchrow_array() )
    {
       $m{$id} = $name;
    }
    return \%m;
}

sub _getPublisherName {
    my($self, $id) = @_;
    # TODO
}

#--------------------------------------------------------------------------------
# Name: _createPublisherAccount:
#
# Desc:  Returns an existing publisher account or creates one if it doesn't exist
#        If an admin_id is present, then a publisher_indirect_balance_account is
#        used instead of a publisher_account.
#
# Args: payor_id     - The payorID for the account (required)
#       publisher_id - The publisherID (required)
#       admin_id     - The publisherId of an administrator or agent. (optional)
#
# Returns: the publisher account object if created, undef otherwise
#--------------------------------------------------------------------------------
sub _createPublisherAccount {
    my($self, %args) = @_;

    my $payorID          = $args{payor_id};
    my $publisherID      = $args{id};
    my $adminID          = $args{admin_id};
report("DEBUG:USPublisherPayeeTransaction: publisherID($publisherID) adminID(". printNull($adminID) .") payorID($payorID)");

    assert($payorID);
    assert($publisherID);

    my $paObj;

    #----------------------------------------------------------------
    # Find the publisher account.  Note that if any admin or agent ID
    # is present, then an indirect balance account will be used.
    #----------------------------------------------------------------
    my %paArgs = (
        payor_id     => $payorID,
        publisher_id => $publisherID,
    );

    if ( $adminID )
    {
        $paArgs{indirect_publisher_id} = $adminID if ( $adminID );

        $paObj = RPS::DB::Item::PublisherIndirectBalanceAccount->Lookup( %paArgs );

        if( !$paObj )
        {
            if ( $self->exec_mode )
            {
                #$obj = RPS::DB::Item::PublisherAccount->Create
                $paObj = RPS::DB::Item::PublisherIndirectBalanceAccount->Create( %paArgs );
                $paObj->save();
                report("USPublisherPayeeTransaction:_createPublisherAccount -- created publisher_indirect_balance_account "
                    . "for pub($publisherID) payor($payorID) indirectPub($adminID)");
            }
            else
            {
                report("USPublisherPayeeTransaction:_createPublisherAccount -- "
                    . "non-exec mode: skipping publisher_indirect_balance_account "
                    . "for pub($publisherID) payor($payorID) indirectPub($adminID)");
            }
        }
    }
    else
    {
        $paObj = RPS::DB::Item::PublisherAccount->Lookup( %paArgs );

        if( !$paObj )
        {
            if ( $self->exec_mode )
            {
                #$obj = RPS::DB::Item::PublisherAccount->Create
                $paObj = RPS::DB::Item::PublisherAccount->Create( %paArgs );
                $paObj->save();
                report("USPublisherPayeeTransaction:_createPublisherAccount -- created publisher_account "
                    . "for pub($publisherID) payor($payorID)");
            }
            else
            {
                report("USPublisherPayeeTransaction:_createPublisherAccount -- "
                    . "non-exec mode: skipping publisher_account for pub($publisherID) payor($payorID)");
            }
        }
    }

    return $paObj;
}# _createPublisherAccount

sub _findPublisher {
    my($self, %args) = @_;
    my $name            = $args{name};
    my $clientAccountID = $args{client_account_id};
    my $isAdmin         = $args{is_admin};
    my $isAgency        = $args{is_agency};
    my $adminID         = $args{admin_id};
    my $agentID         = $args{agent_id};
    my $publisherID     = $args{publisher_id};

    #----------------------------------------------------------------
    # publisherID can be used to override the default method of using
    # the publisher name (and client account id, if present).
    #----------------------------------------------------------------
    assert($name) if ( !$publisherID );


    my $dbo = $self->{dbo};

    my $sql;
    my $sth;

    if ( $publisherID )
    {
       $sql = "SELECT * from publisher WHERE publisher_id = $publisherID ";
    }
    else
    {
        # Look for the publisher by name
        $sql = "SELECT * FROM publisher WHERE publisher_name=".  $dbo->DBQuote($name) . " ";

        if ( $clientAccountID )
        {
            $sql .= "AND client_account_id=" . $dbo->DBQuote($clientAccountID) . " ";
        }
    }

    if ( $adminID ) {
        $sql .= "AND admin_id=$adminID ";
    }
    elsif( $agentID )
    {
        $sql .= "AND agent_id=$agentID ";
    }

    if ( $isAdmin ) {
        $sql .= "AND is_admin=1 ";
    }
    elsif( $isAgency )
    {
        $sql .= "AND is_agency=1 ";
    }


    report("_findPublisher: sql = $sql");

    my $collection = Common::DB::ItemCollection->new(
        class => "RPS::DB::Item::Publisher",
        query => $sql,
        dbID  => kDB,
    );
    return $collection;

}#_findPublisher

sub _getTransactionCurrencyCode { 'USD'; }

sub _getPublisherString { 'publisher'; }

1;
