#!/usr/bin/perl
#------------------------------------------------------------
# Copyright (C) 2006 RoyaltyShare, Inc.   All Rights Reserved
# $Id$
#------------------------------------------------------------
use strict;

#use warnings;

use Data::Dumper;
use Getopt::Std;
use Carp;

use lib '/app/tools/common/lib';
use Common::Assert;
use Common::RSMath;
use Common::Locale;
use Common::Client;
use Common::UTF8;

use lib '/app/tools/rps/lib';
use RPS::Statement::Mechanical::CA::StatementFull;
use RPS::Statement::Mechanical::CA::StatementLicenseTransactionList;
use RPS::Payor::Payor;
use RPS::Publisher::CA::Publisher;
use RPS::Mechanical::CA::MechanicalRun;
use RPS::DB::Item::CAMechanicalRun;
use RPS::DB::Item::ContractRateType;
use RPS::DB::Item::IncomeSource;
use RPS::DB::Item::Region;
use RPS::DB::Item::Channel;
use RPS::DB::Item::PriceLevel;
use RPS::DB::Item::ProductType;
use RPS::DB::Item::TrackLicense;

use lib '/app/tools/rps/bin/statements';
use Formats;

$SIG{__DIE__} = \&Carp::confess;

# This determines how much output we spew forth to STDERR.
# The user can set this with the -V command-line argument.
#
my $gVerbosityLevel = 1;

# Parse the command-line, then create the text file!
#
my %options;
parseCommandLine( \%options );
createStatement( $options{clientID}, $options{mechanicalStatementID}, $options{outputFile} );

# ----------------------------------------------------------------------------------------------

sub createStatement {
    my ( $clientID, $mechanicalStatementID, $outFilePath ) = @_;

    # Instantiate the application singleton object.
    #
    my $appSingleton = Common::RSApp->new( clientID => $clientID );

    # Instantiate the MechanicalStatement object.
    # This object will contain all the info we need to output the statement document.
    #
    my $statement = RPS::Statement::Mechanical::CA::StatementFull->new(
        mechanicalStatementID => $mechanicalStatementID,
        focusPublisherID      => 'all'
    );

    my $runDBItem = RPS::DB::Item::CAMechanicalRun->Lookup( ca_mechanical_run_id => $statement->MechanicalRunID() );

    my $payorID = $runDBItem->payor_id();

    my $run = RPS::Mechanical::CA::MechanicalRun->new(
        mechanicalRunID => $statement->MechanicalRunID(),
        payorID         => $payorID,
    );

    # If an output file path was not specified, create one out of the statement id.
    #
    if ( !$outFilePath ) {
        $outFilePath = "ca_mechanical_statement_$mechanicalStatementID.txt";
    }

    # Open file for writing
    open( my $outFile, ">" . $outFilePath );

    #binmode($outFile, ':utf8');
    #binmode $outFile,":encoding(latin1)";

    header( $outFile, $run );

    my $statementUnits;
    my $statementAmount;
    my $statementRecords;

    # Loop through all publishers
    my $publisherList = $statement->MechanicalStatementPublisherList()->getList();
    foreach my $publisher (@$publisherList) {
        my ( $publisherUnits, $publisherAmount, $publisherRecords ) = details( $outFile, $publisher );
        $statementUnits   += $publisherUnits;
        $statementAmount  += $publisherAmount;
        $statementRecords += $publisherRecords;
    }

    # We need to account for the header and footer in the statement records count.
    #
    $statementRecords += 2;

    footer( $outFile, $run, $statementUnits, $statementAmount, $statementRecords );

    # All done, close it up.
    #
    close $outFile;
}

sub header {
    my ( $outFile, $run ) = @_;

    my $payorID = $run->PayorID();
    my $payor = RPS::Payor::Payor->new( payorID => $payorID );

    # StartTime format is 2009-05-08 11:42:51
    my $dateCreated = formatDate( $run->StartTime() );
    my $periodStart = formatDate( $run->StartDate() );
    my $periodEnd   = formatDate( $run->EndDate() );

    # Write out header stuff.
    my @headerFields =
      ( 'HC', formatAN( $payor->Name(), 50 ), formatAN( $periodStart, 8 ), formatAN( $periodEnd, 8 ), formatAN( $dateCreated, 8 ), );

    my $header = join( '', @headerFields );
    print $outFile uc("$header") . "\r\n";

}

