package RPS::Import::INGrooves2015;

use strict;

use Date::Calc qw(Days_in_Month Add_Delta_Days Decode_Month);
use Data::Dumper;

use lib '/app/tools/common/lib';
use Common::Country;
use Common::Util qw(normalize_upc normalize_isrc);

use lib '/app/tools/rps/lib';
use RPS::DB::Item::SaleImportError;
use RPS::File::Sale;
use RPS::Import::ServiceMap;
use RPS::Import::Importer;
use base 'RPS::Import::MapFaceBase';
use base 'RPS::Import::Importer';

sub _headerIdentifier { ( upc => 'UPC/EAN' ) }
    
sub _fieldMap {{
    my $self = shift;
    
    my %fieldMap =
    (
        22 => {
            labelName        => 'N',
            serviceID        => 'B',
            countryCode      => 'L',
            dateBegin        => 'A',
            productType      => 'O', # ASSET TYPE
            formatType       => 'P', # SALES DESCRIPTION
            mediaType        => 'Q', # SALES CATEGORY
            artistName       => 'C',
            serviceProductID => 'J', # CATALOG
            upc              => 'E',
            albumName        => 'D',
            isrc             => 'H',
            trackName        => 'F',
            units            => 'R',
            currencyCode     => 'T1',
            price            => 'T',
        },      
        23 => {
            labelName        => 'O',
            serviceID        => 'B',
            countryCode      => 'M',
            dateBegin        => 'C',
            productType      => 'P', # ASSET TYPE
            formatType       => 'Q', # SALES DESCRIPTION
            mediaType        => 'R', # SALES CATEGORY
            artistName       => 'D',
            serviceProductID => 'K', # CATALOG
            upc              => 'F',
            albumName        => 'E',
            isrc             => 'I',
            trackName        => 'G',
            units            => 'S',
            currencyCode     => 'U1',
            price            => 'U',
        },             
        25 => {
            labelName        => 'D',
            serviceID        => 'C',
            countryCode      => 'O',
            dateBegin        => 'A',
            productType      => 'P', # ASSET TYPE
            formatType       => 'Q', # SALES DESCRIPTION
            mediaType        => 'R', # SALES CLASSIFICATION (formerly SALES CATEGORY)
            artistName       => 'E',
            serviceProductID => 'H', # CATALOG
            upc              => 'G',
            albumName        => 'F',
            isrc             => 'K',
            trackName        => 'I',
            units            => 'S',
            currencyCode     => 'U1',
            price            => 'U',
        },
        26 => {
            labelName        => 'D',
            serviceID        => 'C',
            countryCode      => 'O',
            dateBegin        => 'A',
            productType      => 'P', # ASSET TYPE
            formatType       => 'Q', # SALES DESCRIPTION
            mediaType        => 'R', # SALES CLASSIFICATION (formerly SALES CATEGORY)
            artistName       => 'E',
            serviceProductID => 'H', # CATALOG
            upc              => 'G',
            albumName        => 'F',
            isrc             => 'K',
            trackName        => 'I',
            units            => 'S',
            currencyCode     => 'V1',
            price            => 'V',
        },
        27 => {
            labelName        => 'N',
            serviceID        => 'B',
            countryCode      => 'L',
            dateBegin        => 'A',
            productType      => 'O', # ASSET TYPE
            formatType       => 'P', # SALES DESCRIPTION
            mediaType        => 'Q', # SALES CLASSIFICATION (formerly SALES CATEGORY)
            artistName       => 'C',
            serviceProductID => 'J', # CATALOG
            upc              => 'E',
            albumName        => 'D',
            isrc             => 'H',
            trackName        => 'F',
            units            => 'R',
            currencyCode     => 'U1',
            price            => 'U',
        },
        28 => {
            labelName        => 'D',
            serviceID        => 'C',
            countryCode      => 'O',
            dateBegin        => 'A',
            productType      => 'P', # ASSET TYPE
            formatType       => 'Q', # SALES DESCRIPTION
            mediaType        => 'R', # SALES CLASSIFICATION (formerly SALES CATEGORY)
            artistName       => 'E',
            serviceProductID => 'H', # CATALOG
            upc              => 'G',
            albumName        => 'F',
            isrc             => 'K',
            trackName        => 'I',
            units            => 'S',
            currencyCode     => 'V',
            price            => 'V',
        },
    );        
    
    return $fieldMap{$self->_version()};
}}

