#------------------------------------------------------------
# Copyright (C) 2006 RoyaltyShare, Inc.   All Rights Reserved
# $Id$
#------------------------------------------------------------
package RPS::License::BaseLicense;

# This is the base class for all of our track licenses.
# There is a set of common columns that most flavors will have,
# and this class handles those.
# Note that you will never want to instantiate this directly.

use strict;
use warnings;
use Data::Dumper;
use Carp;
use Date::Calc qw( Date_to_Days Decode_Date_US );

use lib '/app/tools/common/lib';
use Common::Assert;
use Common::Util qw(decodeDateMysql);
use Common::Log;

use lib '/app/tools/rps/lib';
use RPS::DB::Item::ReserveLiquidation;
use RPS::DB::Item::FormDefaults;
use RPS::DB::Item::MechanicalStatementItem;
use RPS::DB::Item::RegionCountryMap;
use RPS::DB::Item::Product;
use RPS::License::LicenseType;

use Common::FormObject;
use base 'Common::FormObject';

use constant kDateLowerLimit => '1900-01-01';
use constant kDateUpperLimit => '2050-12-31';

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

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

    my %properties;

    if ( $args{_dbItem} ) {
        $self->_propertiesFromDBItem( \%properties, $args{_dbItem} );
    } elsif ( $args{trackLicenseID} ) {
        $self->_propertiesFromDB( \%properties, $args{trackLicenseID} );
    } elsif ( $args{trackID} ) {
        $self->_propertiesFromDefaults(
            \%properties,
            trackID                 => $args{trackID},
            licenseType             => $args{licenseType},
            controlledCompositionID => $args{controlledCompositionID}
        );
    } else {

        # this shouldn't happen because you can't create a new TrackLicense
        # without knowing which track or controlledComp to link it with
        #
        assert(0);
    }

    $self->_initProperties( \%properties );

    return $self;
}

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

    my $dbItem = $self->_getDBItem($trackLicenseID);
    $self->_propertiesFromDBItem( $hrProperties, $dbItem );
}

#sub _getDBItem
#{
#    my ($self, $id) = @_;
#
#    die "ERROR - You must override this method to instantiate the correct 'flavor' of DB Item";
#}

# this gets called after we update/insert so
# we can refresh our properties
sub _setPropertiesFromDBItem {
    my ( $self, $dbItem ) = @_;

    my %properties;
    $self->_propertiesFromDBItem( \%properties, $dbItem );
    $self->_initProperties( \%properties );
}

