#------------------------------------------------------------
# Copyright (C) 2009 RoyaltyShare, Inc.   All Rights Reserved
# $Id$
#------------------------------------------------------------

# This class encapsulates the 'master process' for a UK Mechanicals run.
# In here, we'll set up the database for the run, then spawn individual
# processes for each statement.
#
# So the theory here is that we'll be able to take advantage of horizontal
# scalable resources if we break a run into a series of smaller jobs, rather
# than 1 humonguous run.
# This will also give us the ability to run a single statement at a time.
# The downside is that every process will end up iterating over the sale table,
# which might be a bottleneck.  Might be some way we can fix that - Perhaps
# we can craft a query into a 'temporary' table to pre-divvy the sale ids?
#
package RPS::Mechanical::UK::Process::RunController;
use strict;
use Data::Dumper;
use File::Path;

use lib '/app/tools/common/lib';
use Common::Assert;
use Common::RSApp;
use Common::Log;


use lib '/app/tools/rps/lib';
use RPS::DB::Item::UKMechanicalRun;
use RPS::DB::Item::McpsStatement;
use RPS::DB::Item::McpsLicenseRun;
use RPS::DB::Item::McpsLicenseRetention;
use RPS::DB::Item::McpsLicense;
use RPS::DB::Item::ReportQueries::UKMechRetentionRunSummary;
use RPS::Mechanical::UK::Job::CreateStatement::AP1;
use RPS::Mechanical::UK::Job::CreateStatement::DVD1;
use RPS::Mechanical::UK::Job::CreateStatement::AVP;
use RPS::Mechanical::UK::Job::CreatePDFStatements;
use RPS::Statement::UKMechanical::McpsPDF;
use RPS::Mechanical::UK::Job::CreateMcpsTextStatement;
use RPS::Statement::UKMechanical::McpsText;
use RPS::Product::Price;

use RPS::Mechanical::UK::Process::CreateStatement::Mcps::AP1;
use RPS::Mechanical::UK::Process::CreateStatement::Mcps::DVD1;
use RPS::Mechanical::UK::Process::CreateStatement::Mcps::AVP;

use lib '/app/tools/job/lib';
use Job::Status;

use base 'RPS::Mechanical::Process::RunController';


sub _getAllActivePublisherIDs
{
    my ($self) = @_;

    # !!! At the moment, we simply don't support direct statements for UK mechanicals.
    #     So we return an empty list.
    #
    my @ids;

    return @ids;
}

sub _getRunDBItem
{
    my ($self) = @_;
    assert($self->{_runID});

    my $dbItem = RPS::DB::Item::UKMechanicalRun->Lookup(uk_mechanical_run_id => $self->{_runID});
    return $dbItem;
}

sub _preCommitSanityCheck
{
    my ($self) = @_;

	return 1;
}

sub _commitCarryover
{
    my ($self) = @_;

    my $allLicenses = RPS::DB::Item::McpsLicenseRun->GetByRunID($self->{_runID});
    while (my $licenseRunMap = $allLicenses->next())
    {
        my $licenseID = $licenseRunMap->mcps_license_id;
        my $license = RPS::DB::Item::McpsLicense->Lookup(mcps_license_id => $licenseID);

        # Delete any carryover associated with this license (making room for new entries, if any)
        #
        RPS::DB::Item::McpsLicenseCarryover->DeleteAllForLicense($license->mcps_license_id);
    }
}


sub _commitReserves
{
    my ($self) = @_;

    # We don't delete/modify reserves the same way we do for US and CA mechanicals.
    #

    my $allLicenses = RPS::DB::Item::McpsLicenseRun->GetByRunID($self->{_runID});
    while (my $licenseRunMap = $allLicenses->next())
    {
        my $licenseID = $licenseRunMap->mcps_license_id;
        my $license = RPS::DB::Item::McpsLicense->Lookup(mcps_license_id => $licenseID);

        # Find all the 'historical' retentions associated with this license, 
        # and 'freeze' their price.   
        #
        my $allRetentions = RPS::DB::Item::McpsLicenseRetention->GetByMcpsLicenseID($licenseID);
        while (my $retention = $allRetentions->next())
        {
            if (0 == $retention->price())
            {
                my $price = RPS::Product::Price::GetWholesaleProductPrice($license->product_id, $retention->price_level_id);
                $retention->price($price);
                $retention->save();
            }
        }
    }
}


