#------------------------------------------------------------
# Copyright (C) 2006 RoyaltyShare, Inc.   All Rights Reserved
#------------------------------------------------------------
package RPS::Catalog::Album;
use strict;
use warnings;
use Data::Dumper;

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

use lib '/app/tools/mediaserve/lib';
use MediaServe::Server;
use MediaServe::DB::Item::AlbumFile;
use MediaServe::DB::Item::ProductTrackFile;

use lib '/app/tools/rps/lib';
use RPS::DB::Item::Album;
use RPS::DB::Item::Artist;
use RPS::DB::Item::AlbumContract;
use RPS::DB::Item::User;
use RPS::Track::TrackList;
use RPS::ArtistContract::ArtistContract;
use RPS::Product::ProductList;
use RPS::Catalog::DistributionCache;

use Common::FormObject;
use base 'RPS::Catalog::AlbumSimple';

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

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

    # Now add in the related items check
    #
    if ($props->{album_id}) {
        my $relatedAlbumItems = ( RPS::DB::Item::Album->HasAlbumSales($props->{album_id})     ||
                                  RPS::DB::Item::Album->HasTrackSales($props->{album_id})     ||
                                  RPS::DB::Item::Album->HasAlbumContracts($props->{album_id}) ||
                                  RPS::DB::Item::Album->HasTrackContracts($props->{album_id}) ||
                                  RPS::DB::Item::Album->HasUSLicenses($props->{album_id})     ||
                                  RPS::DB::Item::Album->HasCALicenses($props->{album_id})     ||
                                  RPS::DB::Item::Album->HasUKLicenses($props->{album_id}) ) ? 1 : 0;
        $self->{RelatedAlbumItems}    = Common::FormObject::Scalar->new( value => $relatedAlbumItems );
    }
}

# Overriding the inherited method.
# This class contains distinctly different classes than AlbumSimple...
# So we will _not_ be calling the inherited method.
#
sub _initSubs {
    my ( $self, $props, $page, $pageSize ) = @_;

    # subclasses
    if ( $self->loadSubs() ) {
        $self->{TrackList} = RPS::Track::TrackList->new(
            albumID => $props->{album_id},
            page => $page,
            pageSize => $pageSize,
            readOnly => 1
        );

        $self->{ProductList} = RPS::Product::ProductList->new( albumID => $props->{album_id} );

        # let's see if there's a controlled comp attached (via a contract) to this album
        my $albumContractItem = RPS::DB::Item::AlbumContract->GetCComp( $props->{album_id} ) if $props->{album_id};
        if ($albumContractItem) {
            # if there is then we need to add the ControlledComp to the xml
            # and calculate the "album pool". Album pool is a number based
            # on the terms of the ccomp, the issue date of the x_contract_x (<--strike that, use this -->) controlled comp
            # and the number and length of all the tracks in the album.
            $self->{ControlledComposition} = RPS::ControlledComposition::ControlledComposition->new(
                contractID => $albumContractItem->artist_contract_id,
                readOnly => 1
            );

            my $albumPool = $self->_calcAlbumPool(
                trackList => $self->{TrackList}->getTracks(),
                ccomp => $self->{ControlledComposition}
            );

            $self->{AlbumPool} = Common::FormObject::Scalar::Decimal->new(
                value => $albumPool,
                precision => "1.4",
                readOnly => 1
            );
        }
    }
}

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

    Common::Log::Debug("#################### Start Validation ##############################");
    $self->{IsDistributionReady} = new Common::FormObject::Scalar::Integer( value => 0 );

    my $distCache = new RPS::Catalog::DistributionCache();
    my $status = $distCache->getAlbumStatus( album => $self );

    assert($status);
    my $valid =
         $status->metadata_valid
      && $status->audio_valid
      && $status->image_valid ? 1 : 0;

    Common::Log::Debug("VALID: $valid");

    $self->{IsDistributionReady} = new Common::FormObject::Scalar::Integer( value => $valid )
      if ($valid);
    Common::Log::Debug("#################### End Validation ##############################");

    return $valid;
}