sub _unverifiedFieldMap {{
    my $self = shift;
    
    my %fieldMap =
    (
        25 => {
            stmtCountryISO => 'N',
            altCurrencyCode => 'T1',
        },
        26 => {
            stmtCountryISO => 'N',
            altCurrencyCode => 'T1',
        },
        28 => {
            stmtCountryISO => 'N',
            altCurrencyCode => 'V1',
        },
    );
    return $fieldMap{$self->_version()};
}}

my %gProductFormatMediaTypeMappings =
(
    'album' => {
        'cma download (album)' => {
            'download' => {
                product_type    => RPS::File::Sale::TYPE_ALBUM,
                format_type     => RPS::File::Sale::FORMAT_DOWNLOAD,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },
        },  
        'download (album)' => {
            'download' => {
                product_type    => RPS::File::Sale::TYPE_ALBUM,
                format_type     => RPS::File::Sale::FORMAT_DOWNLOAD,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },
            'tethered download' => {
                product_type    => RPS::File::Sale::TYPE_ALBUM,
                format_type     => RPS::File::Sale::FORMAT_TETHERED,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },
        },
        'download (disc on demand)' => {
            'download' => {
                product_type    => RPS::File::Sale::TYPE_ALBUM,
                format_type     => RPS::File::Sale::FORMAT_DOWNLOAD,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },
        },  
        'download (rental)' => {
            'tethered download' => {
                product_type    => RPS::File::Sale::TYPE_ALBUM,
                format_type     => RPS::File::Sale::FORMAT_TETHERED,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },
        }, 
        'download (track)' => {
            'download' => {
                product_type    => RPS::File::Sale::TYPE_ALBUM,
                format_type     => RPS::File::Sale::FORMAT_DOWNLOAD,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },
        }, 
        'streaming' => {
            'interactive streaming' => {
                product_type    => RPS::File::Sale::TYPE_ALBUM,
                format_type     => RPS::File::Sale::FORMAT_STREAM,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },
        },                           
    },
    'album completion' => {
        'cma download (album)' => {
            'download' => {
                check_isrc      => 1,
                format_type     => RPS::File::Sale::FORMAT_DOWNLOAD,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },
        },
        'download (a/v)' => {
            'download' => {
                check_isrc      => 1,
                format_type     => RPS::File::Sale::FORMAT_DOWNLOAD,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },
        },
    },
    'ringtone' => {
        'ringtone' => {
            'mobile (ringtones/ringback)' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_RINGTONE,,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },
        },
        'ringtone (conditional)' => {
            'tethered download' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_TETHERED,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },
        },
    },
    'ringback' => {
        'ringback (conditional)' => {
            'tethered download' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_TETHERED,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },
        },
    },    
    'ringback' => {
        'ringback' => {
            'mobile (ringtones/ringback)' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_TETHERED,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },
        },
    },    
    'track' => {
        'cma return download (track)' => {
            'download' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_DOWNLOAD,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },
        },
        'download' => {
            'download' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_DOWNLOAD,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },
        },
        'download (disc on demand)' => {
            'download' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_DOWNLOAD,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },
        },
        'download (track conditional)' => {
            'tethered download' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_TETHERED,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },
        },           
        'download (track)' => {
            'download' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_DOWNLOAD,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },
        }, 
        'not provided' => {
            'interactive streaming' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_STREAM,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },
            'non-interactive streaming' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_STREAM,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },            
        },
        'ringback' => {
            'mobile (ringtones/ringback)' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_TETHERED,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },
        }, 
        'ringtone' => {
            'mobile (ringtones/ringback)' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_RINGTONE,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },
        }, 
        'stream (ad-supported)' => {
            'interactive streaming' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_STREAM,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },
        },
        'streaming' => {
            'download' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_STREAM,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },   
            'interactive streaming' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_STREAM,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },
            'non-interactive streaming' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_STREAM,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            }, 
            'tethered download' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_TETHERED,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },  
        },
        'streaming (cloud)' => {
            'interactive streaming' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_STREAM,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },    
        },  
        'streaming (free trial)' => {
            'interactive streaming' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_STREAM,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },
        },
        'streaming (locker)' => {
            'interactive streaming' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_STREAM,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },
        },
        'streaming (radio)' => {
            'non-interactive streaming' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_STREAM,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },    
        },                                                                    
        'streaming (subscription)' => {
            'interactive streaming' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_STREAM,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeAudio,
            },
        },
    },
    'video' => {
        'download' => {
            'download' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_DOWNLOAD,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeVideo,
            },
        },
        'download (video disc on demand)' => {
            'download' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_DOWNLOAD,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeVideo,
            },
        },
        'streaming' => {
            'interactive streaming' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_STREAM,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeVideo,
            },
        },    
        'streaming (video)' => {
            'interactive streaming' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_STREAM,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeVideo,
            },
        },             
        'video streaming (ad-supported)' => {
            'interactive streaming' => {
                product_type    => RPS::File::Sale::TYPE_TRACK,
                format_type     => RPS::File::Sale::FORMAT_STREAM,
                media_type      => RPS::DB::Item::MediaType::kMediaTypeVideo,
            },
        },
    },   
);
    