sub _commitStatement
{
    my ($self, $statement) = @_;

    my $statementProcessor;
    if (RPS::DB::Item::McpsStatement::kSchemeAP1 eq $statement->mcps_scheme)
    {
        $statementProcessor = RPS::Mechanical::UK::Process::CreateStatement::Mcps::AP1->new(statementID => $statement->mcps_statement_id());
    }
    elsif (RPS::DB::Item::McpsStatement::kSchemeDVD1 eq $statement->mcps_scheme)
    {
        $statementProcessor = RPS::Mechanical::UK::Process::CreateStatement::Mcps::DVD1->new(statementID => $statement->mcps_statement_id());
    }
    elsif (RPS::DB::Item::McpsStatement::kSchemeAVP eq $statement->mcps_scheme)
    {
        $statementProcessor = RPS::Mechanical::UK::Process::CreateStatement::Mcps::AVP->new(statementID => $statement->mcps_statement_id());
    }

    $statementProcessor->commit();
}


sub _getAllStatements
{
    my ($self) = @_;

    my $statements = RPS::DB::Item::McpsStatement->GetByRunID($self->{_runID});
    return $statements;
}


sub _deleteFromSaleRunMap
{
    my ($self) = @_;

    RPS::DB::Item::SaleRunMap->DeleteByUKMechanicalRunID($self->{_runID});
}


sub _getLogFilePath
{
    my ($self) = @_;

    my $logBasePath = RPS::Mechanical::UK::Job::Base::LogFilePath(Common::RSApp::GetClientID(), $self->{_runID});
    return $logBasePath;
}


sub delete
{
    my ($self) = @_;

    # Delete from the McpsLicenseRun table, then invoke the inherited method
    # to finish the job.
    #
    RPS::DB::Item::McpsLicenseRun->DeleteByRunID($self->{_runID});

    $self->SUPER::delete();
}



sub _deleteStatement
{
    my ($self, $statement) = @_;

    my $statementID = $statement->mcps_statement_id;

    $self->_report("deleting statement $statementID");
    $statement->delete();


    # Get rid of the sale/statement_item map entries
    #
    $self->_report("  ... deleting statement items",2);
    RPS::DB::Item::McpsStatementItem->DeleteByMCPSStatementID($statementID);
}



sub _getStatement
{
    my ($self, $statementID) = @_;

    my $statement = RPS::DB::Item::McpsStatement->Lookup(mcps_statement_id => $statementID);
    return $statement;
}




sub _createStatementsAndJobs
{
    my ($self) = @_;

    # For now, we only have 3 statements - AP1,DVD1, and AVP.
    #
    $self->_addJobToJobList('AP1', $self->_createAP1StatementJob());
    $self->_addJobToJobList('DVD1', $self->_createDVD1StatementJob());
    $self->_addJobToJobList('AVP', $self->_createAVPStatementJob());


    $self->SUPER::_createStatementsAndJobs();
}



sub _createAP1StatementJob
{
    my ($self) = @_;


    # The AP1 uses a 'normal' statement record.
    # But each sort of Job will have their own Job subclass.
    #

    my $statementObj = RPS::DB::Item::McpsStatement->Create
    (
        uk_mechanical_run_id => $self->{_runID},
        mcps_scheme => RPS::DB::Item::McpsStatement::kSchemeAP1,
        status => RPS::DB::Item::McpsStatement::kStatusNotQueued,
    );
    $statementObj->save();
    my $statementID = $statementObj->mcps_statement_id();


    # Create the Job object
    #
    my $job = RPS::Mechanical::UK::Job::CreateStatement::AP1->new(runID => $self->{_runID}, statementID => $statementID, logLevel => $self->{_logLevel});
    $job->enqueue();


    # Update the statement record with the job id, and
    # update the status to 'in queue'
    #
    $statementObj->job_id($job->id());
    $statementObj->status(RPS::DB::Item::McpsStatement::kStatusInQueue);
    $statementObj->save();

    return $job;
}