sub validateMetadata {
    my ( $self, %args ) = @_;
    my $valid;
    my $vAlbum   = 1;
    my $vTrack   = 1;
    my $vProduct = 1;

    Common::Log::Debug("Validating Metadata");

    $self->{IsDistributionReady} = new Common::FormObject::Scalar()
      unless ( $self->{IsDistributionReady} );

    my %params = $self->{IsDistributionReady}->getXMLParams();
    my $error  = $params{emsg};

    my $harness =
        $args{harness}
      ? $args{harness}
      : new Metadata::Validate::Harness( failState => Validate::kStatusOK, ignoreCurrentData => 1 );

    my %validate_args = ( metadataValidator => $harness );

    $vAlbum = $self->SUPER::_validateMetadata(%validate_args);

    $error .= "album metadata failed, " unless ($vAlbum);

    $vTrack = $self->{TrackList}->validate(%validate_args)
      if ( $self->{TrackList} );

    $error .= "track metadata failed, " unless ($vTrack);

    $vProduct = $self->{ProductList}->validateDigitalProduct(%validate_args)
      if ( $self->{ProductList} );

    $error .= "product metadata failed, " unless ($vProduct);

    $valid = $vAlbum && $vTrack && $vProduct ? 1 : undef;

    $self->{IsDistributionReady}->setErrorString($error)
      if ($error);

    Common::Log::Debug("Metadata validation result: $valid") if ($valid);

    return $valid;
}

sub validateAlbumAudio {
    my $self     = shift;
    my $album_id = $self->AlbumID;

    $self->{IsDistributionReady} = new Common::FormObject::Scalar()
      unless ( $self->{IsDistributionReady} );

    my %params = $self->{IsDistributionReady}->getXMLParams();
    my $error  = $params{emsg};

    Common::Log::Debug("Validating Album Audio");

    assert( $album_id, "Album ID Required" );

    my $collection = RPS::DB::Item::Album->SearchNoAudio( album_id => $album_id );

    if ( !$collection->hasNext() ) {
        Common::Log::Debug("Audio DB validation successful");
        return 1;
    } else {
        Common::Log::Debug("Audio DB validation failed");
        $error .= "album audio asset DB check failed, ";
        $self->{IsDistributionReady}->setErrorString($error);
        return;
    }

    return !$collection->hasNext();
}

sub validateAlbumImage {
    my $self     = shift;
    my $album_id = $self->AlbumID;

    $self->{IsDistributionReady} = new Common::FormObject::Scalar()
      unless ( $self->{IsDistributionReady} );

    my %params = $self->{IsDistributionReady}->getXMLParams();
    my $error  = $params{emsg};

    Common::Log::Debug("Validating Album Image");

    assert( $album_id, "Album ID Required" );

    my $collection = RPS::DB::Item::Album->SearchNoImage( album_id => $album_id );

    if ( !$collection->hasNext() ) {
        Common::Log::Debug("Image DB validation successful");
        return 1;
    } else {
        Common::Log::Debug("Image DB validation failed");
        $error .= "album image asset DB check failed, ";
        $self->{IsDistributionReady}->setErrorString($error);
        return;
    }
}

# Validate all asset files exist
sub validateAssets {
    my $self = shift;

    # No longer validating physical existance. WGF
    return 1;

    my $album_id = $self->AlbumID;

    $self->{IsDistributionReady} = new Common::FormObject::Scalar()
      unless ( $self->{IsDistributionReady} );

    my %params = $self->{IsDistributionReady}->getXMLParams();
    my $error  = $params{emsg};

    Common::Log::Debug("Validating Album Assets");

    assert( $album_id, "Album ID Required" );

    Common::Log::Debug("Image asset validation failed")
      if ( $self->validateImageAssets );

    Common::Log::Debug("Audio asset validation failed")
      if ( $self->validateAudioAssets );

    return $self->validateImageAssets && $self->validateAudioAssets;
}

sub validateImageAssets {
    my $self = shift;

    # No longer validating physical existance. WGF
    return 1;

    my $album_id  = $self->AlbumID;
    my $client_id = Common::RSApp::GetClientID();
    my $path;

    $self->{IsDistributionReady} = new Common::FormObject::Scalar()
      unless ( $self->{IsDistributionReady} );

    my %params = $self->{IsDistributionReady}->getXMLParams();
    my $error  = $params{emsg};

    assert( $album_id, "Album ID Required" );

    my $image_assets = MediaServe::DB::Item::AlbumFile->Search( album_id => $album_id );

    while ( $image_assets->hasNext ) {
        my $asset = $image_assets->next();
        ( undef, $path ) = MediaServe::Server::GetImagePath(
            clientID    => $client_id,
            mediaFileID => $asset->media_file_id
        );

        if ( !-f $path ) {
            Common::Log::Debug("  -- Missing file: $path");

            $error .= "image file doesn't exist, ";
            $self->{IsDistributionReady}->setErrorString($error);
            return undef;
        }
    }

    return 1;
}