sub details {
    my ( $outFile, $statement ) = @_;

    # We'll add to these as we go so that we can print out publisher totals at the end.
    #
    my $publisherRecords = 0;
    my $publisherUnits   = 0;
    my $publisherAmount  = 0;

    my $publisherNumber = $statement->Publisher()->ClientAccountID();

    # Write out the publisher header stuff.
    #
    _printPublisherHeader( $outFile, $publisherNumber, $statement->Publisher()->PublisherName() );

    my $trackList = $statement->MechanicalStatementTrackList()->getList();
    foreach my $track (@$trackList) {
        my $trackData = RPS::DB::Item::Track->Lookup( track_id => $track->TrackID() );
        my $trackTitle = $trackData->title;

        # Need to grab the song for this track now.
        #
        my $master = RPS::DB::Item::Master->Lookup( master_id => $trackData->master_id );
        my $song = RPS::DB::Item::Song->Lookup( song_id => $master->song_id() );

        my $iswc     = $song->iswc();
        my $duration = $master->duration();
        $duration = formatDuration($duration);

        # Composer is not mandatory, so we're leaving it blank for now.
        #
        my $composer = '';

        # Go through the crossed license list
        #
        my $crossedLicenseList = $track->MechanicalStatementCrossedLicenseList()->getList();

        if ( @$crossedLicenseList > 0 ) {
            my $licenseAmount;
            my $licenseUnits;
            my $licenseRecords;

            # Song header is really more of a license header.
            # Since crossed licenses are grouped, we'll just print out one for all of them.
            #

            my $issuerSongID = $trackData->track_id . "C";

            _printSongHeader( $outFile, $publisherNumber, $issuerSongID, $trackTitle, $iswc, $composer );

            foreach my $license (@$crossedLicenseList) {

                my $trackLicenseData = RPS::DB::Item::CATrackLicense->Lookup( ca_track_license_id => $license->TrackLicenseID() );

                my $issuerLicenseID = $trackLicenseData->issuer_license_id;

                # If there is a previous balance for this license, let's print that out now.
                #
                if ( $license->PreviousAdvanceBalance() != 0 ) {
                    _printSongBalanceForward( $outFile, $license->PreviousAdvanceBalance(),
                        $publisherNumber, $issuerSongID, $issuerLicenseID, $track, $duration, $iswc );

                    $licenseAmount += $license->PreviousAdvanceBalance();

                    $licenseRecords++;
                }

                my $incomeItemList       = $license->MechanicalStatementItemList()->getList();
                my $incomeItemListLength = scalar(@$incomeItemList);

                # If there are income items, print them out now.
                #
                if ( $incomeItemListLength != 0 ) {

                    foreach my $incomeItem (@$incomeItemList) {
                        _printSongRecord( $outFile, $publisherNumber, $issuerSongID, $issuerLicenseID, $track, $incomeItem, $duration,
                            $iswc );

                        $licenseAmount += $incomeItem->AmountPaid();

                        $licenseUnits += $incomeItem->NetUnits();

                        $licenseRecords++;
                    }
                }

                # If there are adjustments or advances for this license, print them out now.
                #
                my $xmlObj                  = $license->MechanicalStatementLicenseTransactionList();
                my $licenseTransactionList  = $xmlObj->getList();
                my $licenseTransactionCount = scalar(@$licenseTransactionList);

                if ( $licenseTransactionCount != 0 ) {
                    foreach my $licenseTransaction (@$licenseTransactionList) {
                        _printSongAdjustment( $outFile, $licenseTransaction->Amount(),
                            $publisherNumber, $issuerSongID, $issuerLicenseID, $track, $duration, $iswc );

                        $licenseAmount += $licenseTransaction->Amount();

                        $licenseRecords++;
                    }
                }

            }

            # If there are adjustments or advances for crossed licenses for this track, print them out now.
            #
            my $xmlObj                  = $track->MechanicalStatementCrossedLicenseTransactionList();
            my $licenseTransactionList  = $xmlObj->getList();
            my $licenseTransactionCount = scalar(@$licenseTransactionList);

            if ( $licenseTransactionCount != 0 ) {
                foreach my $licenseTransaction (@$licenseTransactionList) {
                    _printSongAdjustment( $outFile, $licenseTransaction->Amount(),
                        $publisherNumber, $issuerSongID, '', $track, $duration, $iswc );

                    $licenseAmount += $licenseTransaction->Amount();

                    $licenseRecords++;
                }
            }

            # If there is a previous balance for this group of crossed licenses, let's print that out now.
            #
            if ( $track->CrossedPreviousAdvanceBalance() != 0 ) {
                _printSongBalanceForward( $outFile, $track->CrossedPreviousAdvanceBalance(),
                    $publisherNumber, $issuerSongID, '', $track, $duration, $iswc );

                $licenseAmount += $track->CrossedPreviousAdvanceBalance();

                $licenseRecords++;
            }

            # Negative balances will be carried forward, so don't include them in the totals for the track.
            #
            if ( $licenseAmount < 0 ) {
                $licenseAmount = 0;
                $licenseUnits  = 0;

            }

            # We need to account for the header and footer records in the count.
            #
            $licenseRecords += 2;

            _printSongTrailer( $outFile, $publisherNumber, $issuerSongID, $trackTitle, $licenseUnits, $licenseAmount, $licenseRecords );

            # Add the crossed license totals to the publisher totals.
            #
            $publisherUnits   += $licenseUnits;
            $publisherAmount  += $licenseAmount;
            $publisherRecords += $licenseRecords;

        }

        # Go through the uncrossed license list
        #
        my $licenseList = $track->MechanicalStatementLicenseList()->getList();
        foreach my $license (@$licenseList) {
            my $licenseRecords;
            my $licenseAmount;
            my $licenseUnits;

            my $trackLicenseData = RPS::DB::Item::CATrackLicense->Lookup( ca_track_license_id => $license->TrackLicenseID() );

            my $issuerLicenseID = $trackLicenseData->issuer_license_id;
            my $issuerSongID    = $license->TrackLicenseID();

            _printSongHeader( $outFile, $publisherNumber, $issuerSongID, $trackTitle, $iswc, $composer );

            # If there is a previous balance for this license, let's print that out now.
            #
            if ( $license->PreviousAdvanceBalance() != 0 ) {
                _printSongBalanceForward( $outFile, $license->PreviousAdvanceBalance(),
                    $publisherNumber, $issuerSongID, $issuerLicenseID, $track, $duration, $iswc );

                $licenseAmount += $license->PreviousAdvanceBalance();

                $licenseRecords++;
            }

            my $incomeItemList       = $license->MechanicalStatementItemList()->getList();
            my $incomeItemListLength = scalar(@$incomeItemList);

            # If there are income items, print them out now.
            #
            if ( $incomeItemListLength != 0 ) {

                foreach my $incomeItem (@$incomeItemList) {
                    _printSongRecord( $outFile, $publisherNumber, $issuerSongID, $issuerLicenseID, $track, $incomeItem, $duration, $iswc );

                    $licenseAmount += $incomeItem->AmountPaid();
                    $licenseUnits  += $incomeItem->NetUnits();

                    $licenseRecords++;
                }
            }

            my $xmlObj                  = $license->MechanicalStatementLicenseTransactionList();
            my $licenseTransactionList  = $xmlObj->getList();
            my $licenseTransactionCount = scalar(@$licenseTransactionList);

            if ( $licenseTransactionCount != 0 ) {
                foreach my $licenseTransaction (@$licenseTransactionList) {
                    _printSongAdjustment( $outFile, $licenseTransaction->Amount(),
                        $publisherNumber, $issuerSongID, $issuerLicenseID, $track, $duration, $iswc );

                    $licenseAmount += $licenseTransaction->Amount();

                    $licenseRecords++;
                }
            }

            # Negative balances will be carried forward, so don't include them in the totals for the license.
            #
            if ( $licenseAmount < 0 ) {
                $licenseAmount = 0;
                $licenseUnits  = 0;

            }

            # Print out the totals for this track.
            # We need to account for the header and footer in the track record count.
            #
            $licenseRecords += 2;

            _printSongTrailer( $outFile, $publisherNumber, $issuerSongID, $trackTitle, $licenseUnits, $licenseAmount, $licenseRecords );

            # Add the license totals to the publisher totals.
            #
            $publisherUnits   += $licenseUnits;
            $publisherAmount  += $licenseAmount;
            $publisherRecords += $licenseRecords;

        }

    }

    # Print out the footer with the grand totals for this publisher.
    #

    # We need to account for the header and footer in the publisher record count.
    #
    $publisherRecords += 2;

    _printPublisherTrailer( $outFile, $publisherNumber, $publisherUnits, $publisherAmount, $publisherRecords );

    return ( $publisherUnits, $publisherAmount, $publisherRecords );

}

