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

use strict;
#use warnings;

use Data::Dumper;


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

use lib '/app/tools/rps/lib';
use RPS::DB::Item::Product;
use RPS::DB::Item::Album;
use RPS::DB::Item::Genre;
use RPS::DB::Item::ProductTrack;
use RPS::DB::Item::Track;
use RPS::DB::Item::Artist;
use RPS::DB::Item::Master;
use RPS::DB::Item::Song;
use RPS::DB::Item::Label;
use RPS::DB::Item::ProductDigital;
use RPS::DB::Item::ServicePriceTier;
use RPS::Catalog::TrackAdditionalArtistHash;
use RPS::Catalog::AlbumAdditionalArtistHash;

use lib '/app/tools/distribution/lib';
use Distribution::DB::Item::DistributionJob;
use Distribution::DB::Item::ProductDistribution;
use Distribution::Job::Parameters;
use Distribution::DB::Item::ProductServiceID;
use Distribution::DB::Item::ProductTrackServiceID;

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

sub CreateDistributionParameters
{
    my ($distProcessID) = @_;
    assert($distProcessID);

    # !!! Not sure this is the correct ID...
    # !!! Not even sure if this is really the interface we'll need.
    # !!! We will need a 'job' class, perhaps that can abstract away everything?
    #

    # This is just a quick sanity check.
    #
    my $jobData = Distribution::DB::Item::DistributionProcess->Lookup(distribution_process_id => $distProcessID);
    die "ERROR - distribution job id $distProcessID does not exist" unless $jobData;


    # So, there should just be _1_ service id.  I'm going to keep track of this, and
    # freak out if it changes...
    #
    my $serviceID;

    my @albums;
    # So, we're going to iterate over all the 'product_distribution' records with that dist_job_id.
    #
    my $productDistCollection = Distribution::DB::Item::ProductDistribution->GetAllByDistributionProcessID($distProcessID);
    while (my $productDist = $productDistCollection->next())
    {
        if (! defined $serviceID)
        {
            $serviceID = $productDist->service_id;
        }
        elsif ($productDist->service_id != $serviceID)
        {
            die "ERROR - expected service_id $serviceID in this product_distribution record: " . Dumper($productDist);
        }

        my $productID = $productDist->product_id;
        my $product = RPS::DB::Item::Product->Lookup(product_id => $productID);
        assert($product->product_type_id == RPS::DB::Item::Product::kProductTypeDigital);

        #
        # Quick hack to add apple vendor id.  This should be removed when more services
        # start using custom IDs
        #
        my $appleAlbumID;
        if( $serviceID == 11 ) {
            my $productServiceID = Distribution::DB::Item::ProductServiceID->Lookup( service_id => $serviceID, product_id => $product->product_id );
            $appleAlbumID = $productServiceID->code() if( $productServiceID );
        }


        # Build the territory list
        #
        my $productDigital = RPS::DB::Item::ProductDigital->Lookup(product_id => $productID);
        assert($productDigital);
        my @territoryList;
        my $territories = $productDigital->territories_list;
        if ($territories)
        {
            @territoryList = split(' ', $territories);
        }
        my $territoryAllowedFlag = (RPS::DB::Item::ProductDigital::kTerritoriesFlagAllow eq $productDigital->territories_flag ? 1 : 0);


        my $albumID = $product->asset_id;
        my $album = RPS::DB::Item::Album->Lookup(album_id => $albumID);

        my $label = RPS::DB::Item::Label->Lookup(label_id => $album->label_id);

        my $albumExplicitFlag = RPS::DB::Item::Album->GetAlbumParentalAdvisory($albumID);
        if ('E' eq $albumExplicitFlag)
        {
            $albumExplicitFlag = 'explicit';
        }
        elsif ('C' eq $albumExplicitFlag)
        {
            $albumExplicitFlag = 'clean';
        }
        else
        {
            $albumExplicitFlag = 'none';
        }

        # Let's derive the correct genre - we'll force all the tracks to be this genre too.
        #
        my $isComposerRequired;
        my @genreNames;
        if ($album->genre_primary_id)
        {
            my $genre = RPS::DB::Item::Genre->Lookup(genre_id => $album->genre_primary_id);

            # !!! Not all albums have this yet.
            #
            if ($genre)
            {
                push @genreNames, $genre->genre_name;

                $isComposerRequired = RPS::DB::Item::Genre::isComposerRequired(genre_id => $album->genre_primary_id);
            }
        }

        my @genreNames_secondary;
        if ($album->genre_secondary_id)
        {
            my $genre = RPS::DB::Item::Genre->Lookup(genre_id => $album->genre_secondary_id);

            # !!! Not all albums have this yet.
            #
            if ($genre)
            {
                push @genreNames_secondary, $genre->genre_name;

                if (RPS::DB::Item::Genre::isComposerRequired(genre_id => $album->genre_secondary_id)) {
                    $isComposerRequired = 1;
                }
            }
        }

        # Need the 'volume' data, from the product_track table.
        #
        # !!! Going to add a new accessor to include some order_by args
        my $productTracks = RPS::DB::Item::ProductTrack->GetTracksByProductID($productID, "disc_number, disc_track");


        my @volumes;

        # So, we'll iterate over the product_tracks, and assemble everything we need to know.
        #
        while (my $productTrack = $productTracks->next())
        {
            my $trackID = $productTrack->track_id;

            # If this is a bonus track, make sure it belongs at this service.
            #
            if ($productTrack->is_bonus_track)
            {
                my $bonusTrackData = RPS::DB::Item::BonusTrack->Lookup(product_id => $productID, track_id => $trackID, service_id => $serviceID);
                if (! $bonusTrackData)
                {
                    next;
                }
            }
            my $discNum = $productTrack->disc_number;
            my $volumeData = $volumes[$discNum - 1];
            if (! defined $volumeData)
            {
                # This is a new volume entry.
                # Need id, total length, and the list of tracks.
                #
                $volumeData = {};
                $volumeData->{id} = $discNum;
                $volumeData->{sequence} = $discNum;

                # We'll calculate this later.
                #
                $volumeData->{'total-length'} = 0;

                $volumeData->{track} = [];

                push @volumes, $volumeData;
            }


            # Fill in the track info.
            # We'll need track and master data.
            #
            my $tracks = $volumeData->{track};
            my $trackData = {};

            my $track = RPS::DB::Item::Track->Lookup(track_id => $productTrack->track_id);
            my $master = RPS::DB::Item::Master->Lookup(master_id => $track->master_id);
            my $song = RPS::DB::Item::Song->Lookup(song_id => $master->song_id);
            my $trackArtist = RPS::DB::Item::Artist->Lookup(artist_id => $track->artist_id);

            my $composerName;
            if ($song->composer_id)
            {
                my $composer = RPS::DB::Item::Composer->Lookup(composer_id => $song->composer_id);
                if ($composer)
                {
                    $composerName = $composer->name;
                }
            }

            my $trackExplicitFlag = $track->parental_advisory;
            if ('E' eq $trackExplicitFlag)
            {
                $trackExplicitFlag = 'explicit';
            }
            elsif ('C' eq $trackExplicitFlag)
            {
                $trackExplicitFlag = 'clean';
            }
            else
            {
                $trackExplicitFlag = 'none';
            }


            #
            # Quick hack to add apple vendor id.  This should be removed when more services
            # start using custom IDs
            #
            my $appleTrackID;
            if( $serviceID == 11 ) {
                my $productTrackServiceID = Distribution::DB::Item::ProductTrackServiceID->Lookup( service_id => $serviceID, product_track_id => $productTrack->product_track_id );
                $appleTrackID = $productTrackServiceID->code() if( $productTrackServiceID );
            }

            $trackData->{'is-explicit'} = $trackExplicitFlag;
            $trackData->{'sell-unbundled'} = 'yes';
            $trackData->{'title'} = $track->title;
            $trackData->{'isrc'} = $master->isrc;
            $trackData->{'sequence'} = $productTrack->disc_track;
            $trackData->{'length'} = $master->duration;  # We'll translate this into stupid mode later.

            $trackData->{'genre'} = \@genreNames;

            $trackData->{'label'} = $label->label_name;
            $trackData->{'cline'} = $album->c_line;
            $trackData->{'pline'} = $album->p_line;
            $trackData->{'display-artist'} = $trackArtist->name;
            $trackData->{'composer'} = $composerName;
            $trackData->{'apple-track-id'} = $appleTrackID;
            $trackData->{'album-only'} = $productTrack->album_only;

            $trackData->{'additional-artists'} = getAdditionalArtists( track_id => $trackID, service_id => $serviceID );

            # Need to fetch the media_file_id that corresponds to this track's audio.
            #
            my $productTrackFile = MediaServe::DB::Item::ProductTrackFile->Lookup
            (
                product_track_id => $productTrack->product_track_id,
                file_type => MediaServe::DB::Item::ProductTrackFile::kFileTypeOriginal,
            );

            my $mediaFileID = $productTrackFile->media_file_id;
            my $audioPath = MediaServe::Server::GetAudioPath(mediaFileID => $mediaFileID, clientID => Common::RSApp::GetClientID(), type => 'linux' );
            my $audioWinPath = MediaServe::Server::GetAudioPath(mediaFileID => $mediaFileID, clientID => Common::RSApp::GetClientID(), type => 'windows' );
            $trackData->{'audio-path-linux'} = $audioPath;
            $trackData->{'audio-path-windows'} = $audioWinPath;

            push @{$tracks}, $trackData;
        }

        my $price_tier = RPS::DB::Item::ServicePriceTier->LookupByProduct( service_id => $serviceID, product_id => $product->product_id );
        my $default_price_tier = RPS::DB::Item::ServicePriceTier->Lookup( service_id => $serviceID, default_tier => 1 );

        my $albumData = {};
        $albumData->{volume} = \@volumes;
        $albumData->{'sell-bundled'} = 'yes';
        $albumData->{'is-explicit'} = $albumExplicitFlag;
        $albumData->{upc} = $product->upc_ean;
        $albumData->{title} = $album->title;
        $albumData->{'catalog-number'} = $album->catalog_number;
        $albumData->{'label'} = $label->label_name;
        $albumData->{'release-date'} = $product->release_date;
        $albumData->{'wholesale-price-tier'} = $price_tier->tier_code if( $price_tier );
        $albumData->{'default-price-tier'}   = $default_price_tier->tier_code if( $default_price_tier );
        $albumData->{'cline'} = $album->c_line;
        $albumData->{'pline'} = $album->p_line;
        $albumData->{'genre'} = \@genreNames;
        $albumData->{'genre-id'} = $album->genre_primary_id;
        $albumData->{'genre-secondary'} = \@genreNames_secondary;
        $albumData->{'genre-secondary-id'} = $album->genre_secondary_id;
        $albumData->{'apple-album-id'} = $appleAlbumID;

        $albumData->{'is-classical'} = $isComposerRequired;
        $albumData->{'product-distribution-id'} = $productDist->product_distribution_id;

        my $albumArtist = RPS::DB::Item::Artist->Lookup(artist_id => $album->artist_id);
        $albumData->{'display-artist'} = $albumArtist->name;

        $albumData->{'additional-artists'} = getAdditionalArtists( album_id => $albumID, service_id => $serviceID );

        # Get the image path
        #
        my $imageFile = MediaServe::DB::Item::AlbumFile->Lookup(album_id => $album->album_id, file_type => MediaServe::DB::Item::AlbumFile::kFileTypeDistribution);
        assert( $imageFile, "Failed to find album image. Album ID: " . $album->album_id );

        my $mediaFile = MediaServe::DB::Item::MediaFile->Lookup(media_file_id => $imageFile->media_file_id);
        my $imagePath = MediaServe::Server::GetImagePath(mediaFileID => $imageFile->media_file_id, clientID => Common::RSApp::GetClientID(), type => 'linux' );
        my $imageWinPath = MediaServe::Server::GetImagePath(mediaFileID => $imageFile->media_file_id, clientID => Common::RSApp::GetClientID(), type => 'windows' );
        $albumData->{'image-file'} = $mediaFile->filename;
        $albumData->{'image-path-linux'} = $imagePath;
        $albumData->{'image-path-windows'} = $imageWinPath;

        # Build the territories XML
        #
        if (scalar @territoryList)
        {
            if ($territoryAllowedFlag)
            {
                $albumData->{'territories'}{'allowed'} = \@territoryList;
            }
            else
            {
                $albumData->{'territories'}{'denied'} = \@territoryList;
            }
        }
        else
        {
            $albumData->{'territories'} = undef;
        }

        push @albums, $albumData;
    }


    my %paramHash;
    $paramHash{album} = \@albums;

    # Now, we instantiate the XML object.
    #
    my $paramObj = Distribution::Job::Parameters->new(hash => \%paramHash);
    return $paramObj;
}