sub validateAudioAssets {
    my $self = shift;

    # No longer validating physical existance. WGF
    return 1;

    my $album_id  = $self->AlbumID;
    my $client_id = Common::RSApp::GetClientID();
    my $path;

    $self->{IsDistributionReady} = new Common::FormObject::Scalar()
      unless ( $self->{IsDistributionReady} );

    my %params = $self->{IsDistributionReady}->getXMLParams();
    my $error  = $params{emsg};

    assert( $album_id, "Album ID Required" );

    my $audio_assets = MediaServe::DB::Item::ProductTrackFile->Search( album_id => $album_id );

    while ( $audio_assets->hasNext ) {
        my $asset = $audio_assets->next();
        ( undef, $path ) = MediaServe::Server::GetAudioPath(
            clientID    => $client_id,
            mediaFileID => $asset->media_file_id
        );
        if ( !-f $path ) {
            Common::Log::Debug("  -- Missing file: $path");

            $error .= "audio file doesn't exist, ";
            $self->{IsDistributionReady}->setErrorString($error);
            return undef;
        }
    }

    return MediaServe::DB::Item::ProductTrackFile::hasUnmatchedAudio( album_id => $album_id ) ? undef : 1;
}

# Album pool is a number based on the terms of the ccomp, the issue date of the contract
# and the number and length of all the tracks in the album.
#
sub _calcAlbumPool {
    my ($self, %args) = @_;
    my $trackList = $args{trackList};
    my $ccomp     = $args{ccomp};

    #my $dateIssued = $args{contractStartDate};
    my $lockDate = $ccomp->LockDate();

    my $albumPool = 0;

    require RPS::DB::Item::TrackLicense;
    require RPS::DB::Item::StatRate;

    if ( RPS::DB::Item::TrackLicense::kRateTypePenny == $ccomp->RateType ) {

        # album_pool = min(track_cap,number_of_tracks)*rate_percentage
        #
        my $trackCount = ( $ccomp->TrackCap < scalar @$trackList ) ? $ccomp->TrackCap : scalar @$trackList;
        $albumPool = $trackCount * $ccomp->PennyRate * ( $ccomp->RatePercentage / 100 );
    } else {
        my $statRate;

        # if rate_basis != sale_date or lockDate is '0000-00-00' use system_date to determine which stat rate period to use
        if ( RPS::DB::Item::TrackLicense::kRateBasisLock != $ccomp->RateBasis() ) {
            my $date = join( '-', Date::Calc::Today() );
            $statRate = RPS::DB::Item::StatRate->GetByDate( $date, 1 );
        }

        # if rate_basis == lock_date and lockDate is NOT '0000-00-00'
        elsif ( $lockDate && $lockDate ne '0000-00-00' ) {
            $statRate = RPS::DB::Item::StatRate->GetByDate( $lockDate, 1 );
        } else {

            # I don't really know what to do here.
            return $albumPool;
        }

        if ( RPS::DB::Item::TrackLicense::kRateTypeFull == $ccomp->RateType() ) {

            # use the shortest length tracks up to track cap and calculate rate for each
            # album_pool = sum(track_rates_use) * rate_percentage
            #
            my $trkCount  = 0;
            my $totalRate = 0;
            foreach my $trk ( sort { $a->{Master}->Duration() cmp $b->{Master}->Duration() } @$trackList ) {
                last if ( $trkCount == $ccomp->TrackCap() );

                # I could use the _MMSSToSeconds function, but all I really care
                # about is the minutes.
                my ( $min, $sec ) = split( ':', $trk->{Master}->Duration() );

                $totalRate += $statRate->rate;
                if ( $min > 5 ) {
                    $totalRate += ( $min % 5 ) * $statRate->minute_rate;
                }

                $trkCount++;
            }

            $albumPool = $totalRate * ( $ccomp->RatePercentage / 100 );
        } elsif ( RPS::DB::Item::TrackLicense::kRateTypeMinimum == $ccomp->RateType ) {

            # album_pool = min(track_cap,number_of_tracks)*base_rate*rate_percentage
            #
            my $trackCount = ( $ccomp->TrackCap() < scalar @$trackList ) ? $ccomp->TrackCap() : scalar @$trackList;
            $albumPool = $trackCount * $statRate->rate * ( $ccomp->RatePercentage / 100 );
        }
    }

    return $albumPool;
}

1;
