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

use PDF::API2;

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 lib '/app/tools/rps/lib';
use RPS::RoyaltyRun::Status;
use RPS::Statement::Label::StatementFull;
use RPS::Payor::Payor;
use RPS::LabelPayee::LabelPayee;
use RPS::LabelRoyalty::LabelRoyaltyRun;

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

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


#
# A lot of this code is taken from this tutorial: http://rick.measham.id.au/pdf-api2/
#


# These constants will make it easier to convert between 'regular' units
# and postscript points.
# There are 72 postscript points in an inch, and 25.4 millimeters in an inch.
# All the PDF::API2 methods expect their size or coordinate arguments to be in points.
#
use constant mm => (25.4 / 72);
use constant in => (1 / 72);
use constant pt => 1;


# The standard page dimensions.  Note that we're creating _landscape_ docs.
#
use constant kPageHeight    => (8.5/in);
use constant kPageWidth     => (11/in);


# The margins of the page.
# Remember that (0,0) in PDF coordinates is the bottom-left of the page.
#
use constant kLeftMargin    => 0.5/in;
use constant kBottomMargin  => 0.5/in;
use constant kRightMargin   => (kPageWidth - (0.5/in));
use constant kTopMargin     => (kPageHeight - (0.5/in));


# We are going to keep track of every page we create, so that we
# can go back later and add page numbers
#
my @gPages;


# We'll store a hashref with font info here, once we have a PDF object to work with.
#
my $font;


# 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 PDF!
#
my %options;
parseCommandLine(\%options);
createStatementPDF($options{clientID}, $options{labelStatementID}, $options{outputFile});


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




sub createStatementPDF
{
    my ($clientID, $labelStatementID, $outFilePath) = @_;

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


    # Instantiate the ArtistStatement object.
    # This object will contain all the info we need to output the statement document.
    #
    my $statement = RPS::Statement::Label::StatementFull->new(labelRoyaltyStatementID => $labelStatementID);


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


    # Instantiate the PDF object.
    #
    my $pdf = PDF::API2->new(-file => $outFilePath);


    # Fetch the fonts that we might want to use.
    # Note that every time we define a font, it will get embedded in the document,
    # so we will grab them all here at the very beginning.
    # !!! Be sure to remove any of these we don't actually need...
    #
    # (These are the 'built-in' fonts that all pdf documents get for free. We can embed fancy
    #  fonts if we want to, but that will make the statement files larger...)
    #
    $font = 
    {
        Helvetica =>
        {
            Bold    => $pdf->corefont('Helvetica-Bold',     -encoding => 'latin1'),
            Roman   => $pdf->corefont('Helvetica',          -encoding => 'latin1'),
            Italic  => $pdf->corefont('Helvetica-Oblique',  -encoding => 'latin1'),
        },
        Times =>
        {
            Bold    => $pdf->corefont('Times-Bold',     -encoding => 'latin1'),
            Roman   => $pdf->corefont('Times',          -encoding => 'latin1'),
            Italic  => $pdf->corefont('Times-Italic',   -encoding => 'latin1'),
        },
    };

    
    # Declare the 'cursor' coordinates.  As we go, we'll be updating these values so that the
    # next element shows up in the right place.
    #
    my $x = kLeftMargin;
    my $y = kTopMargin;

    # Create the first (blank) page.
    # Each output subroutine will take the current page as a parameter, and will
    # return the page that they ended on.
    #
    my $page = newPage($pdf);
    
    
	# Add label logo to the first page, if desired
	#	
	my $payor = $statement->Payor();
	my $showLogo = $payor->ShowLogo();
		 
    if ($showLogo == 1) 
    {
         my $clientNameClean = Common::Client::Current()->ClientNameClean();
    	($pdf, $page) = EmbedImage::labelLogo($pdf, $page, $clientNameClean, kTopMargin, kRightMargin);
    }    


    # Each section of the statement will have its own subroutine.
    #
    ($x, $y, $page) = header($pdf, $statement, $x, $y, $page);
    ($x, $y, $page) = summary($pdf, $statement, $x, $y, $page);
    ($x, $y, $page) = details($pdf, $statement, $x, $y, $page);


    # Now add the page numbers, and other 'footer' stuff
    #
    addFooter($pdf);


    # If the state of the run is not 'COMMITTED' or 'CLOSED', then we want to add a watermark 
    # to the pages so that our users don't mail this statement out.
    #
   	my $run = RPS::LabelRoyalty::LabelRoyaltyRun->new(labelRoyaltyRunID => $statement->LabelRoyaltyRunID(), loadSubs => 0);
    if (RPS::RoyaltyRun::Status::kCommitted != $run->Status()
     && RPS::RoyaltyRun::Status::kClosed != $run->Status())
    {
        addDraftWatermark($pdf);
    }


    # All done, save and clean up
    #
    $pdf->save();
    $pdf->end();
}


