#------------------------------------------------------------
# Copyright (C) 2009 RoyaltyShare, Inc.   All Rights Reserved
#------------------------------------------------------------
package BookPub::Matcher::Sale;

use strict;
use warnings;

use lib '/app/tools/common/lib';
use Common::Assert;
use RSApache::Message;
use base 'Common::FormObject';

use lib '/app/tools/bookpub/lib';
use BookPub::DB::Item::Sale;
use BookPub::DB::Item::rNativeListPrice;
use BookPub::Sale::Match;

# !!! Going to make this class _abstract_, so we can share the interface between
# both the revenue and the pos sale tables.

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

    $self->SUPER::_init(%args);

    my %properties;
    if ( $args{dbItem} ) {
        $self->_propertiesFromDBItem( \%properties, $args{dbItem} );
    } elsif ( defined $args{saleID} ) {
        $self->_propertiesFromDB( \%properties, $args{saleID} );
    } elsif ( defined $args{fileID} && defined $args{lineNum} ) {
        $self->_propertiesFromDBViaFileAndLineNum( \%properties, $args{fileID}, $args{lineNum} );
    }

    my $rval = $self->_initProperties( \%properties );

    return $rval;
}

sub _propertiesFromDB {
    my ( $self, $hrProperties, $saleID ) = @_;
    assert( 0, 'override' );
}

sub _propertiesFromDBViaFileAndLineNum {
    my ( $self, $hrProperties, $fileID, $lineNum ) = @_;
    assert( 0, 'override' );
}

sub _propertiesFromDBItem {
    my ( $self, $hrProperties, $dbItem ) = @_;
    assert( 0, 'override' );
}