# You are going to want to override this method to set up the key property.
# For example, if this is a Canadian track license, that might be 'ca_track_license_id'.
#
sub _propertiesFromDBItem {
    my ( $self, $hrProperties, $dbItem ) = @_;

    # !!! Note that the _key_ field will need to be declared and set in the overridden method.
    $hrProperties->{track_id}                   = $dbItem->track_id,
    $hrProperties->{type}                       = $dbItem->type,
    $hrProperties->{share}                      = $dbItem->share,
    $hrProperties->{payor_id}                   = $dbItem->payor_id,
    $hrProperties->{status}                     = $dbItem->status,
    $hrProperties->{inactive}                   = $dbItem->inactive,
    $hrProperties->{date_sent}                  = $dbItem->date_sent;
    $hrProperties->{date_received}              = $dbItem->date_received;
    $hrProperties->{date_issued}                = $dbItem->date_issued;
    $hrProperties->{lock_date}                  = $dbItem->lock_date;
    $hrProperties->{term_start}                 = $dbItem->term_start;
    $hrProperties->{term_end}                   = $dbItem->term_end;
    $hrProperties->{publisher_direct}           = $dbItem->publisher_direct;
    $hrProperties->{issuer_license_id}          = $dbItem->issuer_license_id;
    $hrProperties->{rate_basis}                 = $dbItem->rate_basis;
    $hrProperties->{rate_type}                  = $dbItem->rate_type;
    $hrProperties->{finance_account_id}         = $dbItem->finance_account_id;
    $hrProperties->{reserve_percentage}         = $dbItem->reserve_percentage;
    $hrProperties->{penny_rate}                 = $dbItem->penny_rate;
    $hrProperties->{product_type_id}            = $dbItem->product_type_id;
    $hrProperties->{rate_percentage}            = $dbItem->rate_percentage;
    $hrProperties->{percentage_of_sales}        = $dbItem->percentage_of_sales;
    $hrProperties->{packaging_deduction}        = $dbItem->packaging_deduction;
    $hrProperties->{free_goods}                 = $dbItem->free_goods;
    $hrProperties->{misc_deduction}             = $dbItem->misc_deduction;
    $hrProperties->{date_created}               = $dbItem->date_created;
    $hrProperties->{date_modified}              = $dbItem->date_modified;
    $hrProperties->{created_by}                 = $dbItem->created_by;
    $hrProperties->{modified_by}                = $dbItem->modified_by;
    $hrProperties->{region_id}                  = $dbItem->region_id,
    $hrProperties->{comments}                   = $dbItem->comments,
    $hrProperties->{cross_collateralized}       = $dbItem->cross_collateralized,
    $hrProperties->{digital_reserves_enabled}   = $dbItem->digital_reserves_enabled,

      # from ControlledComp
    $hrProperties->{controlled_composition_id}  = $dbItem->controlled_composition_id;
    $hrProperties->{rate_percentage}            = $dbItem->rate_percentage;
}

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

    # pre-defined defaults
    #
    $hrProperties->{rate_percentage}     = 100;
    $hrProperties->{percentage_of_sales} = 100;

    my $defaultPayor = RPS::DB::Item::Payor->GetDefault();
    $hrProperties->{payor_id} = $defaultPayor->payor_id;

    # trackID is required to create a new TrackLicense
    #
    my $trackID = $args{trackID};
    assert($trackID);
    $hrProperties->{track_id} = $trackID;

    # !!! Set the 'type' property in the subclass.
}

