#------------------------------------------------------------
# Copyright (C) 2006 RoyaltyShare, Inc.   All Rights Reserved
#------------------------------------------------------------
package Raptor::Tracker::LicenseIncome;

use strict;
use warnings;
use Carp;
use Data::Dumper;

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

use lib '/app/tools/rps/lib';
use RPS::File::Sale;

use lib '/app/tools/rps/lib';
use RPS::DB::Item::LicenseIncome;
use RPS::DB::Item::LicenseIncomeType;
use RPS::DB::Item::NewArtistContract;
use RPS::DB::Item::Album;
use RPS::DB::Item::Track;

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{licenseIncomeID} ) {
        $self->_propertiesFromDB( \%properties, $args{licenseIncomeID} );
    } else {
        $self->_propertiesFromDefaults( \%properties, $args{fileID} );
    }

    $self->_initProperties( \%properties );

    return $self;
}

sub _propertiesFromDB {
    my ( $self, $hrProperties, $id ) = @_;
    my $dbItem = RPS::DB::Item::LicenseIncome->Lookup( license_income_id => $id );
    $self->_propertiesFromDBItem( $hrProperties, $dbItem );
}

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

    $self->{_inDB} = 1;

    $hrProperties->{license_income_id}      = $dbItem->license_income_id;
    $hrProperties->{file_id}                = $dbItem->file_id;
    $hrProperties->{sale_id}                = $dbItem->sale_id;
    $hrProperties->{date}                   = $dbItem->date;
    $hrProperties->{units}                  = $dbItem->units;
    $hrProperties->{revenue}                = $dbItem->revenue;
    $hrProperties->{album_id}               = $dbItem->album_id;
    $hrProperties->{track_id}               = $dbItem->track_id;
    $hrProperties->{contract_id}            = $dbItem->contract_id;
    $hrProperties->{license_income_type_id} = $dbItem->license_income_type_id;
    $hrProperties->{memo}                   = $dbItem->memo;
    $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->{LicenseIncomeID} = Common::FormObject::Scalar->new( value => $props->{license_income_id}, readOnly => 1 );
    $self->{FileID}          = Common::FormObject::Scalar->new( value => $props->{file_id} );
    $self->{SaleID}          = Common::FormObject::Scalar->new( value => $props->{sale_id}, readOnly => 1 );
    $self->{Date} = Common::FormObject::Scalar::Date->new( value => $props->{date}, required => 1 );
    $self->{Units} = Common::FormObject::Scalar::Integer->new( value => $props->{units} );
    $self->{Revenue} = Common::FormObject::Scalar::Decimal->new( value => $props->{revenue}, required => 1, precision => '0.2' );
    $self->{AlbumID}             = Common::FormObject::Scalar->new( value => $props->{album_id} );
    $self->{TrackID}             = Common::FormObject::Scalar->new( value => $props->{track_id} );
    $self->{ContractID}          = Common::FormObject::Scalar->new( value => $props->{contract_id} );
    $self->{LicenseIncomeTypeID} = Common::FormObject::Scalar->new( value => $props->{license_income_type_id}, required => 1 );
    $self->{Memo} = Common::FormObject::Scalar::String->new( value => $props->{memo} );
    $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 );

    # Provide album, track, and contract titles.
    #
    my $albumTitle;
    my $catalogNumber;
    my $trackTitle;
    my $contractTitle;
    my $clientContractID;
    my $licenseIncomeType;

    if ( $props->{album_id} ) {
        my $album = RPS::DB::Item::Album->Lookup( album_id => $props->{album_id} );
        if ($album) {
            $albumTitle    = $album->title;
            $catalogNumber = $album->catalog_number;
        }
    }

    if ( $props->{track_id} ) {
        my $track = RPS::DB::Item::Track->Lookup( track_id => $props->{track_id} );
        if ($track) {
            $trackTitle = $track->title;
        }
    }

    if ( $props->{contract_id} ) {
        my $contract = RPS::DB::Item::NewArtistContract->Lookup( artist_contract_id => $props->{contract_id} );
        if ($contract) {
            $contractTitle    = $contract->title;
            $clientContractID = $contract->client_contract_id;
        }
    }

    if ( $props->{license_income_type_id} ) {
        my $type = RPS::DB::Item::LicenseIncomeType->Lookup( license_income_type_id => $props->{license_income_type_id} );
        $licenseIncomeType = $type->name;
    }

    $self->{AlbumTitle}        = Common::FormObject::Scalar::String->new( value => $albumTitle );
    $self->{CatalogNumber}     = Common::FormObject::Scalar::String->new( value => $catalogNumber );
    $self->{TrackTitle}        = Common::FormObject::Scalar::String->new( value => $trackTitle );
    $self->{ContractTitle}     = Common::FormObject::Scalar::String->new( value => $contractTitle );
    $self->{ClientContractID}  = Common::FormObject::Scalar::String->new( value => $clientContractID );
    $self->{LicenseIncomeType} = Common::FormObject::Scalar::String->new( value => $licenseIncomeType );

    # this is how the template tells the backend to delete one of these.
    # the default is 'OFF' (ie. don't delete)
    #
    $self->{Delete} = Common::FormObject::Scalar::Boolean->new();
}

