#------------------------------------------------------------
# Copyright (C) 2006 RoyaltyShare, Inc.   All Rights Reserved
#------------------------------------------------------------
package RPS::ArtistContract::ArtistContract;

use strict;
use warnings;
use Carp;
use Date::Calc qw(Days_in_Month Decode_Month);

use lib '/app/tools/rps/lib';

#use RPS::ArtistContract::TermList;
use RPS::ArtistContract::TermHash;
use RPS::ArtistContract::DefaultTerm;
use RPS::Payee::ArtistPayee;
use RPS::ArtistContract::UnitEscalationList;
use RPS::ControlledComposition::ControlledComposition;

use RPS::DB::Item::NewArtistContract;
use RPS::DB::Item::Artist;
use RPS::DB::Item::ContractRateType;
use RPS::DB::Item::AlbumContract;
use RPS::DB::Item::TrackContract;
use RPS::DB::Item::LicenseIncome;
use RPS::DB::Item::ArtistContractLicenseIncome;
use RPS::DB::Item::ExpenseType;
use RPS::DB::Item::ControlledComposition;
use RPS::DB::Item::ReserveLiquidation;

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

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

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

    my %properties;
    if ( $args{_dbItem} ) {
        $self->_propertiesFromDBItem( \%properties, $args{_dbItem} );
    } elsif ( $args{artistContractID} ) {
        $self->_propertiesFromDB( \%properties, $args{artistContractID} );
    } else {
        $self->_propertiesFromDefaults( \%properties );
    }

    $self->_initProperties( \%properties );
    $self->_initSubs( \%properties );

    # save parameters if contract copy mode is applied
    $self->_saveArgsForCopyMode(\%args) if $args{patternArtistContractID};

    return $self;
}

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

    my $dbItem = RPS::DB::Item::NewArtistContract->Lookup( artist_contract_id => $id, deleted => 0 );
    $self->_propertiesFromDBItem( $hrProperties, $dbItem );
}

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

    $hrProperties->{artist_contract_id} = $dbItem->artist_contract_id;
    $hrProperties->{title}              = $dbItem->title;
    $hrProperties->{artist_description} = $dbItem->artist_description;
    $hrProperties->{artist_payee_id}    = $dbItem->artist_payee_id;
    $hrProperties->{payor_id}           = $dbItem->payor_id;
    $hrProperties->{client_contract_id} = $dbItem->client_contract_id;
    $hrProperties->{issue_date}         = $dbItem->issue_date;
    $hrProperties->{term_start}         = $dbItem->term_start;
    $hrProperties->{term_end}           = $dbItem->term_end;
    $hrProperties->{reserve_rate}       = $dbItem->reserve_rate;

    $hrProperties->{comments} = $dbItem->comments;
    $hrProperties->{deleted}  = $dbItem->deleted;

    # !!! JPK - Going to ignore this property - We'll want to drop this column from the table soon.
    #
    #    $hrProperties->{digital_reserves_enabled} = $dbItem->digital_reserves_enabled;

    $hrProperties->{date_created}  = $dbItem->date_created;
    $hrProperties->{date_modified} = $dbItem->date_modified;
    $hrProperties->{created_by}    = $dbItem->created_by;
    $hrProperties->{modified_by}   = $dbItem->modified_by;

}

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

    $self->{ArtistContractID}  = Common::FormObject::Scalar->new( value => $props->{artist_contract_id}, readOnly => 1 );
    $self->{Title}             = Common::FormObject::Scalar::String->new( value => $props->{title}, required => 1 );
    $self->{ArtistDescription} = Common::FormObject::Scalar::String->new( value => $props->{artist_description} );
    $self->{ArtistPayeeID}     = Common::FormObject::Scalar->new( value => $props->{artist_payee_id}, required => 1 );
    $self->{PayorID}           = Common::FormObject::Scalar->new( value => $props->{payor_id},        required => 1 );
    $self->{ClientContractID}  = Common::FormObject::Scalar::String->new( value => $props->{client_contract_id} );
    $self->{IssueDate}         = Common::FormObject::Scalar::Date->new( value => $props->{issue_date} );
    $self->{TermStart}         = Common::FormObject::Scalar::Date->new( value => $props->{term_start} );
    $self->{TermEnd}           = Common::FormObject::Scalar::Date->new( value => $props->{term_end} );
    $self->{ReserveRate}       = Common::FormObject::Scalar::Percent->new( value => $props->{reserve_rate} );

    $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 );

    $self->{Comments}          = Common::FormObject::Scalar::String->new( value => $props->{comments} );
    $self->{Deleted}           = Common::FormObject::Scalar->new( value => $props->{deleted} );

    # Combining Title and ClientContractID for autocomplete purposes
    #
    my $titleAndClientContractID = "(" . $props->{client_contract_id} . ") " . $props->{title};
    $self->{TitleAndClientContractID} = Common::FormObject::Scalar::String->new( value => $titleAndClientContractID );

    # !!! jpk - I don't agree with this at all - this stuff really should be in load subs.
    # There _is_ a use for a contract object without all this extra state.
    # But... I'll leave it alone for now.
    #

    # -jff- the artist contract by itself is fairly useless,
    # so I feel like ArtistPayee is a pretty integral part of this object.
    # It was in the _initSubs, but I moved it here.
    #
    $self->{ArtistPayee} = RPS::Payee::ArtistPayee->new( artistPayeeID => $props->{artist_payee_id}, loadSubs => 0, readOnly => 1 );

    # the basic contract object needs to know if it has a ControlledComp or not.
    # So we'll look for one here and save it internally so we can reuse it later
    # in loadSubs (if necessary)
    #
    $self->{_ccomp} = RPS::ControlledComposition::ControlledComposition->new( contractID => $props->{artist_contract_id}, readOnly => 1 );
    my $hasCComp = 0;
    if ( defined $self->{_ccomp} && $self->{_ccomp}->ControlledCompositionID() ) {
        $hasCComp = 1;
    }
    $self->{HasCComp} = Common::FormObject::Scalar->new( value => $hasCComp, readOnly => 1 );

    # This is an editable section of the contract, so it
    # needs to be loaded here.
    #
    $self->{ReserveLiquidationList} = RPS::License::ReserveLiquidationList->new(
        id   => $props->{artist_contract_id},
        type => RPS::DB::Item::ReserveLiquidation::kTypeArtistContract,
    );

    $self->{RelatedAlbumsAndTracks} = $props->{artist_contract_id}
        ? RPS::DB::Item::AlbumContract->GetByContractID( $props->{artist_contract_id} )->size() +
          RPS::DB::Item::TrackContract->GetByContractID( $props->{artist_contract_id} )->size() +
          RPS::DB::Item::LicenseIncome->GetByContractID( $props->{artist_contract_id} )->size()
        : 0;
}

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

    if ( $self->loadSubs() ) {
        my $contractID = $props->{artist_contract_id};

        $self->{ControlledComposition} = $self->{_ccomp};
        $self->{TermList}              = RPS::ArtistContract::TermHash->new( artistContractID => $contractID );
        $self->{DefaultTerm}           = RPS::ArtistContract::DefaultTerm->new( artistContractID => $contractID );
    }
}

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

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

    # JPK - Don't have any canned defaults (yet)
    #
}

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

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

    my $sum = 0;
    if ( $self->ReserveRate() ) {
        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 save {
    my ($self) = @_;

    my $dbObj;
    if ( $self->ArtistContractID() ) {
        $dbObj = RPS::DB::Item::NewArtistContract->Lookup( artist_contract_id => $self->ArtistContractID() );
    } else {
        $dbObj = RPS::DB::Item::NewArtistContract->Create();
    }

    # set fields here
    #
    $dbObj->artist_payee_id( $self->ArtistPayeeID() );
    $dbObj->client_contract_id( $self->ClientContractID() );
    $dbObj->title( $self->Title() );
    $dbObj->artist_description( $self->ArtistDescription() );
    $dbObj->issue_date( $self->IssueDate() );
    $dbObj->reserve_rate( $self->ReserveRate() );
    $dbObj->payor_id( $self->PayorID() );
    $dbObj->term_start( $self->TermStart() );
    $dbObj->term_end( $self->TermEnd() );
    $dbObj->comments( $self->Comments() );
    $dbObj->deleted( $self->Deleted() );
    # save db item
    $dbObj->save();

    # copy mode is applied
    if ( $self->{_copyMode} ) {
        my $newArtistContractID = $dbObj->artist_contract_id;
        # editable blocks of a contract
        $self->_copyContractTerms($dbObj)                             if $self->{_copyContractTerms};
        $self->_copyReserveLiquidationSchedule($dbObj)                if $self->{_copyReserveSchedule};
        # non editable blocks of a contract
        $self->_copyLicenseIncomeSources($newArtistContractID)        if $self->{_copyLicenseIncomeSources};
        $self->_copyRecoupableExpenseTypes($newArtistContractID)      if $self->{_copyRecoupableExpenseTypes};
        $self->_copyControlledCompositionClause($newArtistContractID) if $self->{_copyControlledCompositionClause};
    }
    # create/edit mode
    else {
        # copy the term list
        $self->_copyContractTerms($dbObj);
        # copy the liquidation list.
        $self->_copyReserveLiquidationSchedule($dbObj);
    }

    # save the default term
    $self->{DefaultTerm}->ArtistContractTermID(undef) if ( !$self->ArtistContractID() );    # default term for new contract
    $self->{DefaultTerm}->ArtistContractID( $dbObj->artist_contract_id );
    $self->{DefaultTerm}->save();

    $dbObj->touch();
    $dbObj->save();
    $self->_init( _dbItem => $dbObj );
}

sub delete { 1 }


sub _saveArgsForCopyMode {
    my ($self, $hArgs) = @_;

    $self->{_copyMode} = 1;
    $self->{_patternArtistContractID}         = $hArgs->{patternArtistContractID};
    $self->{_copyContractTerms}               = $hArgs->{copyContractTerms};
    $self->{_copyReserveSchedule}             = $hArgs->{copyReserveSchedule};
    $self->{_copyLicenseIncomeSources}        = $hArgs->{copyLicenseIncomeSources};
    $self->{_copyRecoupableExpenseTypes}      = $hArgs->{copyRecoupableExpenseTypes};
    $self->{_copyControlledCompositionClause} = $hArgs->{copyControlledCompositionClause};

    return 1;
}

sub _copyLicenseIncomeSources {
    my ( $self, $newArtistContractID) = @_;

    return RPS::DB::Item::ArtistContractLicenseIncome->CopyFromPatternContractID(
        $self->{_patternArtistContractID},
        $newArtistContractID
    );
}

sub _copyRecoupableExpenseTypes {
    my ( $self, $newArtistContractID) = @_;

    return RPS::DB::Item::ExpenseType->CopyFromPatternContractID(
        $self->{_patternArtistContractID},
        $newArtistContractID
    );
}

sub _copyControlledCompositionClause {
    my ( $self, $newArtistContractID) = @_;

    RPS::DB::Item::ControlledComposition->CopyFromPatternContractID(
        $self->{_patternArtistContractID},
        $newArtistContractID
    );

    # copy relevant reserve liquidation records for the newly created controlled composition record
    my $oRecPattern = RPS::DB::Item::ControlledComposition->GetByContractID( $self->{_patternArtistContractID} );
    my $oRecNew     = RPS::DB::Item::ControlledComposition->GetByContractID( $newArtistContractID );
    # skip this step if there is no controlled composition
    return unless $oRecPattern && $oRecNew;

    return RPS::DB::Item::ReserveLiquidation->CopyFromPatternIDAndType(
        $oRecPattern->controlled_composition_id,
        RPS::DB::Item::ReserveLiquidation::kTypeControlledComposition,
        $oRecNew->controlled_composition_id
    );
}

sub _copyContractTerms {
    my ($self, $dbObj) = @_;

    foreach my $termKey ( keys %{ $self->{TermList}->getHash() } ) {
        my $term = $self->{TermList}->getHash()->{$termKey};
        $term->ArtistContractID( $dbObj->artist_contract_id ) if defined $term ;
    }
    $self->{TermList}->save();

    return 1;
}

sub _copyReserveLiquidationSchedule {
    my ($self, $dbObj) = @_;

    foreach my $liq ( @{ $self->{ReserveLiquidationList}->getList() } ) {
        if ( defined $liq && $liq->Percent() ) {
            # assign from the newly saved dbObj
            $liq->ID( $dbObj->artist_contract_id );
        }
    }
    $self->{ReserveLiquidationList}->save();

    return 1;
}


1;
