package RPS::Import::FontanaDigital::Base2009;

use strict;

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

use lib '/app/tools/common/lib';
use Common::Util;
use Common::Consts qw(%COUNTRY_CODE);

use lib '/app/tools/data_classes/lib';
use Client::Service;

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

my %service_map = (
    'Calabash Music'                   => Client::Service::DSP_CALABASH,
    'Dancetracks Digital'              => Client::Service::DSP_DANCETRACKS,
    'DestraMusic.com'                  => Client::Service::DSP_DESTRAMUSIC,
    'iTunes Music Store'               => Client::Service::DSP_ITUNES,
    'Mix and Burn'                     => Client::Service::DSP_MIXANDBURN,
    'm-Qube'                           => Client::Service::DSP_MQUBE,
    'MSN Music Service'                => Client::Service::DSP_MSNMUSIC,
    'RealNetworks / Rhapsody'          => Client::Service::DSP_REAL,
    'T-Online'                         => Client::Service::DSP_TONLINE,
    'Virtual Music Stores'             => Client::Service::DSP_VIRTUALMUSICSTORE,
    'Virginmega.fr'                    => Client::Service::DSP_VIRGINMEGA,
    'Snocap/Myspace'                   => Client::Service::DSP_SNOCAP,
    'Napster - Streams'                => Client::Service::DSP_NAPSTER,
    'Rhapsody'                         => Client::Service::DSP_REAL,
    'FNAC'                             => Client::Service::DSP_FNAC,
    'Starbucks'                        => Client::Service::DSP_STARBUCKS,
    'My Store'                         => Client::Service::DSP_MYSTORE,
    'Audio Lunchbox - Streams'         => Client::Service::DSP_AUDIOLUNCHBOX,
    'eMusic'                           => Client::Service::DSP_EMUSIC,
    'Sony Connect'                     => Client::Service::DSP_SONY,
    'Fun Mobility'                     => Client::Service::DSP_FUNMOBILITY,
    'Zingy Mobile'                     => Client::Service::DSP_ZINGY,
    'Beatport.com'                     => Client::Service::DSP_BEATPORT,
    'Other Music'                      => Client::Service::DSP_OTHERMUSIC,
    'Verizon'                          => Client::Service::DSP_VERIZON,
    'MediaNet Digital'                 => Client::Service::DSP_MEDIANET,
    'OD2 (Loudeye)'                    => Client::Service::DSP_OD2,
    'SecuryCast Download'              => Client::Service::DSP_SECURYCAST,
    'Thumbplay - **updated'            => Client::Service::DSP_THUMBPLAY,
    'Bell Mobility Full Track'         => Client::Service::DSP_BELLMOBILITY,
    'Hudson Entertainment (US)'        => Client::Service::DSP_HUDSON,
    'Pure Tracks'                      => Client::Service::DSP_PURETRACKS,
    'Jamba/Jamster'                    => Client::Service::DSP_JAMSTER,
    'Navio / gBox'                     => Client::Service::DSP_NAVIO,
    'Bell Mobility Ringtone'           => Client::Service::DSP_BELLMOBILITY,
    'Mbop Digital'                     => Client::Service::DSP_MBOPDIGITAL,
    'Slacker'                          => Client::Service::DSP_SLACKERINC,
    'Livewire Mobile / Groove Mobile'  => Client::Service::DSP_GROOVEMOBILE,
    'Amazon MP3'                       => Client::Service::DSP_AMAZON,
    'Rogers Wireless Ringtone'         => Client::Service::DSP_ROGERSWIRELESS,
    'm-Qube / VeriSign'                => Client::Service::DSP_MQUBE,
    'BOOST MOBILE/NEXTEL'              => Client::Service::DSP_BOOST,
    'LISTEN/RHAPSODY'                  => Client::Service::DSP_LISTEN,
    'MEDIAPORT ENTERTAINMENT INC.'     => Client::Service::DSP_MEDIAPORT,
    'MOD SYSTEMS, INC.'                => Client::Service::DSP_MODSYSTEMS,
    'MUSICGREMLIN, INC.'               => Client::Service::DSP_MUSICGREMLIN,
    'NextRadio Solutions'              => Client::Service::DSP_NEXTRADIO,
    'T-MOBILE USA'                     => Client::Service::DSP_TMOBILE,
    'VIRGIN MOBILE USA'                => Client::Service::DSP_VIRGINMOBILE,
    'APPLE DIGITAL SALES'              => Client::Service::DSP_ITUNES,
    'LAST.FM'                          => Client::Service::DSP_LASTFM,
    'MOHEN, INC.'                      => Client::Service::DSP_SPIRALFROG,
    'DIGITAL KIOSK TECHNOLOGIES LLC'   => Client::Service::DSP_DIGITALKIOSKTECH,
    'YOU TUBE'                         => Client::Service::DSP_YOUTUBE,
    'VIRTUAL MUSIC STORES, INC.'       => Client::Service::DSP_VIRTUALMUSICSTORE,
    'TEENHOLLYWOOD.COM INC.'           => Client::Service::DSP_TEENHOLLYWOOD,
    'PURETRACKS/B3'                    => Client::Service::DSP_PURETRACKS,
    'NEUROTIC / AMPLIFIED'             => Client::Service::DSP_NEUROTICMEDIA,
    'NAVIO SYSTEMS, INC.'              => Client::Service::DSP_NAVIO,
    'LA LA MEDIA, INC.'                => Client::Service::DSP_LALA,
    'FULL AUDIO/MUSICNOW'              => Client::Service::DSP_MUSICNOW,
    'CLEAR CHANNEL BROADCASTING, INC.' => Client::Service::DSP_CLEARCHANNEL,
    'CELLMANIA'                        => Client::Service::DSP_CELLMANIA,
    'ALLTEL COMMUNICATIONS, INC.'      => Client::Service::DSP_ALLTEL,
    'PLUGGEDIN MEDIA CORP.'            => Client::Service::DSP_PLUGGEDIN_MEDIA,
    'HIP DIGITAL MEDIA, INC.'          => Client::Service::DSP_HIP_DIGITAL_MEDIA,
    'ALL MEDIA GUIDE'                  => Client::Service::DSP_ALL_MEDIA_GUIDE,
    'BUONGIORNO USA'                   => Client::Service::DSP_BUONGIORNO_USA,
    '7DIGITAL LIMITED'                 => Client::Service::DSP_7DIGITAL,
    '9 SQUARED, INC.'                  => Client::Service::DSP_NINESQUARED,
    'AMI ENTERTAINMENT, INC'           => Client::Service::DSP_AMI,
    'BROADBAND INSTRUMENTS CORP.'      => Client::Service::DSP_BROADBANDINSTS,
    'CINGULAR WIRELESS, LLC'           => Client::Service::DSP_CINGULAR,
    'DADA MOBILE'                      => Client::Service::DSP_DADA,
    'INSTANT MEDIA NETWORKS'           => Client::Service::DSP_INSTANTMEDIA,
    'BLACKSTONE CALLING CARD, INC.'    => Client::Service::DSP_BLACKSTONE_CALLING_CARD,    # FB13204
    'SPOTIFY USA INC'                  => Client::Service::DSP_SPOTIFY,
    'PCM TECHNOLOGIES, INC. (CANADA)'  => Client::Service::DSP_PCMTECHNOLOGIES,
);

