#---------------------------------------------------------------
# ____                   _ _         ____  _
#|  _ \ ___  _   _  __ _| | |_ _   _/ ___|| |__   __ _ _ __ ___
#| |_) / _ \| | | |/ _` | | __| | | \___ \| '_ \ / _` | '__/ _ \
#|  _ < (_) | |_| | (_| | | |_| |_| |___) | | | | (_| | | |  __/
#|_| \_\___/ \__, |\__,_|_|\__|\__, |____/|_| |_|\__,_|_|  \___|
#            |___/             |___/
#
# Copyright (C) 2010 RoyaltyShare, Inc.   All Rights Reserved
#---------------------------------------------------------------
package RPS::Import::Universal::v19;

use strict;

use Date::Calc qw(Days_in_Month Decode_Month);

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

use lib '/app/tools/rps/lib';
use RPS::Import::ServiceMap;

use base 'RPS::Import::MapFaceBase';
use base 'RPS::Import::Importer';

sub _fieldMap {
    my $self      = shift;
    my $version   = $self->version;
    my %field_map = (
        19 => {
            dateBegin   => 'R',
            serviceID   => 'D',
            productType => 'F',
            labelName   => 'A',
            upc         => 'I',
            albumName   => 'H',
            isrc        => 'N',
            trackName   => 'K',
            units       => 'Q',
            price       => 'R',
        },
        22 => {
            dateBegin   => 'N',
            serviceID   => 'D',
            productType => 'F',
            labelName   => 'A',
            upc         => 'I',
            albumName   => 'H',
            isrc        => 'M',
            trackName   => 'K',
            units       => 'O',
            price       => 'N',
        },
        25 => {
            dateBegin   => 'Q',
            serviceID   => 'D',
            productType => 'F',
            labelName   => 'A',
            upc         => 'I',
            albumName   => 'H',
            isrc        => 'N',
            trackName   => 'K',
            units       => 'R',
            price       => 'Q',
        },
        26 => {
            dateBegin   => 'O',
            serviceID   => 'D',
            productType => 'F',
            labelName   => 'A',
            upc         => 'I',
            albumName   => 'H',
            isrc        => 'N',
            trackName   => 'K',
            units       => 'P',
            price       => 'O',
        },
        27 => {
            dateBegin   => 'O',
            serviceID   => 'D',
            productType => 'F',
            labelName   => 'A',
            upc         => 'J',
            albumName   => 'I',
            isrc        => 'N',
            trackName   => 'L',
            units       => 'P',
            price       => 'O',
        },
        38 => {
            labelName   => 'A',
            serviceID   => 'D',
            dateBegin   => 'N3',
            productType => 'F',
            upc         => 'I',
            albumName   => 'H',
            isrc        => 'M',
            trackName   => 'K',
            units       => 'O',
            price       => 'N',
        },
        45 => {
            labelName   => 'B',
            serviceID   => 'D',
            dateBegin   => 'N',
            productType => 'F',
            upc         => 'I',
            albumName   => 'H',
            isrc        => 'M',
            trackName   => 'K',
            units       => 'O',
            price       => 'N',
        },
        50 => {
            labelName   => 'B',
            serviceID   => 'D',
            dateBegin   => 'O',
            productType => 'F',
            upc         => 'I',
            albumName   => 'H',
            isrc        => 'N',
            trackName   => 'K',
            units       => 'P',
            price       => 'O',
        },
        57 => {
            labelName   => 'B',
            serviceID   => 'D',
            dateBegin   => 'N',
            productType => 'F',
            upc         => 'I',
            albumName   => 'H',
            isrc        => 'M',
            trackName   => 'K',
            units       => 'O',
            price       => 'N',
        },
        58 => {
            labelName   => 'B',
            serviceID   => 'D',
            dateBegin   => 'O',
            productType => 'F',
            upc         => 'I',
            albumName   => 'H',
            isrc        => 'N',
            trackName   => 'K',
            units       => 'P',
            price       => 'O',
        },
        61 => {
            labelName   => 'A',
            serviceID   => 'D',
            dateBegin   => 'N',
            productType => 'F',
            upc         => 'I',
            albumName   => 'H',
            isrc        => 'M',
            trackName   => 'K',
            units       => 'O',
            price       => 'N',
        },
    );
    return $field_map{$version};
}