sub header
{
    my ($pdf, $statement, $x, $y, $page) = @_;

    my $text = $page->text();

    # Step 1 - Put the text 'Label Royalty Statement' at the top of the page.
    #
    $y = printTextCentered($text, $y, 'Label Royalty Statement', $font->{Helvetica}{Bold}, 12/pt);
    
#    report("payor: " . Dumper($statement->{Payor}));


    # Print the 'From: Payor' info
    #
    my $payor = $statement->Payor();
 
    my $cityStateLine = $payor->City();
    if ($payor->City() && $payor->StateProvince())
    {
    	$cityStateLine .= ","; 
    }
    $cityStateLine .= $payor->StateProvince();
    
    if ($payor->PostalCode())
    {        
        $cityStateLine .=  " " . $payor->PostalCode();   
    }

    $y = printText($text, $x, $y, 'From:', $font->{Helvetica}{Roman}, 9/pt);
    $y = printText($text, $x, $y, $payor->Name(), $font->{Helvetica}{Roman}, 9/pt);
    $y = printText($text, $x, $y, $payor->StreetAddress(), $font->{Helvetica}{Roman}, 9/pt);
    $y = printText($text, $x, $y, $payor->StreetAddress2(), $font->{Helvetica}{Roman}, 9/pt);
    $y = printText($text, $x, $y, $payor->StreetAddress3(), $font->{Helvetica}{Roman}, 9/pt);
    $y = printText($text, $x, $y, $cityStateLine, $font->{Helvetica}{Roman}, 9/pt);
    $y = printText($text, $x, $y, $payor->CountryCode(), $font->{Helvetica}{Roman}, 9/pt);

    # Add in some space, then print the 'To:' info
    #
    $y -= 9/pt;

    my $payee = $statement->LabelPayee();
    
    my $cityStateLine = $payee->City();
    if ($payee->City() && $payee->StateProvince())
    {
    	$cityStateLine .= ","; 
    }
    $cityStateLine .= $payee->StateProvince();  
    
    if ($payee->PostalCode())
    {
        $cityStateLine .= " " . $payee->PostalCode(); 
    } 

    $y = printText($text, $x, $y, $payee->Name(), $font->{Helvetica}{Roman}, 9/pt);
    $y = printText($text, $x, $y, $payee->StreetAddress(), $font->{Helvetica}{Roman}, 9/pt);
    $y = printText($text, $x, $y, $payee->StreetAddress2(), $font->{Helvetica}{Roman}, 9/pt);
    $y = printText($text, $x, $y, $payee->StreetAddress3(), $font->{Helvetica}{Roman}, 9/pt);
    $y = printText($text, $x, $y, $cityStateLine, $font->{Helvetica}{Roman}, 9/pt);
    $y = printText($text, $x, $y, $payee->CountryCode(), $font->{Helvetica}{Roman}, 9/pt);
		
    # Now print the run label. Which means we need to fetch the run...
    #
    my $run = RPS::LabelRoyalty::LabelRoyaltyRun->new(labelRoyaltyRunID => $statement->LabelRoyaltyRunID(), loadSubs => 0);
    $y -= 9/pt;
    $y = printText($text, $x, $y, $run->Label(), $font->{Helvetica}{Bold}, 9/pt);

    $y -= 18/pt;

    return ($x, $y, $page);
}



sub summary
{
    my ($pdf, $statement, $x, $y, $page) = @_;


    # The PDF::Table class doesn't seem to work correctly if there is more than
    # 1 table on a page.  So, going to have to draw this in myself.
    #
    ($x, $y, $page) = drawBalanceTable($pdf, $statement, $x, $y, $page);

    $y -= 18;

    return ($x, $y, $page);
}