sub _getMappings
{
    my $self = shift;

    my $assetType        = $self->_getByFieldName( 'productType' );
    my $salesDescription = $self->_getByFieldName( 'formatType' );
    my $salesCategory    = $self->_getByFieldName( 'mediaType' );
 
    my $productAttributes = $gProductFormatMediaTypeMappings{lc($assetType)}{lc($salesDescription)}{lc ($salesCategory)};

    my $product_type = $productAttributes->{product_type};
    my $format_type  = $productAttributes->{format_type};
    my $media_type   = $productAttributes->{media_type};

    # !!! Note that product type is now based on whether or not we have a track name,
    # !!! so none of the stuff that happens here will actually affect the product type.
    #
    if (defined($productAttributes->{check_isrc}))
    {
        if ($self->_getByFieldName('isrc'))
        {
            $product_type = RPS::File::Sale::TYPE_TRACK;
        }
        else
        {
            $product_type = RPS::File::Sale::TYPE_ALBUM;
        }
    }
    
    # !!! We're going to override some of the mappins now for certain services.
    
    my $retailer = $self->_getByFieldName( 'serviceID' );
    
    if( $retailer =~ /vevo/i && !$salesDescription && !$salesCategory )
    {    
        $format_type = RPS::File::Sale::FORMAT_STREAM;
        $media_type  = RPS::DB::Item::MediaType::kMediaTypeVideo;
    }
    elsif ($retailer =~ /soundexchange/i)
    {
        $format_type = RPS::File::Sale::FORMAT_PERFORMANCE;
        $media_type  = RPS::DB::Item::MediaType::kMediaTypeAudio;        
    }
    elsif( $retailer =~ /pandora/i && $salesCategory =~ /non-interactive streaming/i)
    {    
        $format_type = RPS::File::Sale::FORMAT_PERFORMANCE;
    }

    return($format_type, $product_type, $media_type);
}

sub upc {
    return normalize_upc( shift->_getByFieldName('upc') );
}