# This is used by pre-version 10 importers.
#
my %fontana_formats = (
    'PERMANENT DOWNLOADS'                             => RPS::File::Sale::FORMAT_DOWNLOAD,
    'PERMANENT DOWNLOADS PROMO'                       => RPS::File::Sale::FORMAT_DOWNLOAD,
    'AD SUPPORTED STREAMS'                            => RPS::File::Sale::FORMAT_STREAM,
    'MOBILE AUDIO STREAMS'                            => RPS::File::Sale::FORMAT_STREAM,
    'KIOSK'                                           => RPS::File::Sale::FORMAT_DOWNLOAD,
    'OTA PERMANENT DOWNLOADS'                         => RPS::File::Sale::FORMAT_DOWNLOAD,
    'PORTABLE SUB CLIENT PLAYS'                       => RPS::File::Sale::FORMAT_STREAM,
    'PORTABLE SUB DEVICE PLAYS'                       => RPS::File::Sale::FORMAT_STREAM,
    'PORTABLE SUB PROGRAMMED PLAYS'                   => RPS::File::Sale::FORMAT_STREAM,
    'PORTABLE SUB STREAMS'                            => RPS::File::Sale::FORMAT_STREAM,
    'PROGRAMMED STREAMING'                            => RPS::File::Sale::FORMAT_STREAM,
    'PROGRAMMED STREAMING (NON-ROYALTY BEARING)'      => RPS::File::Sale::FORMAT_STREAM,
    'SUBSCRIPTION PROGRAMMED STREAMING'               => RPS::File::Sale::FORMAT_STREAM,
    'RINGBACKS'                                       => RPS::File::Sale::FORMAT_RINGTONE,
    'SUBSCRIPTION RINGBACK'                           => RPS::File::Sale::FORMAT_RINGTONE,
    'RINGBACKS (NO CPRT LIABILITY)'                   => RPS::File::Sale::FORMAT_RINGTONE,
    'STANDARD MOBILE RINGSOUNDS'                      => RPS::File::Sale::FORMAT_RINGTONE,
    'STREAMS'                                         => RPS::File::Sale::FORMAT_STREAM,
    'SUBSCRIPTION MASTERTONES'                        => RPS::File::Sale::FORMAT_RINGTONE,
    'CONDITIONAL MASTERTONE'                          => RPS::File::Sale::FORMAT_TETHERED,
    'MASTERTONE REDELIVERY'                           => RPS::File::Sale::FORMAT_RINGTONE,
    'TETHERED/CONDITIONAL DOWNLOADS'                  => RPS::File::Sale::FORMAT_TETHERED,
    'VIDEO DOWNLOADS'                                 => RPS::File::Sale::FORMAT_DOWNLOAD,          # was FORMAT_VIDEO (FB1324)
    'USER GENERATED STREAMS (UMG AUDIO / USER VIDEO)' => RPS::File::Sale::FORMAT_STREAM,            # was FORMAT_VIDEOSTREAM (FB1324)
    'VIDEO STREAMS'                                   => RPS::File::Sale::FORMAT_STREAM,            # was FORMAT_VIDEOSTREAM (FB1324)
    'DRM FREE UPGRADE'                                => RPS::File::Sale::FORMAT_DOWNLOADUPGRADE,
    'DRM-FREE UPGRADE TRANSACTIONS'                   => RPS::File::Sale::FORMAT_DOWNLOADUPGRADE,
    'MOBILE VIDEO STREAMING'                          => RPS::File::Sale::FORMAT_STREAM,            # was FORMAT_VIDEOSTREAM (FB1324)
    'OTA VIDEO DOWNLOADS'                             => RPS::File::Sale::FORMAT_DOWNLOAD,
    'PERM DL FROM OTA - W/O WHOLESALE'                => RPS::File::Sale::FORMAT_DOWNLOAD,
    'PROGRAMMED VIDEO STREAMING'                      => RPS::File::Sale::FORMAT_STREAM,            # was FORMAT_VIDEOSTREAM (FB1324)
    'SUBSCRIPTION OTA PERMANENT DOWNLOADS (AUDIO)'    => RPS::File::Sale::FORMAT_VPD,
    'MOBILE IMAGES'                                   => 'SKIP',
    'SUBSCRIPTION MOBILE IMAGES'                      => 'SKIP',
);