sub _unverifiedFieldMap {
    my $self      = shift;
    my $version   = $self->version;
    my %field_map = (
        19 => {
            albumArtist => 'G',
            trackArtist => 'J',
            salesType   => 'C',
        },
        22 => {
            albumArtist => 'G',
            trackArtist => 'J',
            salesType   => 'C',
        },
        25 => {
            albumArtist => 'G',
            trackArtist => 'J',
            salesType   => 'C',
        },
        26 => {
            albumArtist => 'G',
            trackArtist => 'J',
            salesType   => 'C',
        },
        27 => {
            albumArtist => 'H',
            trackArtist => 'K',
            salesType   => 'C',
        },
        38 => {
            albumArtist => 'G',
            trackArtist => 'J',
            salesType   => 'C',
        },
        45 => {
            albumArtist => 'G',
            trackArtist => 'J',
            salesType   => 'C',
        },
        50 => {
            albumArtist => 'G',
            trackArtist => 'J',
            salesType   => 'C',    # Sales channel
        },
        57 => {
            albumArtist => 'G',
            trackArtist => 'J',
            salesType   => 'C',    # Sales channel
        },
        58 => {
            albumArtist => 'G',
            trackArtist => 'J',
            salesType   => 'C',    # Sales channel
        },
        61 => {
            albumArtist => 'G',
            trackArtist => 'J',
            salesType   => 'C',    # Sales channel
        },
    );
    return $field_map{$version};
}

sub _headerIdentifier { ( upc => qr/UP(C|S)/ ) }

sub currencyCode { 'USD' }

sub countryCode {
    my $self = shift;

    return 'US' if ( $self->_version != 57 );

    # version 57 uses the filename to determine country
    #
    if ( !exists $self->{_countryCode} ) {
        if ( $self->filename =~ /[\s_]US[\s_]/i ) {
            $self->{_countryCode} = 'US';
        } elsif ( $self->filename =~ /[\s_]CA[\s_]/i ) {
            $self->{_countryCode} = 'CA';
        } else {
            $self->fail( "Unable to determine country code from " . $self->filename );
        }
    }
    return $self->{_countryCode};
}

