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

#use warnings;

use Data::Dumper;
use Getopt::Std;
use POSIX qw(floor);
use Carp;

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

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::Album;
use RPS::DB::Item::Artist;
use RPS::DB::Item::Master;
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::Product;
use RPS::DB::Item::ProductType;
use RPS::DB::Item::Track;
use RPS::DB::Item::CATrackLicense;

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 CSV!
#
my %options;
parseCommandLine( \%options );

processMechanicalRunCSV( $options{clientID}, $options{mechanicalRunID}, $options{mechanicalStatementID}, $options{outputPath} );

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

sub processMechanicalRunCSV {
    my ( $clientID, $runID, $statementID, $outFilePath ) = @_;

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

    # This report is intended to be run after the statements have been
    # generated, so the output path should already exist.

    # Create the output path if it isn't there already.
    #
    if ( '/' ne substr( $outFilePath, -1, 1 ) ) {
        $outFilePath .= "/";
    }

    if ( !-d $outFilePath ) {
        mkpath($outFilePath) or die "ERROR: Unable to create path $outFilePath: $!\n";
    }

    # Get rid of the semaphore file
    my $semaphore = $outFilePath . "EXPORT_TEXT_COMPLETE";
    unlink($semaphore);

    print STDERR "DEBUG: outFilePath($outFilePath) semaphore($semaphore)!!! \n";

    my $targetFile = $outFilePath . "ca_mechanical_export_run_$runID.txt";

    # Open export file for writing
    #open(my $outFile,">".$outFilePath);
    open( my $outFile, ">" . $targetFile );
    binmode( $outFile, ':utf8' );

    # Write out column headings.
    my @headings = (
        'publisher-name',               # A
        'client-no',                    # B
        'rs-payee-id',                  # C
        'publisher-type',               # D
        'publisher-admin',              # E
        'publisher-agent',              # F
        'track-title',                  # G
        'track-artist',                 # H
        'ISRC',                         # I
        'track-minutes',                # J
        'track-seconds',                # K
        'rs-track-id',                  # L
        'catalog-no',                   # M
        'album-title',                  # N
        'album-artist',                 # O
        'client-album-id',              # P
        'rs-album-id',                  # Q
        'upc',                          # R
        'product-title',                # S
        'rs-product-id',                # T
        'license-config',               # U
        'region',                       # V
        'base-rate',                    # W
        'rate-%',                       # X
        'share',                        # Y
        'net-rate',                     # Z
        'total-gross-units',            # AA
        'percent-of-sales',             # AB
        'free-goods',                   # AC
        'misc',                         # AD
        'total-reserves',               # AE
        'total-liquidations',           # AF
        'total-returns',                # AG
        'total-carryover',              # AH
        'total-net-units',              # AI
        'total-cc-adjustments',         # AJ
        'license-subtotal',             # AK
        'total-adjustments',            # AL
        'total-advances',               # AM
        'previous-license-balance',     # AN
        'license-balance-forward',      # AO
        'license-adjusted-subtotal',    # AP
        'issuer-license-id',            # AQ
        'issuer-song-id',               # AR
        'rs-license-id',                # AS
        'license-date-modified',        # AT
        'album-custom-1',               # AU
        'album-custom-2',               # AV
        'album-custom-3',               # AW
        'track-custom-1',               # AX
        'track-custom-2',               # AY
        'track-custom-3',               # AZ
    );

    my $header = join( "\t", @headings );
    print $outFile "$header\n";

    # Get the collection of statements for this run.
    #
    my $statements = RPS::DB::Item::CAMechanicalStatement->GetByMechanicalRunID($runID);
    while ( my $statement = $statements->next() ) {

        my $_stmtID = $statement->ca_mechanical_statement_id;

        next if ( $statementID && $_stmtID != $statementID );

        processStatementCSV( $outFile, $_stmtID );
    }

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

    # Create the semaphore
    #
    open SEMAPHORE, "> $semaphore";
    print SEMAPHORE "done\n";
    close SEMAPHORE;

}    #processMechanicalRunCSV

