#---------------------------------------------------------------
# ____                   _ _         ____  _
#|  _ \ ___  _   _  __ _| | |_ _   _/ ___|| |__   __ _ _ __ ___
#| |_) / _ \| | | |/ _` | | __| | | \___ \| '_ \ / _` | '__/ _ \
#|  _ < (_) | |_| | (_| | | |_| |_| |___) | | | | (_| | | |  __/
#|_| \_\___/ \__, |\__,_|_|\__|\__, |____/|_| |_|\__,_|_|  \___|
#            |___/             |___/
#
# Copyright (C) 2009 RoyaltyShare, Inc.   All Rights Reserved
#---------------------------------------------------------------
package BookPub::Catalog::Product::Book;
use strict;
use warnings;
use Data::Dumper;

use lib '/app/tools/common/lib';
use lib '/app/tools/bookpub/lib';
use BookPub::DB::Item::BookProduct;
use BookPub::DB::Item::ProductType;
use BookPub::DB::Item::BookFormat;
use BookPub::DB::Item::OnixCode;
use Common::RSApp;
use Common::Util;
use Common::Assert;
use Common::FormObject;

use base 'BookPub::Catalog::Product';

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

    my $dbItem = BookPub::DB::Item::BookProduct->Lookup( product_id => $productID );

    $self->_propertiesFromDBItem( $hrProperties, $dbItem );
}

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

    # !!! Don't need to set 'product_id' : That is handled in the base class.
    #
    $hrProperties->{book_id}                     = $dbItem->book_id;
    $hrProperties->{book_format_id}              = $dbItem->book_format_id;
    $hrProperties->{onix_code_publishing_status} = $dbItem->onix_code_publishing_status;
    $hrProperties->{isbn10}                      = $dbItem->isbn10;
    $hrProperties->{isbn13}                      = $dbItem->isbn13;
    $hrProperties->{work_id}                     = $dbItem->work_id;
    $hrProperties->{imprint_id}                  = $dbItem->imprint_id;
    $hrProperties->{publisher_id}                = $dbItem->publisher_id;
    $hrProperties->{language_code}               = $dbItem->language_code;
    $hrProperties->{num_pages}                   = $dbItem->num_pages;
    $hrProperties->{edition}                     = $dbItem->edition;
    $hrProperties->{average_rank}                = $dbItem->average_rank;
    $hrProperties->{date_created}                = $dbItem->date_created;
    $hrProperties->{date_modified}               = $dbItem->date_modified;
    $hrProperties->{created_by}                  = $dbItem->created_by;
    $hrProperties->{modified_by}                 = $dbItem->modified_by;

    # Invoke the inherited method with a _different_ db item.
    #
    my $baseDBItem = BookPub::DB::Item::Product->Lookup( product_id => $dbItem->product_id );
    $self->SUPER::_propertiesFromDBItem( $hrProperties, $baseDBItem );
}

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

    # By _definition_, the product_type_id for a book product is 'book product'.
    # So we'll force that value before we call the inherited init method.
    $props->{product_type_id} = BookPub::DB::Item::ProductType::kBook;

    # Invoke the inherited method first.
    #
    $self->SUPER::_initProperties($props);

    $self->{BookID}                   = Common::FormObject::Scalar->new( value => $props->{book_id} );
    $self->{BookFormatID}             = Common::FormObject::Scalar->new( value => $props->{book_format_id} );
    $self->{OnixCodePublishingStatus} = Common::FormObject::Scalar->new( value => $props->{onix_code_publishing_status} );
    $self->{ISBN10} = BookPub::Catalog::Product::Book::ISBN10->new( value => $props->{isbn10} );
    $self->{ISBN13} = BookPub::Catalog::Product::Book::ISBN13->new( value => $props->{isbn13} );
    $self->{WorkID} = Common::FormObject::Scalar::String->new( value => $props->{work_id} );
    $self->{ImprintID}   = Common::FormObject::Scalar->new( value => $props->{imprint_id} );
    $self->{PublisherID} = Common::FormObject::Scalar->new( value => $props->{publisher_id} );
    $self->{Language} = Common::FormObject::Scalar::Language->new( value => $props->{language_code} );
    $self->{NumPages}    = Common::FormObject::Scalar::Integer->new( value => $props->{num_pages} );
    $self->{Edition}     = Common::FormObject::Scalar::Integer->new( value => $props->{edition} );
    $self->{AverageRank} = Common::FormObject::Scalar::Integer->new( value => $props->{average_rank} );
    $self->{CreatedDate}  = Common::FormObject::Scalar::DateTime->new( value => $props->{date_created},  readOnly => 1 );
    $self->{ModifiedDate} = Common::FormObject::Scalar::DateTime->new( value => $props->{date_modified}, readOnly => 1 );
    $self->{CreatedBy}    = Common::FormObject::Scalar::UserName->new( value => $props->{created_by},    readOnly => 1 );
    $self->{ModifiedBy}   = Common::FormObject::Scalar::UserName->new( value => $props->{modified_by},   readOnly => 1 );
}

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

    # Before doing anything, see if we have a product_id yet.  If we don't, we're creating
    # a new record. (Actually, _two_ new records - product and book_product).
    #
    my $productID = $self->ProductID();

    # Now invoke the inherited method.
    # This will create and/or update the 'product' table.
    # Assuming that works out, we'll then get passed back a DB::Item::Product reference
    # from which we can get the product_id (if necessary).
    #
    my $productDBObj = $self->SUPER::_saveProduct();

    # Now we can update OUR table.
    #
    my $bookProductDBObj;
    if ($productID) {
        $bookProductDBObj = BookPub::DB::Item::BookProduct->Lookup( product_id => $productID );
    } else {
        $productID = $productDBObj->product_id;
        $bookProductDBObj = BookPub::DB::Item::BookProduct->Create( product_id => $productID );
    }

    # We need to translate the type and subtype into a format id.
    #

    my $typeCode    = $self->BookFormatType();
    my $subtypeCode = $self->BookFormatSubtype();

    my $typeCodeDB    = BookPub::DB::Item::OnixCode->Lookup( code_value => $typeCode );
    my $subtypeCodeDB = BookPub::DB::Item::OnixCode->Lookup( code_value => $subtypeCode );

    my $bookFormat = BookPub::DB::Item::BookFormat->LookupOrCreate(
        type_onix_code_id    => $typeCodeDB->onix_code_id,
        subtype_onix_code_id => $subtypeCodeDB->onix_code_id,
    );

    $bookProductDBObj->book_format_id( $bookFormat->book_format_id );
    $bookProductDBObj->onix_code_publishing_status( $self->OnixCodePublishingStatus() );

    $bookProductDBObj->book_id( $self->BookID() );
    $bookProductDBObj->isbn10( $self->ISBN10() );
    $bookProductDBObj->isbn13( $self->ISBN13() );
    $bookProductDBObj->work_id( $self->WorkID() );

    $bookProductDBObj->imprint_id( $self->ImprintID() );
    $bookProductDBObj->publisher_id( $self->PublisherID() );
    $bookProductDBObj->language_code( $self->Language() );
    $bookProductDBObj->num_pages( $self->NumPages() );
    $bookProductDBObj->edition( $self->Edition() );

    $bookProductDBObj->save();

    return $bookProductDBObj;

}