my %gFormatMediaMap = (
    'ad supported streams' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'broadcast linear programming' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'broadcast vod' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'conditional mastertone' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'ephemeral plays' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'fixed plays' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'kiosk' => {
        formatType => RPS::File::Sale::FORMAT_JUKEBOX,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'mobile audio streams' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'mobile images' => {
        formatType => 'ERROR',
        mediaType  => '',
    },
    'ota permanent downloads' => {
        formatType => RPS::File::Sale::FORMAT_DOWNLOAD,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'permanent downloads' => {
        formatType => RPS::File::Sale::FORMAT_DOWNLOAD,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'portable sub client plays' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'portable sub device plays' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'portable sub programmed plays' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'portable sub streams' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'portable sub video dvc plays' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'programmed streaming' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'programmed streaming (non-royalty bearing)' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'programmed streaming-capped (non-royalty bearing)' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'programmed video streaming' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'ringbacks' => {
        formatType => RPS::File::Sale::FORMAT_RINGTONE,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'standard mobile ringsounds' => {
        formatType => RPS::File::Sale::FORMAT_RINGTONE,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'streams' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'subscription mastertones' => {
        formatType => RPS::File::Sale::FORMAT_RINGTONE,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'subscription ota permanent downloads (audio)' => {
        formatType => RPS::File::Sale::FORMAT_DOWNLOAD,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'subscription programmed streaming' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'tethered/conditional downloads' => {
        formatType => RPS::File::Sale::FORMAT_TETHERED,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'user generated streams (umg audio / user video)' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeAudio,
    },
    'video downloads' => {
        formatType => RPS::File::Sale::FORMAT_DOWNLOAD,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'video fixed play' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'video streams' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
    'video streams (sponsorship)' => {
        formatType => RPS::File::Sale::FORMAT_STREAM,
        mediaType  => RPS::DB::Item::MediaType::kMediaTypeVideo,
    },
);

sub saleDates {
    my $self = shift;
    return ( $self->{_dateBegin}, $self->{_dateEnd} );
}

sub upc {
    my $self = shift;
    my $upc  = $self->_getByFieldName('upc');
    return Common::Util::normalize_upc($upc);
}

sub isrc {
    my $self = shift;
    my $isrc = $self->_getByFieldName('isrc');
    return ( !defined $self->productType || $self->productType eq RPS::File::Sale::TYPE_TRACK ) ? $isrc : undef;
}

sub trackName {
    my $self = shift;
    my $name = $self->_getByFieldName('trackName');
    return ( !defined $self->productType || $self->productType eq RPS::File::Sale::TYPE_TRACK ) ? $name : undef;
}

sub artistName {
    my $self = shift;
    my $name;
    my $trackArtist = $self->_getByFieldName('trackArtist');
    my $albumArtist = $self->_getByFieldName('albumArtist');

    if ( $self->productType eq RPS::File::Sale::TYPE_TRACK ) {
        $name = $trackArtist;
    } elsif ( $self->productType eq RPS::File::Sale::TYPE_ALBUM ) {
        $name = $albumArtist;
    }

    if ( !defined $self->productType ) {
        $name = ( defined $trackArtist ) ? $trackArtist : $albumArtist;
    }

    if ( $name && $name =~ /(\w*),\s*(\w*)/ )    # Lastname, Firstname
    {
        $name = $2 . ' ' . $1;                   # Firstname Lastname
    }
    return $name;
}

sub serviceID {
    my $self      = shift;
    my $service   = $self->_getByFieldName('serviceID');
    my $serviceID = $self->getServiceID( lc($service) ) || $RPS::Import::ServiceMap::SERVICE_ALIASES{ lc $service };
    return $serviceID if ($serviceID);

    return $self->handleError( "Unknown service: $service", RPS::DB::Item::SaleImportError::kErrorService );
}

sub productType {
    my $self = shift;
    my $type = $self->_getByFieldName('productType') || return;

    if ( $type =~ /^complete album$/i ) {
        return RPS::File::Sale::TYPE_ALBUM;
    } elsif ( $type =~ /^track$/i ) {
        return RPS::File::Sale::TYPE_TRACK;
    } else {
        return $self->handleError( "Unknown product type: $type", RPS::DB::Item::SaleImportError::kErrorProductType );
    }
}

sub _processHeader {
    my $self = shift;
    my %args = @_;

    $self->SUPER::_processHeader(@_);    # Let MapFace have first crack at the header ...

    my %months = (
        jan => 1,
        feb => 2,
        mar => 3,
        apr => 4,
        may => 5,
        jun => 6,
        jul => 7,
        aug => 8,
        sep => 9,
        oct => 10,
        nov => 11,
        dec => 12
    );

    my $dt = $self->_getByFieldName('dateBegin') || '';
    if ( $dt =~ /revenue umg \w{2,3} \d{2} \((\w{3,9})\s*(\d{2})\)?/i ) {

        # if it's the whole month name, we need to strip off the first 3 chars
        my $_month = lc( substr( $1, 0, 3 ) );
        my $year = $2;

        my $month = $months{$_month};
        $year += 2000;

        my $sdate = sprintf( "%04d-%02d-01", $year, $month );
        my $edate = sprintf( "%04d-%02d-%02d", $year, $month, Days_in_Month( $year, $month ) );

        $self->{_dateBegin} = $sdate;
        $self->{_dateEnd}   = $edate;
    }
}

sub formatType {
    my $self = shift;

    my $salesType = lc $self->_getByFieldName('salesType');

    my ( $formatID, $mediaType ) = $self->_getFormatMedia($salesType);

    if ($formatID) {
        return $formatID ne 'ERROR'
            ? $formatID
            : $self->handleError( "Unknown sales channel: $salesType", RPS::DB::Item::SaleImportError::kErrorNonqualifying );
    }

    return $self->handleError( "Unknown sales channel: $salesType", RPS::DB::Item::SaleImportError::kErrorFormatType );
}

sub mediaType {
    my $self = shift;

    my $salesType = lc $self->_getByFieldName('salesType');

    my ( $formatID, $mediaType ) = $self->_getFormatMedia($salesType);

    if ($mediaType) {
        return $mediaType;
    } else {
        return $self->handleError( "Unknown sales channel: $salesType", RPS::DB::Item::SaleImportError::kErrorMediaType );
    }
}

sub _getFormatMedia {
    my ( $self, $salesType ) = @_;

    my $formatID;
    my $mediaType;
    if ( exists $gFormatMediaMap{$salesType} ) {
        $formatID  = $gFormatMediaMap{$salesType}->{formatType};
        $mediaType = $gFormatMediaMap{$salesType}->{mediaType};
    }

    return ( $formatID, $mediaType );
}

sub units {
    my $self  = shift;
    my $units = $self->SUPER::units();
    my $price = $self->SUPER::price();

    # The 'sign' of the units is driven by the price.
    # If the price is negative, we'll store negative units,
    # regardless of whether the units were positive or negative
    # in the sale file.  Accordingly, the price is always
    # positive.  This ensures that returns are recorded correctly.
    #
    if ( defined($price) && $price != 0 ) {
        return $price < 0 ? abs($units) * -1 : abs($units);
    } else {
        return $units;
    }
}

sub unitPrice {
    my $self = shift;
    return ( 0 == $self->price ) ? 0 : $self->SUPER::unitPrice();
}

sub _processSheet {
    my $self     = shift;
    my $sheet    = shift;
    my $sheetnum = shift;

    # trim sheetname
    $self->{sheetname} =~ s/^\s+|\s+$//g;

    if (
           $self->{sheetname} =~ /^Digital(?: Sales)?$/i
        || $self->{sheetname} =~ /^EL7_Sales_\d{4}\d{2}$/i
        || ( $self->{sheetname} =~ /^Sheet1$/i && $self->_version =~ /^(?:26|28|45)$/ )
    ) {
        return $self->SUPER::_processSheet( $sheet, $sheetnum );
    }
}

sub _isValidSaleRecord {
    my $self = shift;

    # Assume that if the label, service and config columns are blank, then this
    # is a line we want to skip.
    #
    my $labelName   = $self->_getByFieldName('labelName');
    my $serviceID   = $self->_getByFieldName('serviceID');
    my $productType = $self->_getByFieldName('productType');

    return 0 if ( '' eq $labelName && '' eq $serviceID && '' eq $productType );

    return ( defined( $self->units ) && ( $self->trackName || $self->albumName ) );
}

#####    MapFace    #####
#

sub _mapFaceCompatibleVersions {
    return ( 19, 22, 25, 26, 27, 38, 45, 50, 57, 58, 67 );
}

sub _mapFaceServiceID {
    return ('serviceID');
}

sub _mapFaceCountryCode {
    return ('countryCode');
}

sub _mapFaceProductType {
    return ('productType');
}

sub _mapFaceFormatType {
    return ('salesType');
}

sub _mapFaceMediaType {
    return ('salesType');
}

###
1;    # Play nicely.
###