sub _printPublisherHeader {
    my ( $outFile, $publisherNumber, $publisherName ) = @_;

    my @publisherHeaderFields = ( 'HP', formatAN( $publisherNumber, 10 ), formatAN( $publisherName, 40 ), );

    my $publisherHeader = join( '', @publisherHeaderFields );
    print $outFile uc("$publisherHeader") . "\r\n";
}

sub _printPublisherPreviousBalance {
    my ( $outFile, $publisherNumber, $previousBalance ) = @_;

    my @publisherFields =
      ( 'DP', formatAN( $publisherNumber, 10 ), formatRZ( $previousBalance, 13, 2, 1 ), formatAN( 'Previous Balance', 50 ), );

    my $publisherPreviousBalance = join( '', @publisherFields );
    print $outFile uc("$publisherPreviousBalance") . "\r\n";
}

sub _printPublisherPreviousAdvanceBalance {
    my ( $outFile, $publisherNumber, $previousAdvanceBalance ) = @_;

    my @publisherFields = ( 'DP', formatAN( $publisherNumber, 10 ), formatRZ( $previousAdvanceBalance, 13, 2, 1 ),
        formatAN( 'Previous Advance Balance', 50 ), );

    my $publisherPreviousAdvanceBalance = join( '', @publisherFields );
    print $outFile uc("$publisherPreviousAdvanceBalance") . "\r\n";

}

