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

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

use lib '/app/tools/rps/lib';
use RPS::DB::Item::Master;
use RPS::DB::Item::Artist;
use RPS::DB::Item::Track;
use RPS::Song::Song;

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

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

    return $self;
}

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

    my $dbItem = RPS::DB::Item::Master->Lookup( master_id => $masterID );
    $self->_propertiesFromDBItem( $hrProperties, $dbItem );
}

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

    $hrProperties->{master_id}     = $dbItem->master_id;
    $hrProperties->{song_id}       = $dbItem->song_id;
    $hrProperties->{title}         = $dbItem->title;
    $hrProperties->{isrc}          = $dbItem->isrc;
    $hrProperties->{duration}      = $dbItem->duration;
    $hrProperties->{date_recorded} = $dbItem->date_recorded;
    $hrProperties->{date_created}  = $dbItem->date_created;
    $hrProperties->{date_modified} = $dbItem->date_modified;
    $hrProperties->{created_by}    = $dbItem->created_by;
    $hrProperties->{modified_by}   = $dbItem->modified_by;
    $hrProperties->{artist_id}     = $dbItem->artist_id;
}

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

    $self->{MasterID} = Common::FormObject::Scalar->new( value => $props->{master_id} );
    $self->{SongID}   = Common::FormObject::Scalar->new( value => $props->{song_id} );
    $self->{Title} = Common::FormObject::Scalar::String->new( value => $props->{title}, required  => 1 );
    $self->{ISRC}  = Common::FormObject::Scalar::String->new( value => $props->{isrc},  maxlength => 20 );
    $self->{Duration} = Common::FormObject::Scalar->new( value => Common::FormObject::_secondsToMMSS( $props->{duration} ) );
    $self->{DateRecorded} = Common::FormObject::Scalar::Date->new( value => $props->{date_recorded} );

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

    # We need to fetch the artist name, given the artist id.
    #
    my $artistName;
    if ( $props->{artist_id} ) {
        my $artistDBItem = RPS::DB::Item::Artist->Lookup( artist_id => $props->{artist_id} );
        $artistName = $artistDBItem->name if ($artistDBItem);
    }
    $self->{ArtistName} = Common::FormObject::Scalar::String->new( value => $artistName, required => 1 );
    $self->{ArtistID} = Common::FormObject::Scalar->new( value => $props->{artist_id} );

    # we need to determine if this master is linked to more
    # than one track, if so it will not be editable on the album page
    #
    my $linkedTracks = 0;
    if ( $props->{master_id} ) {
        my $tracks = RPS::DB::Item::Track->GetTracksByMasterID( $props->{master_id} );
        $linkedTracks = ( defined $tracks ) ? $tracks->size : 0;
    }
    $self->{LinkedTracks} = Common::FormObject::Scalar->new( value => $linkedTracks, readOnly => 1 );
}

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

    # subclasses
    #
    if ( $self->loadSubs() ) {
        if ( defined( $props->{song_id} ) && $props->{song_id} > 0 ) {
            $self->{Song} = RPS::Song::Song->new( songID => $props->{song_id} );
        } else {
            $self->{Song} = RPS::Song::Song->new();
        }
    }
}

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

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

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

    # Duration has a required format
    #
    if ( $self->Duration() !~ /^(\d{1,3})?\:\d?\d$/ ) {
        $self->{Duration}->setError(Common::FormObject::kErrFieldInvalid);
        $valid = 0;
    }

    if ( !$self->_validateMetadata(@args) ) {
        $valid = 0;
    }

    return $valid;
}

sub _validateMetadata {
    my $self = shift;
    my %args = @_ if ( @_ % 2 == 0 );

    my $validator = $args{metadataValidator};

    my $currentData = RPS::DB::Item::Master->Lookup( master_id => $self->MasterID )
      if ( $self->MasterID );

    my %scalar_rule_map = (
        ISRC => {
            legacy   => "isrc",
            validate => "isrc"
        },
        Title => {
            legacy   => "title",
            validate => "track-title"
        },
    );

    unless ($validator) {
        Common::Log::Debug( "No validator passed to " . ref($self) . "::_validateMetadata, skipping validation!!!!!" );
        use Common::Assert;
        return 1;
    }

    my $valid = $self->SUPER::_validateMetadata(
        fieldMap          => \%scalar_rule_map,
        currentData       => $currentData,
        metadataValidator => $validator
    );

    my $song_valid = 1;
    $song_valid = $self->{Song}->_validateMetadata(
        fieldMap          => \%scalar_rule_map,
        currentData       => $currentData,
        metadataValidator => $validator
    ) if ( $self->{Song} );

    return $valid && $song_valid;
}

sub isEmpty {
    my $self = shift @_;

    return 0;
}

sub save {
    my $self = shift @_;

    # -------------------------------
    # Handle the Master artist here
    # -------------------------------

    # Translate artist name to artist id, creating the artist if necessary.
    #
    my $artistObj;
    $artistObj = RPS::DB::Item::Artist->Lookup( name => $self->ArtistName() );
    if ( !defined $artistObj ) {
        $artistObj = RPS::DB::Item::Artist->Create( name => $self->ArtistName() );
        $artistObj->save();
    }

    # -------------------------------
    # Handle the Song
    # -------------------------------
    $self->{Song}->save();
    my $songID = $self->{Song}->SongID();

    # -------------------------------
    # Save myself (Master)
    # -------------------------------
    #
    my $masterDBObj;
    if ( $self->MasterID() ) {
        $masterDBObj = RPS::DB::Item::Master->Lookup( master_id => $self->MasterID() );
    } else {
        $masterDBObj = RPS::DB::Item::Master->Create();
    }

    $masterDBObj->title( $self->Title() );
    $masterDBObj->isrc( $self->ISRC() );
    $masterDBObj->duration( Common::FormObject::_MMSSToSeconds( $self->Duration() ) );
    $masterDBObj->date_recorded( $self->DateRecorded() );

    # foreign keys
    #
    $masterDBObj->artist_id( $artistObj->artist_id );
    $masterDBObj->song_id($songID);

    $masterDBObj->save();

    # reload object
    #
    $self->_init( _dbItem => $masterDBObj );
}

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

    # Is this Master used on more than one track?
    # if yes, then skip, else delete the Master
    #
    if ( $self->LinkedTracks() == 1 ) {
        my $dbItem = RPS::DB::Item::Master->Lookup( master_id => $self->MasterID() );
        $dbItem->delete();

        # delete the Song
        #
        $self->{Song}->delete();
    }

    return 1;
}

1;