sub drawBalanceTable
{
    my ($pdf, $statement, $x, $y, $page) = @_;
    my $fontSize = 7/pt;

    my $text = $page->text();

    
    # We'll create a 2-d array that contains the data we want to display.
    #
    my @balanceArray;


    # This array will keep track of various row properties.
    # We're going to change the font for a couple of rows (such as the header),
    # and do a few more tricks.
    #
    my @rowProperties;

    
    # The column headers
    #
    push @balanceArray, [' ', 'Amount', 'Check #', 'Date', 'Memo'];
    push @rowProperties, 
    { 
        font => $font->{Helvetica}{Bold},
        repeat => 1,    # !!! This is a special flag that only affects the header line.
                        # !!! It tells the Table class to repeat the header on new pages.
    };


    # The first line
    #
    push @balanceArray, ["Previous Period Balance", formatMoney($statement->PreviousBalance()), ' ', ' ', ' '];
    push @rowProperties, { };


    # Get any transactions
    #
    my $transactionList = $statement->LabelStatementTransactionList();
    if ($transactionList)
    {
        my $list = $transactionList->getList();
        foreach my $transaction (@$list)
        {
            my $type;
            if ($transaction->TypeCode() == 2)
            {
                $type = 'Adjustment';
            }
            elsif ($transaction->TypeCode() == 3)
            {
                $type = 'Advance';
            }
            elsif ($transaction->TypeCode() == 4)
            {
                $type = 'Payment';
            }
            my $amount = formatMoney($transaction->Amount());
            $amount = ' ' unless defined $amount;
            my $checkNum = $transaction->CheckNumber();
            $checkNum = ' ' unless defined $checkNum;
            my $date = $transaction->TransactionDate();
            $date = ' ' unless defined $date;
            my $memo = $transaction->Memo();
            $memo = ' ' unless defined $memo;

            push @balanceArray, [$type, $amount, $checkNum, $date, $memo];
            push @rowProperties, { };
        }
    }


    push @balanceArray, ['Current Period Royalties:', formatMoney($statement->Total()), ' ', ' ', ' '];
    push @rowProperties, 
    { 
        lines => 
        [
            { 
                # pen_size => 1,
                # color => 'black',
                start_col => 0,
                end_col => 1,
                top_pad => 4,
                # bottom_pad => 2,
            },
        ],
    };


    push @balanceArray, ['Ending Balance:', formatMoney($statement->Balance()), ' ', ' ', ' '];
    push @rowProperties, { font => $font->{Helvetica}{Bold} };

    push @balanceArray, [' ', ' ', ' ', ' ', ' '];
    push @rowProperties, { };

    push @balanceArray, ['Minimum Payment:', formatMoney($statement->MinPayment()), ' ', ' ', ' '];
    push @rowProperties, { };

    my $tableObj = TableObj->new
    (
        $pdf, $page, \@balanceArray,
        bottom_margin => kBottomMargin+20,   # adding a bit of padding to avoid weirdness
        new_page_y => kTopMargin-20,         # ditto
        new_page_func => \&newPage,
        font => $font->{Helvetica}{Roman},
        font_size => $fontSize,
        column_props =>
        [
            {
                font => $font->{Helvetica}{Bold},
                font_size => $fontSize,
                min_w => 1.25/in,
                max_w => 1.25/in,
#                justify => 'center',
            },
            {
                font => $font->{Helvetica}{Roman},
                font_size => $fontSize,
                justify => 'right',
                min_w => 1.25/in,
                max_w => 1.25/in,
            },
            {
                font => $font->{Helvetica}{Roman},
                font_size => $fontSize,
#                justify => 'right',
                min_w => 1.0/in,
                pad => (1/4)/in,
            },
            {
                font => $font->{Helvetica}{Roman},
                font_size => $fontSize,
#                justify => 'right',
                min_w => 1.0/in,
            },
            {
                font => $font->{Helvetica}{Roman},
                font_size => $fontSize,
                #justify => 'right',
                min_w => 1.0/in,
            },
        ],
        row_props => \@rowProperties,
    );


    ($page, $y) = $tableObj->print($x, $y);

		$y -= 2;

    my @amountDueArray;
    my @amountDueProperties;
		
    push @amountDueArray, [' ', ' ', ' '];
    push @amountDueProperties, 
    { 
        lines => 
        [
            { 
                # pen_size => 1,
                # color => 'black',
                start_col => 0,
                end_col => 2,
                top_pad => 2,
                bottom_pad => 0,
            },
        ],
    };

    push @amountDueArray, ['Amount Payable:', formatMoney($statement->AmountDue), ' ('.Common::Client::Current()->Locale()->currencyFormat()->currencyCode().')'];
    push @amountDueProperties, 
	{
        lines => 
        [
            { 
                # pen_size => 1,
                # color => 'black',
                start_col => 0,
                end_col => 2,
                top_pad => 5,
                bottom_pad => 0,
            },
        ],
	};
    my $bigFontSize = 10/pt;

    my $tableObj = TableObj->new
    (
        $pdf, $page, \@amountDueArray,
        bottom_margin => kBottomMargin+20,   # adding a bit of padding to avoid weirdness
        new_page_y => kTopMargin-20,         # ditto
        new_page_func => \&newPage,
        font => $font->{Helvetica}{Roman},
        font_size => $bigFontSize,
        column_props =>
        [
            {
                font => $font->{Helvetica}{Bold},
                font_size => $bigFontSize,
                min_w => 1.25/in,
                max_w => 1.25/in,
            },
            {
                font => $font->{Helvetica}{Bold},
                font_size => $bigFontSize,
                justify => 'right',
                min_w => 1.25/in,
                max_w => 1.25/in,
            },
            {
                font => $font->{Helvetica}{Bold},
                font_size => $bigFontSize,
                justify => 'left',
                min_w => 1.0/in,
            },
        ],
        row_props => \@amountDueProperties,
    );


    ($page, $y) = $tableObj->print($x, $y);

    return ($x, $y, $page);
}



