#!/usr/bin/perl
use strict;
use Data::Dumper;
use lib '/app/tools/common/lib';
use lib '/app/tools/rps/lib';
use Common::RSApp;
use Common::WriteXML;
use RPS::DB::Item::Payor;
use RPS::DB::Item::ArtistRoyaltyRun;
use RPS::DB::Item::LabelRoyaltyRun;
use RPS::DB::Item::MechanicalRun;
use RPS::DB::Item::UKMechanicalRun;
use RPS::RoyaltyRun::Status;


# To make this sample code run, we need an Application singleton.
# We'll use C_RSDEMO as the client id.
#
my $app = Common::RSApp->new(clientID => 202);

my $xml = getRunTypeStuff();

print "Here's the data structure:" . Dumper($xml) . "\n";

print "... And here is the corresponding XML:\n";
print Common::WriteXML::GetXMLString($xml) . "\n";


sub getRunTypeStuff
{
    # First, we can declare an empty hash.  This method will return this hash by reference.
    #
    my %returnHash;

    # Rather than build joins, I'm going to read the whole payor table in at once and cache it in a hash.
    # I find this easier to grok, personally, and the payor table is not very large...
    #
    my %payorCache;
    my $allPayors = RPS::DB::Item::Payor->GetAll();
    while (my $payor = $allPayors->next())
    {
        # We'll use the payor_id as the key, and the name as the hash value.
        #
        $payorCache{ $payor->payor_id() } = $payor->name();
    }


    # Declaring these way out here... We will use these two variables a few times to traverse hashes.
    #
    my ($key, $value);


    # Since we're going to be returning _every_ completed (or commited or closed) run, I would
    # just iterate over a single collection and build the nested hashes as we go.
    #
    # So, here's how I would do this for artist runs.
    #
    my $allArtistRuns = RPS::DB::Item::ArtistRoyaltyRun->GetAll(); 
    #
    # Get all the runs.   Now, if we had a 'GetAllCompletedRuns' method, I'd use that instead, so I could skip
    # the test of 'status' in the following loop.  But this certainly works...

    # There are a few ways to go here... I think we want a 'list' of <Payor> blocks.  The easiest
    # way to do that will be to build up a temporary hash (keyed by payor_id) containing Arrays of
    # runs. Then at the end of this loop we'll iterate over that and shove things into the 'return hash'.
    #
    my %artistPayors;

    while (my $artistRun = $allArtistRuns->next())
    {
        if (RPS::RoyaltyRun::Status::kComplete != $artistRun->status()
         && RPS::RoyaltyRun::Status::kCommitted != $artistRun->status()
         && RPS::RoyaltyRun::Status::kClosed != $artistRun->status())
        {
            # Skip over runs that are not complete, committed, or closed.
            #
            next;
        }

        # Let's de-reference some fields to make this easier to read.
        #
        my $payorID = $artistRun->payor_id();
        my $label = $artistRun->label();
        my $runID = $artistRun->artist_royalty_run_id();
        

        # So note how we treat the final link in this hash chain as an array.
        # Note also that we don't have to explicitly allocate an array. Perl just deals with it.
        #
        push @{$artistPayors{$payorID}}, {
            'RunID' => $runID,
            'Label' => $label,
        };
    }
    # Now iterate over that temporary hash... Basically we want to re-build that as an array that lives
    # inside the hash we want to return.
    #
    my @artistPayorArray;
    while (($key, $value) = each(%artistPayors))
    {
        # '$value' here is an array reference.
        # To tell the XML Output code that each of these should be in a tag called <Run>, we
        # add this 'Run' key
        #
        push @artistPayorArray, {
            'PayorID' => $key,
            'Name' => $payorCache{$key},
            'Run' => $value,  # remember, 'Run' is an array reference
        };
    }
    # Now we add this new 'payor array' to the outgoing hash.
    # Again, we want each item in this array to start with a <Payor> tag, so
    # we use a hash key of 'Payor'.
    $returnHash{'ArtistRoyalty'}{'Payor'} = \@artistPayorArray;



    my $allLabelRuns = RPS::DB::Item::LabelRoyaltyRun->GetAll(); 

    my %labelPayors;

    my $size = $allLabelRuns->size();
    print "label Run collection size: $size\n";

    while (my $labelRun = $allLabelRuns->next())
    {
        if (RPS::RoyaltyRun::Status::kComplete != $labelRun->status()
         && RPS::RoyaltyRun::Status::kCommitted != $labelRun->status()
         && RPS::RoyaltyRun::Status::kClosed != $labelRun->status())
        {
            next;
        }

        my $payorID = $labelRun->payor_id();
        my $label = $labelRun->label();
        my $runID = $labelRun->label_royalty_run_id();

        push @{$labelPayors{$payorID}}, {
            'RunID' => $runID,
            'Label' => $label,
        };
    }

    my @labelPayorArray;
    while (($key, $value) = each(%labelPayors))
    {
        push @labelPayorArray, {
            'PayorID' => $key,
            'Name' => $payorCache{$key},
            'Run' => $value,  # remember, 'Run' is an array reference
        };
    }

    $returnHash{'LabelRoyalty'}{'Payor'} = \@labelPayorArray;


    # Again, this time with US Mechanicals.
    #
    my $allUSMechRuns = RPS::DB::Item::MechanicalRun->GetAll(); 
    my %usMechPayors;
    while (my $mechRun = $allUSMechRuns->next())
    {
        if (RPS::RoyaltyRun::Status::kComplete != $mechRun->status()
         && RPS::RoyaltyRun::Status::kCommitted != $mechRun->status()
         && RPS::RoyaltyRun::Status::kClosed != $mechRun->status())
        {
            next;
        }

        my $payorID = $mechRun->payor_id();
        my $label = $mechRun->label();
        my $runID = $mechRun->mechanical_run_id();
        

        push @{$usMechPayors{$payorID}}, {
            'RunID' => $runID,
            'Label' => $label,
        };
    }

    my @usMechPayorArray;
    while (($key, $value) = each(%usMechPayors))
    {
        push @usMechPayorArray, {
            'PayorID' => $key,
            'Name' => $payorCache{$key},
            'Run' => $value,
        };
    }
    $returnHash{'USMechanicals'}{'Payor'} = \@usMechPayorArray;


    # !!! I'll leave the others as an exercise for the reader...

    # Again, this time with UK Mechanicals.
    #
    my $allUKMechRuns = RPS::DB::Item::UKMechanicalRun->GetAll(); 
    my %ukMechPayors;
    while (my $ukMechRun = $allUKMechRuns->next())
    {
        if (RPS::RoyaltyRun::Status::kComplete != $ukMechRun->status()
         && RPS::RoyaltyRun::Status::kCommitted != $ukMechRun->status()
         && RPS::RoyaltyRun::Status::kClosed != $ukMechRun->status())
        {
            next;
        }

        my $payorID = $ukMechRun->payor_id();
        my $label = $ukMechRun->label();
        my $runID = $ukMechRun->uk_mechanical_run_id();
        

        push @{$ukMechPayors{$payorID}}, {
            'RunID' => $runID,
            'Label' => $label,
        };
    }

    my @ukMechPayorArray;
    while (($key, $value) = each(%ukMechPayors))
    {
        push @ukMechPayorArray, {
            'PayorID' => $key,
            'Name' => $payorCache{$key},
            'Run' => $value,
        };
    }
    $returnHash{'UKMechanicals'}{'Payor'} = \@ukMechPayorArray;



    # The preceeding backslash means 'return by reference'.
    # It's ok to return by value, too, but this is generally more efficient.
    #
    return \%returnHash;
}