sub _printPublisherTransaction {
    my ( $outFile, $publisherNumber, $transaction ) = @_;

    my $transactionType   = transactionTypeCodeToName( $transaction->TypeCode() );
    my $transactionAmount = $transaction->Amount;
    my @publisherTransactionFields =
      ( 'DP', formatAN( $publisherNumber, 10 ), formatRZ( $transactionAmount, 13, 2, 1 ), formatAN( $transactionType, 50 ), );

    my $publisherTransactions = join( '', @publisherTransactionFields );
    print $outFile uc("$publisherTransactions") . "\r\n";
}

sub _printPublisherTrailer {
    my ( $outFile, $publisherNumber, $units, $amount, $records ) = @_;

    my @publisherTrailerFields =
      ( 'TP', formatAN( $publisherNumber, 10 ), formatRZ( $units, 13, 0, 1 ), formatRZ( $amount, 13, 2, 1 ), formatRZ( $records, 6, 0 ), );

    my $publisherTrailer = join( '', @publisherTrailerFields );
    print $outFile uc("$publisherTrailer") . "\r\n";
}

sub _printSongHeader {
    my ( $outFile, $publisherNumber, $issuerSongID, $songTitle, $iswc, $composer ) = @_;

    my @songHeaderFields = (
        'HS',
        formatAN( $publisherNumber, 10 ),
        formatAN( $issuerSongID,    20 ),
        formatAN( $songTitle,       50 ),
        formatAN( $iswc,            20 ),
        formatAN( $composer,        100 ),
    );

    my $songHeader = join( '', @songHeaderFields );
    print $outFile uc("$songHeader") . "\r\n";
}