sub productType {
    my $self = shift;

    my $_productType = $self->_getByFieldName( 'productType' );
    my $trackName = $self->_getByFieldName('trackName');

    my ( $formatType, $productType, $mediaType ) = $self->_getMappings();

    return $productType if( $productType );
    
    # If we can't find the "real" product type,
    # let's pass along whatever is in the file.
    return $_productType;
}

sub formatType           {
    my $self = shift;
    my $assetType   = $self->_getByFieldName( 'formatType' );

    return $self->handleError("Error: Licensing income cannot be processed with this sales file. "
        . "Remove the sales line and enter separately through the Licensing Income interface.",
        RPS::DB::Item::SaleImportError::kErrorNonqualifying) if( $assetType =~ /licensing/i );

    my ( $formatType, $productType, $mediaType ) = $self->_getMappings();

    return $formatType if ($formatType);

    # If we can't find the "real" format type,
    # let's pass along whatever is in the file.
    return $assetType;
}

sub mediaType           {
    my $self = shift;
    my $salesType   = $self->_getByFieldName( 'mediaType' );

    return $self->handleError("Error: Licensing income cannot be processed with this sales file. "
        . "Remove the sales line and enter separately through the Licensing Income interface.",
        RPS::DB::Item::SaleImportError::kErrorNonqualifying) if( $salesType =~ /licensing/i );

    my ( $formatType, $productType, $mediaType ) = $self->_getMappings();

    return $mediaType if( $mediaType );
    
    # If we can't find the "real" media type,
    # let's pass along whatever is in the file.
    return $salesType;
}

sub serviceID           {
    my $self = shift;
    my $retailer = $self->_getByFieldName( 'serviceID' );

    my $service_id = $self->getServiceID(lc($retailer)) || $RPS::Import::ServiceMap::SERVICE_ALIASES{lc($retailer)};

    return $self->handleError( "Unknown service $retailer",
        RPS::DB::Item::SaleImportError::kErrorService ) if( !$service_id );

    return $service_id;
}

sub countryCode {
    my $self = shift;
    my $name = $self->SUPER::countryCode();

	if ($name) {
	    $name =~ s/,.*//;
	
	    $name = $self->_getAlternateCountryName($name) || $name;
	
	    my $country = new Common::Country( search => $name );
		if ($country) {
			return $country->alpha2();
		} else {
			return $name;
		}
	}  
    else
    {
        # If territory is blank, try alternate location (FB12234)
        #
        if( defined $self->_unverifiedFieldMap && exists $self->_unverifiedFieldMap->{'stmtCountryISO'} )
        {
            my $alt = $self->_getByFieldName('stmtCountryISO');
            return ($alt) ? $alt : 'US'; # default is US if nothing in template (FB18630)
        }
        else
        {
            return 'US'; # default is US if nothing in template (FB18630)
        }
    }
}

my %countries = (
   'US Virgin Islands' => 'Virgin Islands, U.S.',
   'British Virgin Islands' => 'Virgin Islands, British',
   'European Economic and Monetary Union' => 'European Union',
   'Kyrgyz Republic' => 'Kyrgyzstan',
   'Micronesia,Federated States of' => 'Micronesia, Federated States of',
);

sub _getAlternateCountryName {
    my($self, $name) = @_;
    return (exists $countries{$name}) ? $countries{$name} : undef;
}

sub free {
    my $self = shift;
    my $assetType        = $self->_getByFieldName( 'productType' );
    my $salesDescription = $self->_getByFieldName( 'formatType' );
    my $salesCategory    = $self->_getByFieldName( 'mediaType' );
    my $price            = $self->_getByFieldName( 'price' );

    my $free = 1 if( $assetType =~ /^track$/i &&
                     $salesDescription =~ /^streaming \(free trial\)$/i  &&
                     $salesCategory =~ /^interactive streaming$/i &&
                     (!defined $price || $price == 0) );
    return $free;
}

sub price {
    my $price = abs( shift->SUPER::price() );
    return $price;
}