sub _initProperties {
    my ( $self, $hrProperties ) = @_;

    # JPK - Because this is a 'read only' object, I am only going to use
    # 'Scalar' fields when I want to get some formatting (dates, integers, etc).
    #
    $self->{SaleID}           = $hrProperties->{sale_id};
    $self->{FileID}           = $hrProperties->{file_id};
    $self->{ServiceID}        = $hrProperties->{service_id};
    $self->{PriceTypeID}      = $hrProperties->{price_type_id};
    $self->{ImportStatus}     = $hrProperties->{import_status};
    $self->{ProductType}      = $hrProperties->{product_type};
    $self->{FormatType}       = $hrProperties->{format_type};
    $self->{PurchaseType}     = $hrProperties->{purchase_type};
    $self->{ServiceProductID} = $hrProperties->{service_product_id};
    $self->{ProductID}        = $hrProperties->{product_id};
    $self->{MapID}            = $hrProperties->{map_id};
    $self->{Agency}           = $hrProperties->{is_agency};
    $self->{Free}             = $hrProperties->{is_free};
    $self->{Units}            = Common::FormObject::Scalar::Integer->new( value => $hrProperties->{units}, readOnly => 1 );

    my $listPrice;
    my $listPriceCurrency;

    # Check for a native list price record for this sale.
    # The SaleID value may be missing in case of non existent line number
    # when using _propertiesFromDBViaFileAndLineNum()
    my $nativePrice = BookPub::DB::Item::rNativeListPrice->Lookup( sale_id => $self->{SaleID} || 0 );
    if ($nativePrice) {
        $listPrice         = $nativePrice->r_native_list_price;
        $listPriceCurrency = $nativePrice->r_native_list_price_currency;
    } else {
        $listPrice = $hrProperties->{list_price};

        # We need to use the list price currency if we have one.
        # Otherwise, default to the revenue currency.
        $listPriceCurrency = $hrProperties->{r_list_price_currency};
        if ( !$listPriceCurrency ) {
            $listPriceCurrency = $hrProperties->{currency_code};
        }
    }

    $self->{ListPrice} = Common::FormObject::Scalar::Money->new( value => $listPrice, currencyCode => $listPriceCurrency, readOnly => 1 );
    $self->{Discount}  = $hrProperties->{discount};
    $self->{UnitPrice} = Common::FormObject::Scalar::Money->new(
        value        => $hrProperties->{unit_price},
        currencyCode => $hrProperties->{currency_code},
        readOnly     => 1
    );
    $self->{Revenue} = Common::FormObject::Scalar::Money->new(
        value        => $hrProperties->{revenue},
        currencyCode => $hrProperties->{currency_code},
        readOnly     => 1
    );
    $self->{ConversionRate}   = $hrProperties->{conversion_rate};
    $self->{CurrencyCode}     = $hrProperties->{currency_code};
    $self->{CountryCode}      = $hrProperties->{country_code};
    $self->{LineNum}          = $hrProperties->{line_num};
    $self->{DateBegin}        = Common::FormObject::Scalar::Date->new( value => $hrProperties->{date_begin}, readOnly => 1 );
    $self->{DateEnd}          = Common::FormObject::Scalar::Date->new( value => $hrProperties->{date_end}, readOnly => 1 );
    $self->{rFormat}          = $hrProperties->{r_format};
    $self->{rClientProductID} = $hrProperties->{r_client_product_id};
    $self->{rISBN10}          = $hrProperties->{r_isbn10};
    $self->{rISBN13}          = $hrProperties->{r_isbn13};
    $self->{rTitle}           = $hrProperties->{r_title};
    $self->{rSubtitle}        = $hrProperties->{r_subtitle};
    $self->{rAuthor}          = $hrProperties->{r_author};
    $self->{rChapterTitle}    = $hrProperties->{r_chapter_title};
    $self->{rChapterOrdinal}  = $hrProperties->{r_chapter_ordinal};
    $self->{rImprint}         = $hrProperties->{r_imprint};
    $self->{rNarrator}        = $hrProperties->{r_narrator};
    $self->{rComments}        = $hrProperties->{r_comments};
    $self->{rChannel}         = $hrProperties->{r_channel};
    $self->{rUnits}           = $hrProperties->{r_units};
    $self->{rSales}           = $hrProperties->{r_sales};
    $self->{rReturns}         = $hrProperties->{r_returns};
    $self->{rAdjustments}     = $hrProperties->{r_adjustments};
    $self->{rFee}             = $hrProperties->{r_fee};
    $self->{rListPrice}       = $hrProperties->{r_list_price};
    $self->{rDiscount}        = $hrProperties->{r_discount};
    $self->{rUnitPrice}       = $hrProperties->{r_unit_price};
    $self->{rRevenue}         = $hrProperties->{r_revenue};
    $self->{rPromoCode}       = $hrProperties->{r_promo_code};
    $self->{DateCreated}      = Common::FormObject::Scalar::Date->new( value => $hrProperties->{date_created}, readOnly => 1 );
    $self->{DateModified}     = Common::FormObject::Scalar::Date->new( value => $hrProperties->{date_modified}, readOnly => 1 );

    return $self;
}

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

    # !!! This interface is not intended to create Sale records from scratch...
    #
    assert( $self->{_dbItem} );

    my $dbItem = $self->{_dbItem};

    $dbItem->import_status( $self->ImportStatus );
    $dbItem->product_id( $self->ProductID );
    $dbItem->service_id( $self->ServiceID );
    $dbItem->map_id( $self->MapID );

    $dbItem->save();
}

sub matchToProduct {
    my ( $self, $productID, $serviceID ) = @_;

    my $dbItem = $self->dbItem();

    $dbItem->service_id($serviceID);

    # returns result object
    #
    # It's almost miraculous, but because we keep the relevant column names the same in all
    # of our 'sale' tables, we can pass any of their DB::Item classes to MakeMatch and
    # it just works...
    #
    my $matcher = BookPub::Sale::Match->new( client_id => Common::RSApp::GetClientID() );
    my $map_id = $matcher->MakeMatch( sale => $dbItem, productID => $productID );

    if ($map_id) {
        $self->ProductID($productID);
        $self->MapID($map_id);

        # For the love of god, please don't change the sale's service id here.
        # I almost lost my mind trying to figure out why this was happening...
        #    $self->ServiceID($serviceID);

        $self->save();
        return 1;
    } else {
        Common::Log::Print( $matcher->errstr );
        return undef;
    }
}

# This is a bit of a hack to make this interface more easily into the Matcher code.
#
sub dbItem {
    my ($self) = @_;

    return $self->{_dbItem};
}

1;