sub _printSongBalanceForward {
    my ( $outFile, $trackAmount, $publisherNumber, $issuerSongID, $issuerLicenseID, $track, $duration, $iswc ) = @_;

    my @itemRow = (
        'DS',
        formatAN( 'B',                     2 ),
        formatAN( $publisherNumber,        10 ),
        formatAN( $issuerSongID,           20 ),
        formatAN( $track->SongTitle(),     50 ),
        formatAN( $track->CatalogNumber(), 15 ),
        formatAN( '',                      15 ),
        formatRZ( 0, 13, 0, 1 ),
        'P',
        formatRZ( 0, 15, 9 ),
        formatRZ( 0, 7,  4 ),
        formatRZ( $trackAmount, 13, 2, 1 ),
        formatRZ( $duration,    6,  0 ),
        formatAN( '',    20 ),
        formatAN( $iswc, 20 ),
        formatAN( '',    5 ),    # distribution method
    );

    my $joinedItemRow = join( "", @itemRow );
    print $outFile uc("$joinedItemRow") . "\n";
}

sub _printSongRecord {
    my ( $outFile, $publisherNumber, $issuerSongID, $issuerLicenseID, $track, $incomeItem, $duration, $iswc ) = @_;

    my @itemRow = (
        'DS',
        formatAN( 'N',                     2 ),
        formatAN( $publisherNumber,        10 ),
        formatAN( $issuerSongID,           20 ),
        formatAN( $track->SongTitle(),     50 ),
        formatAN( $track->CatalogNumber(), 15 ),
        formatAN( $issuerLicenseID,        15 ),
        formatRZ( $incomeItem->NetUnits(), 13, 0, 1 ),
        'P',
        formatRZ( $incomeItem->NetRate(),             15, 9 ),
        formatRZ( $incomeItem->TrackLicense->Share(), 7,  4 ),
        formatRZ( $incomeItem->AmountPaid(), 13, 2, 1 ),
        formatRZ( $duration,                 6,  0 ),
        formatAN( $incomeItem->UPC(), 20 ),
        formatAN( $iswc,              20 ),
        formatAN( '',                 5 ),    # distribution method
    );

    my $joinedItemRow = join( "", @itemRow );
    print $outFile uc("$joinedItemRow") . "\n";
}

sub _printSongAdjustment {
    my ( $outFile, $adjustmentAmount, $publisherNumber, $issuerSongID, $issuerLicenseID, $track, $duration, $iswc ) = @_;

    my @itemRow = (
        'DS',
        formatAN( 'A',                     2 ),
        formatAN( $publisherNumber,        10 ),
        formatAN( $issuerSongID,           20 ),
        formatAN( $track->SongTitle(),     50 ),
        formatAN( $track->CatalogNumber(), 15 ),
        formatAN( $issuerLicenseID,        15 ),
        formatRZ( 0, 13, 0, 1 ),
        'P',
        formatRZ( 0, 15, 9 ),
        formatRZ( 0, 7,  4 ),
        formatRZ( $adjustmentAmount, 13, 2, 1 ),
        formatRZ( $duration,         6,  0 ),
        formatAN( '',    20 ),
        formatAN( $iswc, 20 ),
        formatAN( '',    5 ),    # distribution method
    );

    my $joinedItemRow = join( "", @itemRow );
    print $outFile uc("$joinedItemRow") . "\n";
}

sub _printSongTrailer {
    my ( $outFile, $publisherNumber, $issuerSongID, $songTitle, $units, $amount, $records ) = @_;

    my @songHeaderFields = (
        'TS',
        formatAN( $publisherNumber, 10 ),
        formatAN( $issuerSongID,    20 ),
        formatAN( $songTitle,       50 ),
        formatRZ( $units,   13, 0, 1 ),
        formatRZ( $amount,  13, 2, 1 ),
        formatRZ( $records, 6,  0 ),
    );

    my $songHeader = join( '', @songHeaderFields );
    print $outFile uc("$songHeader") . "\r\n";
}