sub details
{
    my ($pdf, $statement, $x, $y, $page) = @_;
    my $fontSize = 7/pt;

    my $text = $page->text();  

		my @labelRows;
    # This array will keep track of various row properties.
    # We're going to change the font for a couple of rows (such as the header),
    # and do a few more tricks.
    #
    my @rowProps;

    
    # The column headers
    #
    push @labelRows, ['Label', 'Service', 'Country', 'Distribution Rate', 'Gross Sales', 'Distribution Fee', 'Net Sales'];
    push @rowProps, 
    { 
        font => $font->{Helvetica}{Bold},
        repeat => 1,    # !!! This is a special flag that only affects the header line.
                        # !!! It tells the Table class to repeat the header on new pages.
        lines => 
        [
            { 
                # pen_size => 1,
                # color => 'black',
                start_col => 0,
                end_col => 6,
                top_pad => 4,
                # bottom_pad => 2,
            },
        ],                        
    };


    my $labelList = $statement->LabelStatementLabelList()->getList();
    
    # We need to print out some totals at the end,
    # so let's capture them here.
    my $grossSalesTotal;
    my $feeTotal;
    
  	foreach my $label (@$labelList)
  	{    
  		$grossSalesTotal += $label->GrossSales();
  		$feeTotal += $label->Fee();
      
      push @labelRows,
      [
          $label->Label->LabelName(),        
          $label->ServiceName(),
          $label->CountryName(),
          formatPercent($label->DistributionFee()),
          formatMoney($label->GrossSales()),
          formatMoney($label->Fee()),
          formatMoney($label->NetSales()),
      ];

      push @rowProps, {};
    }

    # We want a little line under the last label row.
    #
    my $numRows = scalar(@rowProps);
    my $lastRowPropHashref = @rowProps[($numRows - 1)];
    $lastRowPropHashref->{lines} = 
    [
        { 
            start_col => 0,
            end_col => 6,
            top_pad => 4,
            # bottom_pad => 2,
        },
    ];    


		# And now we want the grand totals.
    push @labelRows,
    [
        'Total:',
        '',
        '',
        '',
        formatMoney($grossSalesTotal),
        formatMoney($feeTotal),
        formatMoney($statement->Total()),
    ];

    push @rowProps, {};


    my $tableObj = TableObj->new
    (
        $pdf, $page, \@labelRows,
        bottom_margin => kBottomMargin+20,   # adding a bit of padding to avoid weirdness
        new_page_y => kTopMargin-20,         # ditto
        new_page_func => \&newPage,
        font => $font->{Helvetica}{Roman},
        font_size => $fontSize,
        column_props =>
        [
            {   # label
                font => $font->{Helvetica}{Bold},
                font_size => $fontSize,
                min_w => 2.75/in,
                max_w => 2.75/in,
                justify => 'left',
            },
            {   # service
                font => $font->{Helvetica}{Roman},
                font_size => $fontSize,
                justify => 'left',
                min_w => 1.25/in,
                max_w => 1.25/in,
            },
            {   # country
                font => $font->{Helvetica}{Roman},
                font_size => $fontSize,
                justify => 'left',
                min_w => 1.25/in,
                max_w => 1.25/in,
            },            
            {   # dist rate
                font => $font->{Helvetica}{Roman},
                font_size => $fontSize,
                justify => 'right',
                min_w => 1.00/in,
                max_w => 1.00/in,
            },
            {   # gross sales
                font => $font->{Helvetica}{Roman},
                font_size => $fontSize,
                justify => 'right',
                min_w => 1.25/in,
                max_w => 1.25/in,
            },
            {   # dist fee
                font => $font->{Helvetica}{Roman},
                font_size => $fontSize,
                justify => 'right',
                min_w => 1.25/in,
                max_w => 1.25/in,
                #pad => (1/4)/in,
            },
            {   # net sales
                font => $font->{Helvetica}{Roman},
                font_size => $fontSize,
                justify => 'right',
                min_w => 1.25/in,
                max_w => 1.25/in,
            },
        ],
        row_props => \@rowProps,
    );


    ($page, $y) = $tableObj->print($x, $y);

    return ($x, $y, $page);
}