sub _propertiesFromDefaults {
    my ( $self, $hrProperties, $fileID ) = @_;
    $hrProperties->{file_id} = $fileID;

}

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

    foreach my $field (qw(AlbumID TrackID ContractID LicenseIncomeTypeID Date Units Revenue Memo)) {
        if ( $self->$field() ) {
            $self->{_hasData} = 1;
        }
    }

    if ( $self->Delete() ) {

        # no need to perform further validation
        return 1;
    }

    if ( $self->{_hasData} ) {
        my $valid = $self->SUPER::validate();

        # Make sure we have all we need....
        #
        my $album;
        my $track;
        my $contract;

        if ( $self->ContractID() ) {
            $contract = RPS::DB::Item::NewArtistContract->Lookup( artist_contract_id => $self->ContractID() );
            if ( !$contract ) {
                $valid = 0;
                $self->setError('invalid contract id');
            }

            if ( $self->LicenseIncomeTypeID() ) {
                if ( !RPS::DB::Item::LicenseIncomeType->MatchesArtistContract( $self->LicenseIncomeTypeID(), $self->ContractID() ) ) {
                    $valid = 0;
                    $self->setError('invalid license income type id');
                }
            }
        }

        if ( $self->LicenseIncomeType() && !$self->LicenseIncomeTypeID() ) {
            $valid = 0;
            $self->setError('invalid license income type id');
        }

        if ( $self->AlbumID() ) {
            $album = RPS::DB::Item::Album->Lookup( album_id => $self->AlbumID() );
            if ( !$album ) {
                $self->setError('invalid album id');
                $valid = 0;
            }

            if ( $self->LicenseIncomeTypeID() ) {
                if ( !RPS::DB::Item::LicenseIncomeType->MatchesAlbumID( $self->LicenseIncomeTypeID(), $self->AlbumID() ) ) {
                    $valid = 0;
                    $self->setError('invalid license income type id');
                }
            }
        }

        if ( $self->TrackID() ) {
            $track = RPS::DB::Item::Track->Lookup( track_id => $self->TrackID() );
            if ( !$track ) {
                $self->setError('invalid track id');
                $valid = 0;
            }

            if ( $self->LicenseIncomeTypeID() ) {
                if ( !RPS::DB::Item::LicenseIncomeType->MatchesTrackID( $self->LicenseIncomeTypeID(), $self->TrackID() ) ) {
                    $valid = 0;
                    $self->setError('invalid license income type id');
                }
            }
        }

        # Need an album or a contract...
        #

        unless ( $album || $contract ) {
            $self->setError('album or contract are required');
            $valid = 0;
        }

        # If we have a contract and an album, the contract must be associated with that album.
        #
        # If we have an album and a track, the track must be on that album.
        #
        if ( $contract && $album ) {
            if ( !RPS::DB::Item::NewArtistContract->IsAlbumOnContract( $album->album_id, $contract->artist_contract_id ) ) {
                $self->setError( "album " . $album->album_id . " is not associated with contract " . $contract->artist_contract_id );
                $valid = 0;
            }
        }

        if ($track) {
            if ( !$album ) {
                $self->setError("cannot have a track without an album");
                $valid = 0;
            } elsif ( $track->album_id != $album->album_id ) {
                $self->setError( "track " . $track->track_id . " does not belong to album " . $album->album_id );
                $valid = 0;
            } elsif ( $contract && !RPS::DB::Item::NewArtistContract->IsTrackOnContract( $track->track_id, $contract->artist_contract_id ) )
            {
                $self->setError( "track " . $track->track_id . " is not associated with contract " . $contract->artist_contract_id );
                $valid = 0;
            }
        }

        if ( $self->Date() ) {
            my $date = $self->Date();
            my $year;

            #Current Unix time
            my $currentTime = time();

            #Get the current year to check year ranges
            my ( $sec, $min, $hour, $mday, $mon, $currentYear, $wday, $yday, $isdst ) = localtime($currentTime);

            #Must add 1900 to current year to get 4 digit year value
            $currentYear += 1900;

            # Let's make sure the year is reasonable.

            if ( $date =~ /^(\d{4})-\d{2}-\d{2}$/ ) {
                $year = $1;
                if ( ( $year < 1990 ) || ( $year > $currentYear ) ) {
                    $self->setError("date is invalid");
                    $valid = 0;
                }
            } else {
                $self->setError("date is invalid");
                $valid = 0;
            }
        }

        return $valid;
    } else {
        return 1;
    }
}

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

    if ( $self->Delete() ) {
        $self->delete();
        return 1;
    }

    return 1 unless $self->{_hasData};

    my $dbObj;
    if ( $self->LicenseIncomeID() ) {
        $dbObj = RPS::DB::Item::LicenseIncome->Lookup( license_income_id => $self->LicenseIncomeID() );
    } else {
        $dbObj = RPS::DB::Item::LicenseIncome->Create();
    }

    # set fields here
    #
    $dbObj->contract_id( $self->ContractID() );
    $dbObj->file_id( $self->FileID() );
    $dbObj->date( $self->Date() );
    $dbObj->units( $self->Units() );
    $dbObj->revenue( $self->Revenue() );
    $dbObj->album_id( $self->AlbumID() );
    $dbObj->track_id( $self->TrackID() );
    $dbObj->license_income_type_id( $self->LicenseIncomeTypeID() );
    $dbObj->memo( $self->Memo() );

    # save db item
    #
    $dbObj->save();

    $self->_init( _dbItem => $dbObj );

    $self->createSale();

    return $self;
}