sub processStatementCSV {
    my ( $outFile, $mechanicalStatementID ) = @_;

    # 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'
    );

    # Determine if this is an admin or regular publisher.
    if ( $statement->Publisher()->IsAdmin() == 1 || $statement->Publisher()->IsAgency() == 1 ) {

        # Loop through all publishers for admins.
        my $publisherList = $statement->MechanicalStatementPublisherList()->getList();
        foreach my $publisher (@$publisherList) {
            details( $publisher, $outFile );
        }
    } else {

        # Not an admin, so just do this once.
        details( $statement, $outFile );
    }

}

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

    my %gExport;    # will hold our royalty data export

    my $trackList = $statement->MechanicalStatementTrackList()->getList();
    foreach my $track (@$trackList) {

        # Grab some track data
        my $trackDB = RPS::DB::Item::Track->Lookup(track_id => $track->TrackID);
        my $trackArtist = RPS::DB::Item::Artist->Lookup(artist_id => $trackDB->artist_id);
        my $trackMaster = RPS::DB::Item::Master->Lookup(master_id => $trackDB->master_id);
        my $trackMinutes;
        my $trackSeconds;
        if ($trackMaster) {
            $trackMinutes = floor($trackMaster->duration / 60);
            $trackSeconds = $trackMaster->duration % 60;
        }

        # Grab some album data
        my $albumDB = RPS::DB::Item::Album->Lookup(album_id => $track->AlbumID);
        my $albumArtist = RPS::DB::Item::Artist->Lookup(artist_id => $albumDB->artist_id);

        my %licenseData;    # will contain all license-centric report data for the current track

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

        my $crossedAdvanceTotal    = 0;
        my $crossedAdjustmentTotal = 0;

        if ( @$crossedLicenseList > 0 ) {

            my $balanceTotal = 0;

            # Add the transactions up into two buckets, adjustments and advances.
            #
            my $advanceTotal    = 0;
            my $adjustmentTotal = 0;

            foreach my $license (@$crossedLicenseList)    # Crossed licenses !!!
            {
                my $trackLicenseData = RPS::DB::Item::CATrackLicense->Lookup( ca_track_license_id => $license->TrackLicenseID() );
                my $issuerLicenseID  = $trackLicenseData->issuer_license_id;
                my $licenseID        = $trackLicenseData->ca_track_license_id;

                $licenseData{$licenseID}{cross_collateralized} = $trackLicenseData->cross_collateralized;

                #
                $licenseData{$licenseID}{crossed_previous_advance_balance} = $track->CrossedPreviousAdvanceBalance();
                $licenseData{$licenseID}{crossed_subtotal}                 = $track->CrossedSubtotal();
                $licenseData{$licenseID}{crossed_adjusted_subtotal}        = $track->CrossedAdjustedSubtotal();
                $licenseData{$licenseID}{crossed_advance_balance}          = $track->CrossedAdvanceBalance();

                $licenseData{$licenseID}{adjusted_subtotal} = $license->AdjustedSubtotal();
                $licenseData{$licenseID}{subtotal}          = $license->Subtotal();

                # Get the license transactions tied to this license
                #
                my $xmlObj                  = $license->MechanicalStatementLicenseTransactionList();
                my $licenseTransactionList  = $xmlObj->getList();
                my $licenseTransactionCount = scalar(@$licenseTransactionList);

                if ( $licenseTransactionCount != 0 ) {
                    foreach my $licenseTransaction (@$licenseTransactionList) {
                        if ( $licenseTransaction->TypeCode == 3 ) {
                            $advanceTotal += $licenseTransaction->Amount();
                        } else {
                            $adjustmentTotal += $licenseTransaction->Amount();
                        }
                    }
                }

                $licenseData{$licenseID}{advance_total}    = $advanceTotal;
                $licenseData{$licenseID}{adjustment_total} = $adjustmentTotal;

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

                if ( $incomeItemListLength != 0 ) {

                    # If there are income items, process them all and aggregate
                    # the following data:
                    #  - gross units
                    #  - reserves held
                    #  - reserves liquidated
                    #  - returns
                    #  - carryover
                    #  - net units
                    #  - cc adjustments (crossed adjustments)
                    #

                    foreach my $incomeItem (@$incomeItemList) {
                        $licenseData{$licenseID}{net_units} += $incomeItem->NetUnits();

                        #$licenseData{$licenseID}{gross_units} += $incomeItem->GrossUnits();
                        $licenseData{$licenseID}{gross_units} += $incomeItem->Sales();

                        $licenseData{$licenseID}{reserved}   += $incomeItem->Reserved();
                        $licenseData{$licenseID}{liquidated} += $incomeItem->Liquidated();
                        $licenseData{$licenseID}{carryover}  += $incomeItem->Carryover();
                        $licenseData{$licenseID}{returns}    += $incomeItem->Returns();

                        $licenseData{$licenseID}{upc}        = $incomeItem->UPC()       if ( $incomeItem->UPC() );
                        $licenseData{$licenseID}{product_id} = $incomeItem->ProductID() if ( $incomeItem->ProductID() );

                        $licenseData{$licenseID}{base_rate}  = $incomeItem->BaseRate()  if $incomeItem->BaseRate();
                        $licenseData{$licenseID}{net_rate}   = $incomeItem->NetRate()   if $incomeItem->NetRate();
                    }    #income item loop

                }    #income item list block

            }    # license loop

        }    #crossedLicenseList loop

        # Calculate the crossed advances and/or adjustments
        #
        # Note: these transactions are for ALL crossed licenses attached
        # to the track.
        #
        my $xmlObj                  = $track->MechanicalStatementCrossedLicenseTransactionList();
        my $licenseTransactionList  = $xmlObj->getList();
        my $licenseTransactionCount = scalar(@$licenseTransactionList);

        if ( $licenseTransactionCount != 0 ) {
            foreach my $licenseTransaction (@$licenseTransactionList) {
                if ( $licenseTransaction->TypeCode == 3 ) {
                    $crossedAdvanceTotal += $licenseTransaction->Amount();
                } else {
                    $crossedAdjustmentTotal += $licenseTransaction->Amount();
                }
            }
        }

        #-------------------------------------------------------
        #
        #  U N C R O S S E D    L I C E N S E    S E C T I O N
        #
        #-------------------------------------------------------

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

            my $licenseID = $license->TrackLicenseID;

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

            # Get the mechanical statement license totals for the license
            #

            $licenseData{$licenseID}{cross_collateralized} = $trackLicenseData->cross_collateralized;

            $licenseData{$licenseID}{previous_advance_balance} = $license->PreviousAdvanceBalance();
            $licenseData{$licenseID}{subtotal}                 = $license->Subtotal();
            $licenseData{$licenseID}{adjusted_subtotal}        = $license->AdjustedSubtotal();
            $licenseData{$licenseID}{advance_balance}          = $license->AdvanceBalance();

            # Get the income items associated with this license
            #
            my $incomeItemList       = $license->MechanicalStatementItemList()->getList();
            my $incomeItemListLength = scalar(@$incomeItemList);

            # If there are income items, aggregate some totals
            #
            if ( $incomeItemListLength != 0 ) {

                # Process the mechanical statement items tied to this license,
                # aggregating totals along the way.
                #

                foreach my $incomeItem (@$incomeItemList) {
                    my $licenseID = $incomeItem->TrackLicense->TrackLicenseID;
                    $licenseData{$licenseID}{net_units} += $incomeItem->NetUnits();

                    #$licenseData{$licenseID}{gross_units} += $incomeItem->GrossUnits();
                    $licenseData{$licenseID}{gross_units} += $incomeItem->Sales();

                    $licenseData{$licenseID}{reserved}   += $incomeItem->Reserved();
                    $licenseData{$licenseID}{liquidated} += $incomeItem->Liquidated();
                    $licenseData{$licenseID}{carryover}  += $incomeItem->Carryover();
                    $licenseData{$licenseID}{returns}    += $incomeItem->Returns();

                    $licenseData{$licenseID}{upc}        = $incomeItem->UPC()       if ( $incomeItem->UPC() );
                    $licenseData{$licenseID}{product_id} = $incomeItem->ProductID() if ( $incomeItem->ProductID() );

                    $licenseData{$licenseID}{base_rate}  = $incomeItem->BaseRate()  if $incomeItem->BaseRate();
                    $licenseData{$licenseID}{net_rate}   = $incomeItem->NetRate()   if $incomeItem->NetRate();
                }
            }    # income item list block

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

            # Add the transactions up into two buckets, adjustments and advances.
            #
            my $advanceTotal    = 0;
            my $adjustmentTotal = 0;

            if ( $licenseTransactionCount != 0 ) {
                foreach my $licenseTransaction (@$licenseTransactionList) {
                    my $transactionType;
                    if ( $licenseTransaction->TypeCode == 3 ) {
                        $advanceTotal += $licenseTransaction->Amount();
                    } else {
                        $adjustmentTotal += $licenseTransaction->Amount();
                    }
                }
            }

            $licenseData{$licenseID}{advance_total}    = $advanceTotal;
            $licenseData{$licenseID}{adjustment_total} = $adjustmentTotal;

        }    # uncrossed license list block

        # Output the report lines
        #
        foreach my $licenseID ( keys %licenseData ) {
            my $licenseObj        = RPS::DB::Item::CATrackLicense->Lookup( ca_track_license_id => $licenseID );
            my $productTypeID     = $licenseObj->product_type_id;
            my $share             = $licenseObj->share;
            my $ratePercentage    = $licenseObj->rate_percentage;
            my $issuerLicenseID   = $licenseObj->issuer_license_id;
            my $issuerSongID      = $licenseObj->issuer_song_id;
            my $regionID          = $licenseObj->region_id;
            my $dateModified      = $licenseObj->date_modified;
            my $percentageOfSales = $licenseObj->percentage_of_sales;
            my $freeGoods         = $licenseObj->free_goods || 0;
            my $miscDeduction     = $licenseObj->misc_deduction || 0;

            my $publisherObj = RPS::DB::Item::CAPublisher->Lookup( ca_publisher_id => $licenseObj->ca_publisher_id );

            my $publisherClientAccountID = $publisherObj->client_account_id;
            my $adminName                = _getAdminName($publisherObj);
            my $agentName                = _getAgentName($publisherObj);
            my $publisherType            = _getPublisherType($publisherObj);

            my $cross_collateralized = $licenseData{$licenseID}{cross_collateralized};

            my $previousAdvanceBalance;
            my $subtotal;
            my $adjustedSubtotal;
            my $licenseBalanceForward;

            if ($cross_collateralized) {
                $previousAdvanceBalance = $licenseData{$licenseID}{crossed_previous_advance_balance};

                my $crossedSubtotal         = $licenseData{$licenseID}{crossed_subtotal};
                my $crossedAdjustedSubtotal = $licenseData{$licenseID}{crossed_adjusted_subtotal};

                $subtotal = $licenseData{$licenseID}{subtotal};

                $adjustedSubtotal = $licenseData{$licenseID}{adjusted_subtotal};

                $licenseBalanceForward = $licenseData{$licenseID}{crossed_advance_balance};

                if ( ( $previousAdvanceBalance != 0 ) || ( $crossedSubtotal != $crossedAdjustedSubtotal ) ) {
                    $adjustedSubtotal = $crossedAdjustedSubtotal;
                }
            } else {
                $previousAdvanceBalance = $licenseData{$licenseID}{previous_advance_balance};
                $subtotal               = $licenseData{$licenseID}{subtotal};
                $adjustedSubtotal       = $licenseData{$licenseID}{adjusted_subtotal};
                $licenseBalanceForward  = $licenseData{$licenseID}{advance_balance};
            }

            my $advanceTotal    = $licenseData{$licenseID}{advance_total};
            my $adjustmentTotal = $licenseData{$licenseID}{adjustment_total};

            my $licenseConfig = RPS::DB::Item::Product->ProductTypeIDToString($productTypeID);

            my $albumTitle = $track->AlbumName();

            my $productTitle = '';
            my $productID = $licenseData{$licenseID}{product_id};
            if ($productID) {
                my $product = RPS::DB::Item::Product->Lookup( product_id => $productID );
                $productTitle = _getProductTitle($product);
            }

            my @reportRow = (
                $statement->Publisher()->PublisherName(),    # A - publisher-name
                $publisherClientAccountID,                   # B - client-no
                $statement->Publisher()->PublisherID(),      # C - rs-payee-id
                $publisherType,                              # D - publisher-type
                $adminName,                                  # E - publisher-admin
                $agentName,                                  # F - publisher-agent
                $track->SongTitle(),                         # G - track-title
                $trackArtist->name,                          # H - track-artist
                $track->ISRC(),                              # I - isrc
                $trackMinutes,                               # J - track-minutes
                $trackSeconds,                               # K - track-seconds
                $track->TrackID(),                           # L - rs-track-id
                $track->CatalogNumber(),                     # M - catalog-no
                $albumTitle,                                 # N - album-title
                $albumArtist->name,                          # O - album-artist
                $albumDB->client_album_id,                   # P - client-album-id
                $track->AlbumID(),                           # Q - rs-album-id
                $licenseData{$licenseID}{upc},               # R - upc
                $productTitle,                               # S - product-title
                $productID,                                  # T - rs-product-id
                $licenseConfig,                              # U - license-config
                regionIDToName($regionID),                   # V - region
                $licenseData{$licenseID}{base_rate},         # W - base-rate
                formatPercent($ratePercentage),              # X - rate-%
                formatPercent($share),                       # Y - share
                $licenseData{$licenseID}{net_rate},          # Z - net-rate
                $licenseData{$licenseID}{gross_units},       # AA - total-gross-units
                formatPercent($percentageOfSales),           # AB - percent-of-sales
                formatPercent($freeGoods),                   # AC - free-goods
                formatPercent($miscDeduction),               # AD - misc
                $licenseData{$licenseID}{reserved},          # AE - total-reserves
                $licenseData{$licenseID}{liquidated},        # AF - total-liquidations
                $licenseData{$licenseID}{returns},           # AG - total-returns
                $licenseData{$licenseID}{carryover},         # AH - total-carryover
                $licenseData{$licenseID}{net_units},         # AI - total-net-units
                $crossedAdjustmentTotal,                     # AJ - total-cc-adjustments (NB: we don't show crossedAdvanceTotal)
                formatMoney($subtotal),                      # AK - license-subtotal (current period license subtotal)
                formatMoney($adjustmentTotal),               # AL - total-adjustments
                formatMoney($advanceTotal),                  # AM - total-advances
                formatMoney($previousAdvanceBalance),        # AN - previous-license-balance
                formatMoney($licenseBalanceForward),         # AO - license-balance-foward
                formatMoney($adjustedSubtotal),              # AP - license-adjusted-subtotal
                $issuerLicenseID,                            # AQ - issuer-license-id
                $issuerSongID,                               # AR - issuer-song-id
                $licenseID,                                  # AS - rs-license-id
                $dateModified,                               # AT - date-modified
                $albumDB->custom_1,                          # AU - album-custom-1
                $albumDB->custom_2,                          # AV - album-custom-2
                $albumDB->custom_3,                          # AW - album-custom-3
                $trackDB->custom_1,                          # AX - track-custom-1
                $trackDB->custom_2,                          # AY - track-custom-2
                $trackDB->custom_3,                          # AZ - track-custom-3
            );
            my $joinedReportRow = join( "\t", @reportRow );
            print $outFile "$joinedReportRow\n";
        }    #license aggregated data loop

    }    # track loop
}    #details