sub addFooter
{
    my ($pdf) = @_;

    my $pageCount = 1;
    my $numPages = scalar @gPages;
    foreach my $page (@gPages)
    {
        my $text = $page->text;
        printTextCentered($text, kBottomMargin, "$pageCount of $numPages", $font->{Helvetica}{Roman}, 12/pt);
        $pageCount++;
    }
}


sub addDraftWatermark
{
    my ($pdf) = @_;

    my $centerX = kPageWidth / 2;
    my $centerY = kPageHeight / 2;

    foreach my $page (@gPages)
    {
        my $text = $page->text(1);
        $text->font($font->{Helvetica}{Bold}, 128/pt);
        $text->transform(
         -translate => [ $centerX, $centerY ],
         -rotate => 45
        );

        $text->fillcolor('lightgray');
        $text->text_center('DRAFT');
        $text->fillcolor('black');
    }
}


# All the pages will _probably_ need the same settings.
#
sub newPage
{
    my ($pdf) = @_;

    my $page = $pdf->page;

    # the mediabox is the size of the paper.
    #
    $page->mediabox(kPageWidth, kPageHeight);

    # the cropbox defines the margins, essentially.
    # the args are the coordinates for the left, bottom, right, and top (in that order)
    #

    # !!! Rather than set the cropbox right to the margins, I am going to make it larger.
    # !!! Basically, I want to have this thing render in the viewer with the apperance of having
    # !!! margins.
    #
#    $page->cropbox(kLeftMargin, kBottomMargin, kRightMargin, kTopMargin);
    $page->cropbox(5, 5, kPageWidth - 5, kPageHeight - 5);


    # Not currently declaring a 'bleedbox' or an 'artbox'.  Check out the tutorial if you want to
    # know what those are... the url for that is at the top of this file.
    #
    push @gPages, $page;

    return $page;
}


# A helper routine to print some text centered.
# 'y' will tell it where to start - 'x' is basically ignored.
#
sub printTextCentered
{
    my ($text, $y, $textToPrint, $fontToUse, $fontSize, $color) = @_;

    $color = 'black' unless $color;

    $text->font($fontToUse, $fontSize);
    $text->fillcolor($color);

    my @strings = split(/\n/, $textToPrint);
    foreach my $string (@strings)
    {
    		# Remove any carriage returns that are left over from the new line splitting above.
				$string =~ s/\r//g;  
				    	
        # Calculate how wide this string will be.
        #
        my $stringWidth = $text->advancewidth($string);

        $y -= $fontSize;

        # Calculate where 'X' needs to be
        #
        my $x = ((kRightMargin - kLeftMargin)/2) + kLeftMargin - ($stringWidth / 2);
   
        $text->translate($x, $y);
        $text->text($string);

        # Move the cursor down the page.
        # add a little bitty bit of padding
        $y -= 1;
    }

    return $y;
}


# This just prints a line of text, left justified to the left margin
#
sub printText
{
    my ($text, $x, $y, $textToPrint, $fontToUse, $fontSize, $color) = @_;

    $color = 'black' unless $color;

    $text->font($fontToUse, $fontSize);
    $text->fillcolor($color);

    my @strings = split(/\n/, $textToPrint);
    foreach my $string (@strings)
    {
    		# Remove any carriage returns that are left over from the new line splitting above.
				$string =~ s/\r//g;      	
    	
        # Calculate how wide this string will be.
        #
        my $stringWidth = $text->advancewidth($string);

        $y -= $fontSize;

        $text->translate($x, $y);
        $text->text($string);

        # Move the cursor down the page.
        # add a little bitty bit of padding
        $y -= 1;
    }

    return $y;
}


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;
}


#
# 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->{labelStatementID} = $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 <label_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-r <label_statement_id>\tThe id of the label royalty statement to convert to pdf\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";
    }
}