sub delete {
    my $self = shift;

    if ( $self->{_inDB} ) {
        my $myDBObj = RPS::DB::Item::LicenseIncome->Lookup( license_income_id => $self->LicenseIncomeID() );

        $self->deleteSale();
        $myDBObj->delete();
    }
    return 1;
}

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

    assert( $self->FileID(), "ERROR - cannot create a sale from a license_income entity without a file_id" );

    my $myDBObj = RPS::DB::Item::LicenseIncome->Lookup( license_income_id => $self->LicenseIncomeID() );
    assert($myDBObj);

    my $sale;

    # If we already have a sale associated with this license_income record, we want to simply update its state.
    #
    if ( $myDBObj->sale_id ) {
        $sale = Raptor::DB::Item::Sale->Lookup( sale_id => $myDBObj->sale_id );
        if ( !$sale ) {
            die "ERROR - bad sale id in license_income " . $self->LicenseIncomeID();
        }
    } else {
        $sale = Raptor::DB::Item::Sale->Create();

        # Make sure we're using the correct native currency.
        #
        my $nativeCurrency = Common::Client::Current()->Locale()->currencyFormat()->currencyCode();
        $sale->currency_code($nativeCurrency);
    }

    $sale->date_begin( $self->Date() );
    $sale->date_end( $self->Date() );
    $sale->file_id( $self->FileID() );
    $sale->product_type(RPS::File::Sale::TYPE_LICENSE_INCOME);
    $sale->units( $self->Units() );
    $sale->total_revenue( $self->Revenue() );

    $sale->save();

    # We'll need to mark the LicenseIncome item with the new sale id
    # ... if it changed.  But if it didn't then save won't do anything anyway.
    #
    my $saleID = $sale->sale_id;
    $myDBObj->sale_id($saleID);
    $myDBObj->save();

}

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

    assert( $self->FileID(), "ERROR - cannot create a sale from a license_income entity without a file_id" );

    my $myDBObj = RPS::DB::Item::LicenseIncome->Lookup( license_income_id => $self->LicenseIncomeID() );
    assert($myDBObj);

    my $saleID = $myDBObj->sale_id;
    assert($saleID);

    # !!! Might want to put a few more sanity checks into this...
    #

    my $sale = Raptor::DB::Item::Sale->Lookup( sale_id => $saleID );
    $sale->delete();

    $myDBObj->sale_id(0);
    $myDBObj->save();
}

###
1;    #
###