# For now, we are not realy going to be doing any formatting of numbers.
#

sub formatNumber {
    my ($value) = @_;

    #$value = Formats::formatNumber($value);

    return $value;
}

sub formatMoney {
    my ($value) = @_;

    #$value = Formats::formatMoney($value);

    return $value;
}

sub formatPercent {
    my ($value) = @_;

    #$value = Formats::formatPercent($value);

    return $value;
}

# 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 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 _getProductTitle {
    my ($product) = @_;

    my $productTitle = $product->title;

    # If this is a track product, we need to get the title from the parent.
    if ( $product->product_type_id == RPS::DB::Item::Product::kProductTypeDigitalTrack && $product->parent_product_id ) {
        my $parentProduct = RPS::DB::Item::Product->Lookup( product_id => $product->parent_product_id );
        $productTitle = $parentProduct->title;
    }

    return $productTitle;
}

sub _getPublisherType {
    my ($publisher) = @_;
    assert($publisher);

    if ( $publisher->is_agency ) {
        return "Agent";
    } elsif ( $publisher->is_admin ) {
        return "Admin";
    } else {
        return "Standard";
    }
}

sub _getAdminName {
    my ($publisher) = @_;
    assert($publisher);
    my $name;
    if ( $publisher->admin_id ) {
        my $o = RPS::DB::Item::CAPublisher->Lookup( ca_publisher_id => $publisher->admin_id, );
        $name = $o->publisher_name;
    }
    return $name;
}

sub _getAgentName {
    my ($publisher) = @_;
    assert($publisher);
    my $name;
    if ( $publisher->agent_id ) {
        my $o = RPS::DB::Item::CAPublisher->Lookup( ca_publisher_id => $publisher->agent_id, );
        $name = $o->publisher_name;
    }
    return $name;
}

#
# Boring script stuff below...
#

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

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

    if ( !$opt{r} || !$opt{c} ) {
        usage();
        exit(1);
    }
    $settings->{mechanicalRunID}       = $opt{r};
    $settings->{clientID}              = $opt{c};
    $settings->{outputPath}            = $opt{p};
    $settings->{mechanicalStatementID} = $opt{s};

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

sub usage {
    print STDERR "\nusage: $0 -c <client_id> -r <ca_mechanical_run_id> [-p <output path>]\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-r <ca_mechanical_run_id>\tThe id of the CA mechanical run to generate export data for\n";
    print STDERR "\t-p <output path>\tThe output path. Optional. If not provided, use current directory.\n";
}

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

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

