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

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';





# 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) = @_;

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

		# we can figure this out based on the ProductList and TypeList xml
		#$self->{ProductTypes} = RPS::DB::Item::Album->GetProductTypesAsString( $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.
			#
			my $ccompItem = RPS::ControlledComposition::ControlledComposition->new(contractID => $albumContractItem->artist_contract_id, readOnly => 1);
			$self->{ControlledComposition} = $ccompItem;

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

			$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 (%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;