sub getAdditionalArtists {
    my %args = @_;
    my $hash;
    my $artistHash;
    my @result;

    my $serviceID = $args{service_id};

    assert( $serviceID );

    if( $args{album_id} ) {
        $artistHash = new RPS::Catalog::AlbumAdditionalArtistHash( albumID => $args{album_id}, serviceID => $serviceID );
    } elsif( $args{track_id} ) {
        $artistHash = new RPS::Catalog::TrackAdditionalArtistHash( trackID => $args{track_id}, serviceID => $serviceID );
    }

    return unless( $artistHash );

    foreach my $key ( @{$artistHash->getKeys()} ) {
        my $artist = $artistHash->getHash()->{$key};
 		my $dbItem = RPS::DB::Item::ArtistRole->LookupWithMap( service_role => $artist->{Role}->Role(), service_id => $serviceID );

        $hash = {};
        $hash->{'artist-id'} = $artist->ArtistID;
        $hash->{'display-artist'} = $artist->Name;
        $hash->{'role'}->{'artist-role-id'} = $artist->{Role}->ArtistRoleID();
        $hash->{'role'}->{'name'} = $artist->{Role}->Role();
	    $hash->{'role'}->{'map'} = $dbItem->{service_role} if( $dbItem );

        push( @result, $hash );
    }

    return @result ? \@result : undef;
}


1;