sub footer {
    my ( $outFile, $run, $units, $amount, $records ) = @_;

    my $payorID = $run->PayorID();
    my $payor = RPS::Payor::Payor->new( payorID => $payorID );

    # Write out footer stuff.
    my @footerFields =
      ( 'TC', formatAN( $payor->Name(), 50 ), formatRZ( $units, 13, 0, 1 ), formatRZ( $amount, 13, 2, 1 ), formatRZ( $records, 6, 0 ), );

    my $footer = join( '', @footerFields );
    print $outFile uc("$footer") . "\r\n";
}

# Formatting functions
#

sub formatAN {

    #  Left-adjusted alphanumeric field, right space-filled
    #
    my ( $string, $length ) = @_;
    my $latinString = Common::UTF8::ToAscii($string);

    my $padded = pack( "A$length", $latinString );

    return $padded;
}

sub formatRZ {

    #  Right-adjusted numeric field, left zero filled
    my ( $string, $length, $decimalPlaces, $signed ) = @_;

    # Let's see if we're dealing witha positive or negative number.
    #
    my $sign;

    if ( $string < 0 ) {
        $sign = '-';
    } else {
        $sign = '+';
    }

    # First, let's make sure there are the right number of places after the decimal.
    #
    if ( $decimalPlaces > 0 ) {
        my $sprintfArg = "%." . $decimalPlaces . "f";
        $string = sprintf( $sprintfArg, $string );
    }

    # Now let's get rid of anything that's not a digit.
    $string =~ s/\D//g;

    $string = substr( "0" x $length . $string, -$length );

    # Note that we are not "signing" zero at this time.
    # If it turns out that we should be, simply remove that part of the following if statement.
    #
    if ( $string != 0 && $signed ) {
        #
        # Here's the fun part.  We need to convert the last digit to EBCDIC.
        # This allows us to show whether a number is positive or negative without using an extra character.
        # Characters aren't cheap, ya know.
        my $last = chop($string);
        $last = convertToEBCDIC( $sign . $last );
        $string .= $last;
    }

    return $string;
}

sub transactionTypeCodeToName {
    my ($code) = @_;

    my $name = "Adjustment";

    if ( $code == 3 ) {
        $name = "Advance";
    }

    return $name;
}

sub convertToEBCDIC {
    my ($string) = @_;

    if ( $string eq '+0' ) {
        $string = '{';
    } elsif ( $string eq '+1' ) {
        $string = 'A';
    } elsif ( $string eq '+2' ) {
        $string = 'B';
    } elsif ( $string eq '+3' ) {
        $string = 'C';
    } elsif ( $string eq '+4' ) {
        $string = 'D';
    } elsif ( $string eq '+5' ) {
        $string = 'E';
    } elsif ( $string eq '+6' ) {
        $string = 'F';
    } elsif ( $string eq '+7' ) {
        $string = 'G';
    } elsif ( $string eq '+8' ) {
        $string = 'H';
    } elsif ( $string eq '+9' ) {
        $string = 'I';
    } elsif ( $string eq '-0' ) {
        $string = '}';
    } elsif ( $string eq '-1' ) {
        $string = 'J';
    } elsif ( $string eq '-2' ) {
        $string = 'K';
    } elsif ( $string eq '-3' ) {
        $string = 'L';
    } elsif ( $string eq '-4' ) {
        $string = 'M';
    } elsif ( $string eq '-5' ) {
        $string = 'N';
    } elsif ( $string eq '-6' ) {
        $string = 'O';
    } elsif ( $string eq '-7' ) {
        $string = 'P';
    } elsif ( $string eq '-8' ) {
        $string = 'Q';
    } elsif ( $string eq '-9' ) {
        $string = 'R';
    }
    return $string;
}