# !!! Will need to be overidden to set the Key property.
#
sub _initProperties {
    my ( $self, $props ) = @_;

    $self->{TrackID}                = Common::FormObject::Scalar->new( value => $props->{track_id}, required => 1 );
    $self->{Type}                   = Common::FormObject::Scalar->new( value => $props->{type}, required => 1 );
    $self->{Share}                  = Common::FormObject::Scalar::Percent->new(
        value => $props->{share}, precision => '4.2', minValue => 0.1, maxValue => 9999, required => 1
    );
    $self->{Status}                 = Common::FormObject::Scalar->new( value => $props->{status}, readOnly => 1 );
    $self->{ParentTrackLicenseID}   = Common::FormObject::Scalar->new( value => $props->{parent_track_license_id} );
    $self->{Inactive}               = Common::FormObject::Scalar::Boolean->new( value => $props->{inactive} );
    $self->{PayorID}                = Common::FormObject::Scalar->new( value => $props->{payor_id} );
    $self->{DateSent}               = Common::FormObject::Scalar::Date->new( value => $props->{date_sent} );
    $self->{DateReceived}           = Common::FormObject::Scalar::Date->new( value => $props->{date_received} );
    $self->{DateIssued}             = Common::FormObject::Scalar::Date->new( value => $props->{date_issued} );
    $self->{LockDate}               = Common::FormObject::Scalar::Date->new( value => $props->{lock_date} );
    $self->{TermStart}              = Common::FormObject::Scalar::Date->new( value => $props->{term_start} );
    $self->{TermEnd}                = Common::FormObject::Scalar::Date->new( value => $props->{term_end} );
    $self->{PublisherDirect}        = Common::FormObject::Scalar::Boolean->new( value => $props->{publisher_direct} );
    $self->{IssuerLicenseID}        = Common::FormObject::Scalar::String->new( value => $props->{issuer_license_id}, maxlength => 40 );
    $self->{DigitalReservesEnabled} = Common::FormObject::Scalar::Boolean->new( value => $props->{digital_reserves_enabled} );
    $self->{RegionID}               = Common::FormObject::Scalar->new( value => $props->{region_id} );
    $self->{Comments}               = Common::FormObject::Scalar::String->new( value => $props->{comments} );
    $self->{DateCreated}            = Common::FormObject::Scalar::DateTime->new( value => $props->{date_created},  readOnly => 1 );
    $self->{DateModified}           = 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 ReserveLiquidationList { shift->{ReserveLiquidationList} }

sub validate {
    my ( $self, $skipRequiredFields ) = @_;

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

    return $valid if ($skipRequiredFields);

    if ( !$self->PublisherID() && $self->Type() != RPS::License::LicenseType::kPublicDomain ) {
        $self->{PublisherID}->setError(Common::FormObject::kErrFieldBlank);
        $valid = 0;
    }

    if ( $self->DigitalReservesEnabled() && !$self->ReservePercentage() ) {
        $self->{ReservePercentage}->setError(Common::FormObject::kErrRequiredFields);
        $valid = 0;
    }

    if (   ( $self->Type() == RPS::License::LicenseType::kPublishingLicense )
        || ( $self->Type() == RPS::License::LicenseType::kRingtone ) ) {
        my $sum = 0;
        if ( $self->ReservePercentage() && $self->ReserveLiquidationList() ) {
            foreach my $liq ( @{ $self->ReserveLiquidationList->getList() } ) {
                if ( defined $liq && $liq->Percent() ) {
                    $sum += $liq->Percent();
                }
            }
            if ( $sum == 0 ) {
                $self->ReserveLiquidationList->setError(Common::FormObject::kErrFieldBlank);
                $valid = 0;
            }
        }
    }

    return $valid;
}

sub _setDBValues {
    my ( $self, $dbItem ) = @_;
    assert($dbItem);

    # original TrackLicense
    #
    $dbItem->track_id( $self->TrackID() );
    $dbItem->type( $self->Type() );
    $dbItem->share( $self->Share() );
    $dbItem->date_sent( $self->DateSent() );
    $dbItem->date_received( $self->DateReceived() );
    $dbItem->date_issued( $self->DateIssued() );
    $dbItem->lock_date( $self->LockDate() );
    $dbItem->term_start( $self->TermStart() );
    $dbItem->term_end( $self->TermEnd() );
    $dbItem->publisher_direct( $self->PublisherDirect() );
    $dbItem->issuer_license_id( $self->IssuerLicenseID() );
    $dbItem->inactive( $self->Inactive() );
    $dbItem->payor_id( $self->PayorID() );
    $dbItem->region_id( $self->RegionID() );
    $dbItem->digital_reserves_enabled( $self->DigitalReservesEnabled() );
}

# !!! Should we just mke the decision that, irregardless of what table we read the data from,
# the XML Key Property will _always_ be called 'TrackLicenseID'?  That would make life easier. (I think).

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

    # This will either return an existing item, or a new item, depending on whether
    # we have an ID yet.
    #
    return $self->_getDBItem( $self->TrackLicenseID() );
}

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

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

    $self->_setDBValues($dbItem);

    $dbItem->save();

    $self->_setPropertiesFromDBItem($dbItem);

}

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

    # Using a somewhat more certain method now to tell when a track license has been used.
    #
    return undef if ( $self->{InUse} );

    my $dbItem = $self->_getDBItem( $self->TrackLicenseID() );
    $dbItem->delete();
}

# Need to handle PublisherID a little differently.
# I want to be automatically update the PublisherName field when this is changed.
# !!! But, Publishers are context-specific... So this needs to become more abstract.
#
sub PublisherID {
    my ( $self, @args ) = @_;

    if ( $self->{PublisherID} ) {
        my $rval = $self->{PublisherID}->access(@args);
        if ( scalar @args && $rval ) {
            my $pubID         = $self->{PublisherID}->access();
            my $publisherName = '- Unknown -';
            if ($pubID) {
                my $pubObj = $self->_getPublisherObject($pubID);
            }

            # This field is read-only...  The 'best' way to deal with it is to
            # simply _replace_ the object.
            #
            $self->{PublisherName} = Common::FormObject::Scalar->new( value => $publisherName, readOnly => 1 );
        }
        return $rval;
    }

}

sub _getPublisherObject {
    my ( $self, $pubID ) = @_;

    # Override this to fetch the correct sort of publisher.
    #
    die "ERROR - You must override _getPublisherObject";

    # Example:
    #		    my $pubObj = RPS::Publisher::Publisher->new(publisherID => $pubID);
}

###
1;    #
###