sub _createDVD1StatementJob
{
    my ($self) = @_;


    # The AP1 uses a 'normal' statement record.
    # But each sort of Job will have their own Job subclass.
    #

    my $statementObj = RPS::DB::Item::McpsStatement->Create
    (
        uk_mechanical_run_id => $self->{_runID},
        mcps_scheme => RPS::DB::Item::McpsStatement::kSchemeDVD1,
        status => RPS::DB::Item::McpsStatement::kStatusNotQueued,
    );
    $statementObj->save();
    my $statementID = $statementObj->mcps_statement_id();


    # Create the Job object
    #
    my $job = RPS::Mechanical::UK::Job::CreateStatement::DVD1->new(runID => $self->{_runID}, statementID => $statementID, logLevel => $self->{_logLevel});
    $job->enqueue();


    # Update the statement record with the job id, and
    # update the status to 'in queue'
    #
    $statementObj->job_id($job->id());
    $statementObj->status(RPS::DB::Item::McpsStatement::kStatusInQueue);
    $statementObj->save();

    return $job;
}

sub _createAVPStatementJob
{
    my ($self) = @_;


    my $statementObj = RPS::DB::Item::McpsStatement->Create
    (
        uk_mechanical_run_id => $self->{_runID},
        mcps_scheme => RPS::DB::Item::McpsStatement::kSchemeAVP,
        status => RPS::DB::Item::McpsStatement::kStatusNotQueued,
    );
    $statementObj->save();
    my $statementID = $statementObj->mcps_statement_id();


    # Create the Job object
    #
    my $job = RPS::Mechanical::UK::Job::CreateStatement::AVP->new(runID => $self->{_runID}, statementID => $statementID, logLevel => $self->{_logLevel});
    $job->enqueue();


    # Update the statement record with the job id, and
    # update the status to 'in queue'
    #
    $statementObj->job_id($job->id());
    $statementObj->status(RPS::DB::Item::McpsStatement::kStatusInQueue);
    $statementObj->save();

    return $job;
}


sub _createPDFJobs
{
    my ($self) = @_;

    # Create a job for each statement id, and put it in the queue.
    #
    my $clientID = Common::RSApp::GetClientID();

    my $filePath = RPS::Statement::UKMechanical::McpsPDF::StatementPathFromRunID($self->{_runID});
    my $jobArgs = RPS::Mechanical::UK::Job::CreatePDFStatements->new
    (
        runID       => $self->{_runID},
        clientID 	=> $clientID,
        filePath 	=> $filePath,            
    );
    my $job = $jobArgs->enqueue(); 

}


sub _createTextJobs
{
    my ($self) = @_;

    # Create a job for the run, and put it in the queue.
    #
    my $clientID = Common::RSApp::GetClientID();
    my $filePath = RPS::Statement::UKMechanical::McpsText::StatementPathFromRunID($self->{_runID}, $clientID);
    my $jobArgs = RPS::Mechanical::UK::Job::CreateMcpsTextStatement->new
    (
        runID       => $self->{_runID},
        clientID 	=> $clientID,
        filePath 	=> $filePath,            
    );
    my $job = $jobArgs->enqueue(); 
}


sub _createRetentionReport
{
    my ($self) = @_;
    
    # We may want to wrap a job around this later.
    #
    RPS::DB::Item::ReportQueries::UKMechRetentionRunSummary->CreateRetentionSummary($self->{_runID});
    
}


sub _getLicenseShareErrors {
    my ($self) = @_;
    return undef;
}


sub _getAllOtherCommittedRuns
{
    my ($self) = @_;
    return undef;
}

1;