sub isEBook {
    my $self = shift;
    assert( $self->ProductID );

    return BookPub::DB::Item::BookProduct->IsEBook( productID => $self->ProductID );
}

sub isSubFormat {
    my $self        = shift;
    my $subformatID = shift;

    assert( $self->ProductID );
    assert($subformatID);

    return BookPub::DB::Item::BookProduct->IsSubFormat( productID => $self->ProductID, subformatID => $subformatID );
}

sub isPublished {
    my $self = shift;
    my $code = $self->OnixCodePublishingStatus;

    if ( !defined($code) || $code eq '00' || $code eq '04' ) {
        return 1;
    } else {
        return;
    }
}

###
1;    #
###

package BookPub::Catalog::Product::Book::ISBN10;

use strict;
use warnings;

use lib '/app/tools/common/lib';
use lib '/app/tools/bookpub/lib';
use Common::Assert;
use Common::FormObject;

use base 'Common::FormObject::Scalar::String';

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

    my $valid = $self->SUPER::_isValid();

    return $valid unless $valid;

    my $value = $self->{_value};
    if ( defined $value ) {
        if ( length $value != 10 ) {
            $valid = 0;
            $self->setError('isbn10_wrong_length');
        } elsif ( $value !~ /^(\d{9})([0-9X]{1})$/ ) {
            $valid = 0;
            $self->setError(Common::FormObject::kErrFieldInvalid);
        }
    }

    return $valid;
}

# Overiding _setValue to transparently convert 'x' to 'X'.
#
sub _setValue {
    my ( $self, $newValue ) = @_;
    if ( defined $newValue ) {
        $newValue =~ s/x/X/g;
    }

    return $self->SUPER::_setValue($newValue);
}

###
1;    #
###

package BookPub::Catalog::Product::Book::ISBN13;

use strict;
use warnings;

use lib '/app/tools/common/lib';
use lib '/app/tools/bookpub/lib';
use Common::Assert;
use Common::FormObject;

use base 'Common::FormObject::Scalar::String';

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

    my $valid = $self->SUPER::_isValid();

    return $valid unless $valid;

    my $value = $self->{_value};
    if ( defined $value ) {
        if ( length $value != 13 ) {
            $valid = 0;
            $self->setError('isbn13_wrong_length');
        } elsif ( $value !~ /^(\d{13})$/ ) {
            $valid = 0;
            $self->setError(Common::FormObject::kErrFieldInvalid);
        }
    }

    return $valid;
}

###
1;    #
###