sub formatDate {
    my ($date) = @_;

    # Returns date in format: yyyymmdd

    my $formattedDate = substr( $date, 0, 4 );
    $formattedDate .= substr( $date, 5, 2 );
    $formattedDate .= substr( $date, 8, 2 );
    return $formattedDate;
}

sub formatDuration {
    my ($seconds) = @_;
    $seconds = 0 unless ($seconds);

    my $hours = $seconds / 3600;
    $seconds = $seconds % 3600;
    my $minutes = $seconds / 60;
    $seconds = $seconds % 60;
    return sprintf( "%02d%02d%02d", $hours, $minutes, $seconds );

}

# These functions map ids to their text representations.
# Basically, the first time we ask for a particular id->string mapping, we
# will query the correct database, and build a hash.  Subsequent calls just
# hit the hash.
#
# Because these tables are so similar, I abstracted the guts into the _genericMapAccessor
# method (to save myself some typing).
#
my %idMaps;

sub _genericMapAccessor {
    my ( $collectionAccessor, $idName, $id ) = @_;

    if ( !defined $idMaps{$collectionAccessor} ) {
        $idMaps{$collectionAccessor} = {};

        # This is a very naughty thing to do, but it works great in this context.
        #
        #        no strict 'refs';
        #        my $c = &$collectionAccessor();
        #        use strict 'refs';
        my $c = $collectionAccessor->GetAll();

        while ( my $item = $c->next() ) {
            if ( $idName ne 'product_type_id' ) {
                $idMaps{$collectionAccessor}{ $item->$idName() } = $item->name;
            } else {
                $idMaps{$collectionAccessor}{ $item->$idName() } =
                  $item->description;
            }
        }
    }

    return $idMaps{$collectionAccessor}{$id};
}

sub incomeSourceIDToName {
    my ($id) = @_;

    return _genericMapAccessor( 'RPS::DB::Item::IncomeSource', 'income_source_id', $id );
}

sub regionIDToName {
    my ($id) = @_;

    # we don't want to show Rest of World here
    if ( $id != 0 ) {
        return _genericMapAccessor( 'RPS::DB::Item::Region', 'region_id', $id );
    } else {
        return ' ';
    }
}

sub channelIDToName {
    my ($id) = @_;
    return _genericMapAccessor( 'RPS::DB::Item::Channel', 'channel_id', $id );
}

sub priceLevelIDToName {
    my ($id) = @_;
    return _genericMapAccessor( 'RPS::DB::Item::PriceLevel', 'price_level_id', $id );
}

sub contractRateTypeIDToName {
    my ($id) = @_;
    return _genericMapAccessor( 'RPS::DB::Item::ContractRateType', 'contract_rate_type_id', $id );
}

sub productCodeToName {
    my ($id) = @_;
    return _genericMapAccessor( 'RPS::DB::Item::ProductType', 'product_type_id', $id );
}

#
# Boring script stuff below...
#

sub parseCommandLine {
    my ($settings) = @_;

    my %opt;
    getopts( 's:c:f:V:', \%opt );

    if ( !$opt{s} || !$opt{c} ) {
        usage();
        exit(1);
    }
    $settings->{mechanicalStatementID} = $opt{s};
    $settings->{clientID}              = $opt{c};
    $settings->{outputFile}            = $opt{f};

    if ( defined $opt{V} ) {
        $gVerbosityLevel = $opt{V};
    }
}

sub usage {
    print STDERR "\nusage: $0 -c <client_id> -s <ca_mechanical_statement_id> [-f <output file>]\n";
    print STDERR "\n";
    print STDERR "Arguments:\n";
    print STDERR "\t-c <client_id>\t\t\tThe client_id of the client to process\n";
    print STDERR "\t-s <ca_mechanical_statement_id>\tThe id of the ca mechanical statement to convert to cmrra text\n";
    print STDERR "\t-f <output file>\tThe output file. Optional. If not provided, we'll make one up\n";
}

sub report {
    my ( $string, $verbosity ) = @_;
    $verbosity = 1 unless defined $verbosity;

    if ( $gVerbosityLevel >= $verbosity ) {
        print STDERR $string . "\n";
    }
}