# This is used by the version 10 importer (see FB15937).
#
my %gFormatMediaMap = (
    'AD SUPPORTED STREAMS' => {
        'AD SUPPORTED STREAMS' => {
            format => RPS::File::Sale::FORMAT_STREAM,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        },
        'DIGITAL STREAM' => {
            format => RPS::File::Sale::FORMAT_STREAM,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        },
    },
    'BROADCAST LINEAR PROGRAMMING' => {
        'VIDEO STREAMING' => {
            format => RPS::File::Sale::FORMAT_STREAM,
            media  => RPS::DB::Item::MediaType::kMediaTypeVideo,
        }
    },
    'BROADCAST VOD' => {
        'VIDEO STREAMING' => {
            format => RPS::File::Sale::FORMAT_STREAM,
            media  => RPS::DB::Item::MediaType::kMediaTypeVideo,
        }
    },
    'CONDITIONAL MASTERTONE' => {
        'CONDITIONAL MASTERTONES' => {
            format => RPS::File::Sale::FORMAT_TETHERED,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
    'EPHEMERAL PLAYS' => {
        'FIXED PLAYS' => {
            format => RPS::File::Sale::FORMAT_STREAM,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
    'FIXED PLAYS' => {
        'FIXED PLAYS' => {
            format => RPS::File::Sale::FORMAT_STREAM,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
    'JUKEBOX' => {
        'SUB USER GENERATED STREAMS (UMG VIDEO)' => {
            format => RPS::File::Sale::FORMAT_STREAM,
            media  => RPS::DB::Item::MediaType::kMediaTypeVideo,
        },
    },
    'KIOSK' => {
        'DIGITAL PERMANENT DOWNLOAD' => {
            format => RPS::File::Sale::FORMAT_DOWNLOAD,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
    'MASTERTONE REDELIVERY' => {
        'DIGITAL RINGSOUNDS' => {
            format => RPS::File::Sale::FORMAT_RINGTONE,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
    'MOBILE AUDIO STREAMS' => {
        'DIGITAL STREAM' => {
            format => RPS::File::Sale::FORMAT_STREAM,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
    'MOBILE IMAGES' => {
        'MOBILE IMAGES' => {
            format => 'SKIP',
            media  => 'SKIP'
        }
    },
    'MOBILE VIDEO STREAMING' => {
        'VIDEO STREAMING' => {
            format => RPS::File::Sale::FORMAT_STREAM,
            media  => RPS::DB::Item::MediaType::kMediaTypeVideo,
        }
    },
    'OTA PERMANENT DOWNLOADS' => {
        'DIGITAL PERMANENT DOWNLOAD' => {
            format => RPS::File::Sale::FORMAT_DOWNLOAD,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        },
        'MOBILE OTA DOWNLOADS' => {
            format => RPS::File::Sale::FORMAT_DOWNLOAD,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
    'PERMANENT DOWNLOADS' => {
        'DIGITAL PERMANENT DOWNLOAD' => {
            format => RPS::File::Sale::FORMAT_DOWNLOAD,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
    'PERMANENT DOWNLOADS PROMO' => {
        'DIGITAL PROMO' => {    # Note: will be considered free if revenue = 0 (see below)
            format => RPS::File::Sale::FORMAT_DOWNLOAD,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
    'PERM DL FROM OTA - W/O WHOLESALE' => {
        'UNKNOWN SALES TYPE 88' => {
            format => RPS::File::Sale::FORMAT_DOWNLOAD,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
    'PORTABLE SUB CLIENT PLAYS' => {
        'PORTABLE SUBSCRIPTIONS' => {
            format => RPS::File::Sale::FORMAT_STREAM,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
    'PORTABLE SUB DEVICE PLAYS' => {
        'PORTABLE SUBSCRIPTIONS' => {
            format => RPS::File::Sale::FORMAT_STREAM,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
    'PORTABLE SUB PROGRAMMED PLAYS' => {
        'DIGITAL STREAM' => {
            format => RPS::File::Sale::FORMAT_STREAM,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
    'PORTABLE SUB STREAMS' => {
        'PORTABLE SUBSCRIPTIONS' => {
            format => RPS::File::Sale::FORMAT_STREAM,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
    'PORTABLE SUB VIDEO DVC PLAYS' => {
        'SUB USER GENERATED STREAMS (UMG VIDEO)' => {
            format => RPS::File::Sale::FORMAT_STREAM,
            media  => RPS::DB::Item::MediaType::kMediaTypeVideo,
        },
        'VIDEO PORTABLE SUBSCRIPTIONS' => {
            format => RPS::File::Sale::FORMAT_STREAM,
            media  => RPS::DB::Item::MediaType::kMediaTypeVideo,
        }
    },
    'PROGRAMMED STREAMING' => {
        'DIGITAL STREAM' => {
            format => RPS::File::Sale::FORMAT_STREAM,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
    'PROGRAMMED STREAMING (NON-ROYALTY BEARING)' => {
        'PROGRAMMED STREAMING (NON-ROYALTY BEARIN' => {
            format => RPS::File::Sale::FORMAT_STREAM,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
    'PROGRAMMED STREAMING-CAPPED (NON-ROYALTY BEARING)' => {
        'PROGRAMMED STREAMING (NON-ROYALTY BEARIN' => {
            format => RPS::File::Sale::FORMAT_STREAM,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
    'PROGRAMMED STREAMING (SOUNDEXCHANGE ADMINISTERED)' => {
        'PROGRAMMED STREAMING (SOUNDEXCHANGE ADMI' => {
            format => RPS::File::Sale::FORMAT_PERFORMANCE,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
    'RINGBACKS' => {
        'RINGBACKS' => {
            format => RPS::File::Sale::FORMAT_RINGTONE,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
    'RINGBACKS (NO CPRT LIABILITY)' => {
        'CONDITIONAL RINGBACKS' => {
            format => RPS::File::Sale::FORMAT_TETHERED,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
    'STANDARD MOBILE RINGSOUNDS' => {
        'DIGITAL RINGSOUNDS' => {
            format => RPS::File::Sale::FORMAT_RINGTONE,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
    'STREAMS' => {
        'DIGITAL STREAM' => {
            format => RPS::File::Sale::FORMAT_STREAM,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        },
        'PORTABLE SUBSCRIPTIONS' => {
            format => RPS::File::Sale::FORMAT_STREAM,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
    'SUBSCRIPTION MASTERTONES' => {
        'DIGITAL RINGSOUNDS' => {
            format => RPS::File::Sale::FORMAT_RINGTONE,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
    'SUBSCRIPTION MOBILE IMAGES' => {
        'MOBILE IMAGES' => {
            format => 'SKIP',
            media  => 'SKIP'
        }
    },
    'SUBSCRIPTION OTA PERMANENT DOWNLOADS (AUDIO)' => {
        'SUBSCRIPTION OTA VIDEO DOWNLOADS' => {
            format => RPS::File::Sale::FORMAT_DOWNLOAD,
            media  => RPS::DB::Item::MediaType::kMediaTypeVideo,
        }
    },
    'SUBSCRIPTION PROGRAMMED STREAMING' => {
        'DIGITAL STREAM' => {
            format => RPS::File::Sale::FORMAT_STREAM,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        },
        'PORTABLE SUBSCRIPTIONS' => {
            format => RPS::File::Sale::FORMAT_STREAM,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
    'SUBSCRIPTION RINGBACK' => {
        'SUBSCRIPTION RINGBACK' => {
            format => RPS::File::Sale::FORMAT_RINGTONE,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
    'SUB USER GENERATED STREAMS (UMG AUDIO)' => {
        'USER GENERATED STREAMS' => {
            format => RPS::File::Sale::FORMAT_STREAM,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
    'SUB USER GENERATED STREAMS (UMG VIDEO)' => {
        'SUB USER GENERATED STREAMS (UMG VIDEO)' => {
            format => RPS::File::Sale::FORMAT_STREAM,
            media  => RPS::DB::Item::MediaType::kMediaTypeVideo,
        },
    },
    'TETHERED/CONDITIONAL DOWNLOADS' => {
        'DIGITAL STREAM' => {
            format => RPS::File::Sale::FORMAT_TETHERED,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        },
        'PORTABLE SUBSCRIPTIONS' => {
            format => RPS::File::Sale::FORMAT_TETHERED,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
    'VIDEO DOWNLOADS' => {
        'DIGITAL PERMANENT DOWNLOAD' => {
            format => RPS::File::Sale::FORMAT_DOWNLOAD,
            media  => RPS::DB::Item::MediaType::kMediaTypeVideo,
        }
    },
    'VIDEO FIXED PLAY' => {
        'VIDEO FIXED PLAY' => {
            format => RPS::File::Sale::FORMAT_STREAM,
            media  => RPS::DB::Item::MediaType::kMediaTypeVideo,
        }
    },
    'VIDEO STREAMS' => {
        'VIDEO STREAMING' => {
            format => RPS::File::Sale::FORMAT_STREAM,
            media  => RPS::DB::Item::MediaType::kMediaTypeVideo,
        }
    },
    'USER GENERATED STREAMS (UMG AUDIO / USER VIDEO)' => {
        'USER GENERATED STREAMS' => {
            format => RPS::File::Sale::FORMAT_STREAM,
            media  => RPS::DB::Item::MediaType::kMediaTypeAudio,
        }
    },
);

#public methods

sub _processHeader       { }
sub _serviceColumnHeader { 'GL Digital Partner' }
sub _sheetName           { '' }

sub _parseDate {
    my $self = shift;
    my $f_date = shift || return;

    my ( $dateBegin, $dateEnd );

    if ( $f_date =~ /\((.*)\)/ ) {
        ( $dateBegin, $dateEnd ) = $self->_getDates( date_begin => $1, type => "text" );
    }

    unless ( $dateBegin && $dateEnd ) {
        die "Couldn't get dates from: $f_date";
    }

    return ( $dateBegin, $dateEnd );
}

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

    my $lines    = $args{lines};
    my $version  = $args{file}->VersionNum();
    my $fileName = $args{file}->OrigFileName();
    my $linenum;

    return undef unless ($lines);

    my $gross_total = 0;

    my $offsets     = $self->_fieldMap();
    my $sheet_names = $args{sheet_names};

    my $sheetnum = 0;
    foreach my $sheet ( @{ $args{sheets} } ) {

        my $sheetName = $self->_sheetName();
        if ( ( $sheetName && $sheet_names->[$sheetnum] =~ /$sheetName/i )
            || !$sheetName )

        {

            my $f_date = $sheet->[ $offsets->{date_row} ]->[ $offsets->{date_col} ];
            my ( $dateBegin, $dateEnd );

            my $f_format = $sheet->[ $offsets->{format_row} ]->[ $offsets->{format_col} ];
            my $format;
            my $formatName;

            my $f_sheetnum = $sheetnum + 1;
            $linenum = 1;

            # Version 7 gets dates and format from the first row.
            my $result = $self->_processHeader( date => $f_date, format => $f_format );

            if ($result) {
                $dateBegin  = $result->{dateBegin};
                $dateEnd    = $result->{dateEnd};
                $formatName = $result->{format};
            }

            my $headerFound = undef;

            foreach my $line (@$sheet) {

                my $serviceName = $line->[ $offsets->{service} ];

                unless ($headerFound) {
                    $headerFound = 1
                      if ( $serviceName eq $self->_serviceColumnHeader() );
                    $linenum++;
                    next;
                }

                $serviceName =~ s/\s-\s\w+.*$//;
                $serviceName =~ s/\ssubscription.*$//i;
                $serviceName =~ s/\sdownload.*$//i;
                my $serviceID =
                     $self->getServiceID($serviceName)
                  || $service_map{$serviceName}
                  || $RPS::Import::ServiceMap::SERVICE_ALIASES{ lc $serviceName };

                my $strippedServiceName = $serviceName =~ s/\s/_/g;
                $serviceID =
                     $self->getServiceID($strippedServiceName)
                  || $service_map{$strippedServiceName}
                  || $RPS::Import::ServiceMap::SERVICE_ALIASES{ lc $serviceName }
                  if ( $serviceID eq "" );

                my $artist        = $line->[ $offsets->{artist} ];
                my $album         = $line->[ $offsets->{album} ];
                my $track         = $line->[ $offsets->{track} ];
                my $track_artist  = $line->[ $offsets->{track_artist} ] if ( $offsets->{track_artist} );
                my $label         = $line->[ $offsets->{label} ] if ( $offsets->{label} );
                my $isrc          = Common::Util::normalize_isrc( $line->[ $offsets->{isrc} ] ) if ( $offsets->{isrc} );
                my $upc           = $line->[ $offsets->{upc} ] if ( $offsets->{upc} );
                my ($units)       = $line->[ $offsets->{units} ];
                my ($total_price) = $line->[ $offsets->{price} ];

                # Excel custom formatting may allow negative numbers to also be surrounded
                # by parentheses.  Example: "(1)" may end up here as "(-1)".
                # To deal with this we remove the parentheses and make sure the value
                # is indeed negative.
                if ($total_price) {
                    $total_price =~ s/,//;
                    $total_price =~ s/\$//;
                    $total_price = ( $1 * -1 ) if ( $total_price =~ /\((\d+\.?\d*)\)/ );
                }
                if ($units) {
                    $units =~ s/,//;
                    $units =~ s/"//;
                    $units = ( $1 * -1 ) if ( $units =~ /\((\d+)\)/ );
                }

                my $price;
                my $type;
                if ( $line->[ $offsets->{type} ] =~ /track/i ) {
                    $type = RPS::File::Sale::TYPE_TRACK;
                } elsif ( $line->[ $offsets->{type} ] =~ /album/i ) {
                    $type = RPS::File::Sale::TYPE_ALBUM;
                } elsif ( $line->[ $offsets->{type} ] =~ /bundles/i ) {
                    $type = RPS::File::Sale::TYPE_TRACK;
                } elsif ( ( $line->[ $offsets->{type} ] =~ /sold as/i )
                    || $line->[ $offsets->{type} ] eq "" ) {
                } else {
                    die "unknown type: " . $line->[ $offsets->{type} ] . " on sheet: $f_sheetnum at line number: $linenum";
                }

                if ( $type eq RPS::File::Sale::TYPE_TRACK && $track_artist ) {
                    $artist = $track_artist;
                }

                # If we couldn't get this info from the header row
                unless ($result) {
                    ( $dateBegin, $dateEnd ) = $self->_parseDate( $line->[ $offsets->{period} ] );
                    $formatName = $line->[ $offsets->{channel} ];
                    $f_format   = $formatName;
                }

                my $mediaType = RPS::DB::Item::MediaType::kMediaTypeAudio;
                $format = '';    # reset

                my $free;

                # The following is for the looking up the format and media type
                # using the Sales Channel DESC and Sales Type DESC columns (FB15937).
                #
                if ( exists $offsets->{sales_type} ) {
                    my $_channel = uc $formatName;
                    my $_type    = uc $line->[ $offsets->{sales_type} ];

                    if ( exists $gFormatMediaMap{$_channel}{$_type} ) {
                        $format    = $gFormatMediaMap{$_channel}{$_type}->{format};
                        $mediaType = $gFormatMediaMap{$_channel}{$_type}->{media};

                        $free = 1 if ( $_channel =~ /^PERMANENT DOWNLOADS PROMO$/i
                            && $_type =~ /^DIGITAL PROMO$/i
                            && 0 == $total_price );
                    } else {
                        die "Line: $linenum: Could not get format and media from $formatName / $_type"
                          if ( $formatName && '' ne $formatName && $_type && '' ne $_type );
                    }
                } else {

                    # This is the method for determining format and media types in
                    # earlier versions of the importer.
                    #
                    $format = $fontana_formats{ uc $formatName };
                    $mediaType = RPS::DB::Item::MediaType::kMediaTypeVideo if ( $formatName =~ /video/i );
                }

                if ( ( $album || $artist || $type ) && $format ne 'SKIP' ) {

                    # Units follow the sign of the revenue ...
                    # See https://royaltyshare.fogbugz.com/default.asp?W21
                    #
                    $units = ( abs($units) * -1 ) if ( $total_price < 0 );
                    $units = abs($units)          if ( $total_price > 0 );

                    if ( $units == 0 ) {

                        # If we have a digital sale with revenue but no units, set units to 1 or -1.
                        # This mimics the logic in RPS::Importer::_checkForRevenueWithoutUnits. -ES
                        if ( $total_price < 0 ) {
                            $units = -1;
                        } elsif ( $total_price > 0 ) {
                            $units = 1;
                        }
                    }

                    if ( defined $total_price && defined $units && $units != 0 ) {

                        # use BigFloat to avoid perl's tendency to use scientific notation.
                        #
                        $price = Math::BigFloat->new($total_price);
                        $price /= $units;
                    }

                    unless ($format) {
                        die "Could not get format from: $f_format (name: $formatName) (line: $linenum)";
                    }
                    unless ($serviceID) {
                        die "Unknown service: $serviceName on sheet $f_sheetnum at line number: $linenum";
                    }

                    my $sale = RPS::Import::SaleRec->new();

                    $sale->serviceID($serviceID);

                    $sale->mediaType($mediaType);
                    $sale->productType($type);
                    $sale->formatType($format);
                    $sale->dateBegin($dateBegin);
                    $sale->dateEnd($dateEnd);
                    $sale->isrc($isrc) if ( $type eq RPS::File::Sale::TYPE_TRACK );
                    $sale->free($free) if ($free);
                    $sale->upc($upc);
                    $sale->artistName($artist);
                    $sale->albumName($album);
                    $sale->trackName($track) if ( $type eq RPS::File::Sale::TYPE_TRACK );
                    $sale->units($units);
                    $sale->price($price);
                    $sale->labelName($label) if $label;
                    $sale->lineNum($linenum);
                    $sale->countryCode('US');

                    $self->_insertSale( sale => $sale );
                }

                $linenum++;
            }
        }
        $sheetnum++;

    }

    return $linenum;
}

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