sub unitPrice { abs( shift->SUPER::unitPrice ) }

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

    # Due to custom Excel formatting, the units may have ".0" appended to them.
    #
    $units =~ s/\.0+$//;

    return undef if ( !$units );

    if( defined($price) ) {
        return $price < 0 ? abs($units) * -1 : $units;
    } else {
        return $units;
    }
}


sub currencyCode {
    my $self = shift;
    my $currency = $self->_getByFieldName( 'currencyCode' );

    if( $currency =~ /^US\$/ || $currency =~ /Dollars/i ) {
        return "USD";
    } else {
        if( defined $self->_unverifiedFieldMap && exists $self->_unverifiedFieldMap->{'altCurrencyCode'} ) {
            $currency = $self->_getByFieldName('altCurrencyCode');
            if( $currency =~ /^US\$/ || $currency =~ /Dollars/i ) {
                return "USD";
            }
        }
        return $self->handleError( "Cannot determine currency code from $currency", RPS::DB::Item::SaleImportError::kErrorNonqualifying );
		return;          
    }
}

sub _getDateBegin
{
    my $self = shift;
    my $period = $self->SUPER::_getDateBegin;

    if( $period =~ /^P(\d\d) (\d\d)/i )  # PMM YY (Jan 13)
    {
        my( $month, $year ) = ($1, $2);
        return '20' . $year . '-' . $month . '-01';
    }
    
    if ($period) {
        return $period;
    }
    
	return $self->handleError( "Date not set", RPS::DB::Item::SaleImportError::kErrorNonqualifying );
}

sub _getDateEnd
{
    my $self = shift;

    return $self->_getDateBegin;
}

sub _isValidSaleRecord {
    my $self = shift;
    my $trackName = $self->_getByFieldName('trackName');
    my $albumName = $self->_getByFieldName('albumName');
    my $service   = $self->_getByFieldName('serviceID');

    my $artistName = $self->_getByFieldName('artistName');
    my $upc = $self->_getByFieldName('upc');
    my $isrc = $self->_getByFieldName('upc');

    my $units = $self->_getByFieldName('units');
    my $price = $self->_getByFieldName('price');

    # Skip line if there are zero units with zero revenue.
    # See https://royaltyshare.fogbugz.com/default.asp?W21 for more information.
    #
    return 0 if(!$units && !$price);

    # Error out if line has a service name, but is missing anything that could be used for matching
    #
    if( $service )
    {
        # If we don't have a track name, album name, artist name, UPC and ISRC, then we have an error.
        # Otherwise, if we have at least a UPC or ISRC then let it through.
        #
        if( (!$trackName  || '' eq $trackName) &&
            (!$albumName  || '' eq $albumName) &&
            (!$artistName || '' eq $artistName) &&
            (!$upc        || '' eq $upc) &&
            (!$isrc       || '' eq $isrc))
        {
            # Since this is being called from within _isValidSaleRecord, we aren't going to return the result of 
            # handleError.  Instead, we'll just log the error and return 1.
            $self->handleError( "Record missing catalog data", RPS::DB::Item::SaleImportError::kErrorNonqualifying );
            return 1;
        }
        elsif( ($isrc && '' ne $isrc) ||
               ($upc  && '' ne $upc) )
        {
            return 1;
        }
    }

    return $self->SUPER::_isValidSaleRecord();
}


## MapFace Stuff

# If we want to check for mappings that were created by other compatible versions,
# that must be specified here.
sub _mapFaceCompatibleVersions {
	return (22,23,25,26,27,28);
}

sub _mapFaceServiceID {
	return ('serviceID');
}

sub _mapFaceCountryCode {
	return ('countryCode');
}

# !! This is now based on whether or not we have a track name.
sub _mapFaceProductType {
	return ('mediaType', 'formatType', 'productType');
}

sub _mapFaceFormatType {
	return ('mediaType', 'formatType', 'productType');
}

sub _mapFaceMediaType {
	return ('mediaType', 'formatType', 'productType');
}


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