#!/usr/bin/env perl
# PROJECT: CASAVA
# MODULE:  $RCSfile: runSplitUnSorted.pl,v $
# AUTHOR:  Richard Carter, Lukasz Szajkowski
#
# Copyright (c) 2008 Illumina
# This software is covered by the "Illumina Genome Analyzer Software
# License Agreement" and the "Illumina Source Code License Agreement",
# and certain third party copyright/licenses, and any user of this
# source file is bound by the terms therein (see accompanying files
# Illumina_Genome_Analyzer_Software_License_Agreement.pdf and
# Illumina_Source_Code_License_Agreement.pdf and third party
# copyright/license notices).
use warnings FATAL => 'all';
use strict;
use POSIX qw(strftime);

use IO::File;
use Sys::Hostname;
use Getopt::Long;

use lib '@CASAVA_FULL_PERL_LIBDIR@';
use Casava::Common::Log;
use Casava::Common::IOLib
  qw(executeCmd createDirs);
use Casava::TaskManager qw(executeSingleTask checkPointInit
    executeArrayTask executeArrayTaskEx executeCheckPoint
    addTask2checkPoint tryAddTask2CheckPoint);
use Casava::PostAlignment::Sequencing::Config qw(loadConfiguration
  %CONF_APP %CONF_PROJ %CONF_RUN isSpliceJunctionChrom readProjectParameters);

my $argvStr     = join ' ', @ARGV;
my $usage       =
    "runSplitUnSorted.pl [options]\n"
  . "\t--projectDir - Destination Dir is the directory to store the sorted files\n";
my $projectDir = "";
my $help       = 0;
my $prevTarget = "";
my $result     = GetOptions(
    "projectDir=s" => \$projectDir,
    "prevTarget=s" => \$prevTarget,
    "help|h"       => \$help
);
errorExit "ERROR: Incorrect number of arguments\n$usage"
  if ( $projectDir eq "" );
loadConfiguration( $projectDir );
#############################################################
# Configuration
my $cmd               = "";
my $projectBinSize    = $CONF_PROJ{binSizeProject};
my $buildBinSize      = $CONF_PROJ{binSizeBuild};
my $timeStampFormat   = $CONF_APP{formatTimeStamp};
my $bamDirName        = $CONF_APP{dirBam};

my $scriptDir         = '@CASAVA_FULL_LIBEXECDIR@';
my $splitCmd          = File::Spec->catfile($scriptDir, $CONF_APP{cmdSplit});
my $sortExportCmd     = File::Spec->catfile($scriptDir, $CONF_APP{cmdExport});
my $reportsCmd        = File::Spec->catfile($scriptDir, $CONF_APP{cmdReports});
my $statsCmd          = File::Spec->catfile($scriptDir, $CONF_APP{cmdStats});
my $sorted2BamScript  = File::Spec->catfile($scriptDir, 'sorted2bam.pl');
my $concatBamScript   = File::Spec->catfile($scriptDir, 'concatChromBam.pl');
my $hostname          = hostname();
my $isRemoveTemps     = ((defined $CONF_PROJ{removeTemps}) and ($CONF_PROJ{removeTemps} eq 'ON'));
#############################################################

if ($help) {
    print $usage;
    exit(0);
}
printLog( "Running $hostname:[$0 $argvStr]\n", 4 );

my %projectChromsBinSizes = ();
my %buildChromsBinSizes   = ();
readProjectParameters( %projectChromsBinSizes, "PROJECT_BIN_SIZES", $projectDir);
readProjectParameters( %buildChromsBinSizes, "BUILD_BIN_SIZES", $projectDir);
my @chromsProject = keys %projectChromsBinSizes;
my @chromsBuild   = keys %buildChromsBinSizes;

# setup output directories:
my $buildDir          = $CONF_PROJ{dirBuildParsed};
my @dirs = ();
for my $chrom (@chromsBuild) {
    next if (isSpliceJunctionChrom($chrom, %CONF_PROJ));
    push @dirs, File::Spec->catdir($chrom,$bamDirName);
}
createDirs($buildDir, @dirs);

my $waitingFor = "SYNCH_EXPORT3";
if ( $prevTarget eq 'start' ) {
    $waitingFor = 'N/A';
}


# primary checkpoint indicating the completion of bin/sort for both SE
# and PE modes:
my $taskLabel      = "sortMerge";
my $checkPointName = "SYNCH_MERGE_DONE";
my $checkPointRef  = checkPointInit( $checkPointName, $taskLabel );


if ( $CONF_PROJ{readMode} eq 'single' ) {
    my $taskLabelBAM      = "sortMerge to BAM";
    my $checkPointNameBAM = "SYNCH_MERGE_BAM_DONE";
    my $checkPointRefBAM  = checkPointInit( $checkPointNameBAM, $taskLabelBAM );

    for my $chrom (@chromsBuild) {
        next if (isSpliceJunctionChrom($chrom, %CONF_PROJ));
        my $checkPointChromNameBAM = "SYNCH_MERGE_BAM_$chrom\_DONE";
        my $checkPointChromRefBAM  = checkPointInit( $checkPointChromNameBAM, "sortMerge to BAM for $chrom" );
        my $binCount = $buildChromsBinSizes{$chrom};
        for ( my $i = 0 ; $i < $binCount; $i++ ) {
            my $binId = sprintf "%04d", $i;
            my $taskId = "build$chrom/$binId";
            printLog( "merging to Build $taskId\n", 4 );
            $cmd = "$splitCmd --projectDir=$projectDir"
              . " --chrom='$chrom' --binId=$binId --target=mergeSingle";
            executeArrayTask( $cmd, $taskId, $waitingFor, %$checkPointChromRefBAM );
        }
        executeCheckPoint( %$checkPointChromRefBAM );
        addTask2checkPoint( $checkPointChromNameBAM , %$checkPointRefBAM );

        my $checkPointChromName = "SYNCH_MERGE_$chrom\_DONE";
        my $checkPointChromRef  = checkPointInit( $checkPointChromName, "sortMerge for $chrom" );

        my $concatBamCmd = "$concatBamScript --projectDir=$projectDir --chrom=$chrom";
        executeArrayTaskEx( $concatBamCmd, "SORTED2BAM_$chrom", "Merging BAMs for $chrom", $checkPointChromNameBAM , %$checkPointChromRef );

        executeCheckPoint( %$checkPointChromRef );
        addTask2checkPoint( $checkPointChromName , %$checkPointRef );
    }    # for

    tryAddTask2CheckPoint( "NMNM", %{$checkPointRefBAM} );
    executeCheckPoint( %$checkPointRefBAM );
    $waitingFor = $checkPointNameBAM;

    if($isRemoveTemps) {
        $cmd = "$sortExportCmd --projectDir='$projectDir' --target=removeTemps";
        executeSingleTask( $cmd, "SYNCH_SORT2", "sortRemoveTemps", $waitingFor );
    }
}    # if
else {
    my $taskLabelSplit      = "sortRmDupSplit";
    my $checkPointNameSplit = "SYNCH_SORT";
    my $checkPointRefSplit  = checkPointInit( $checkPointNameSplit, $taskLabelSplit );
    for my $chrom (@chromsProject) {
        my $binCount = $projectChromsBinSizes{$chrom};
        for ( my $i = 0 ; $i < $binCount; $i++ ) {
            my $binId = sprintf "%04d", $i;
            my $taskId = "$chrom/$binId";
            printLog( "Splitting and sorting in project $taskId\n", 4 );
            $cmd =
                "$splitCmd --projectDir=$projectDir"
              . " --chrom='$chrom' --binId=$binId --target=split";
            executeArrayTask( $cmd, $taskId, $waitingFor, %{$checkPointRefSplit} );
        }    # for
    }    # foreach
    executeCheckPoint( %{$checkPointRefSplit} );
    $waitingFor = $checkPointNameSplit;

    if($isRemoveTemps) {
        # additional checkpoint used to wait for NMNM
        my $taskLabelRT = "syncRmSplitTemp";
        my $checkPointNameRT = "SYNC_RM_SPLIT_TEMP";
        my $checkPointRefRT = checkPointInit( $checkPointNameRT , $taskLabelRT );
        addTask2checkPoint($waitingFor, %$checkPointRefRT );
        tryAddTask2CheckPoint("NMNM", %$checkPointRefRT );
        executeCheckPoint( %{$checkPointRefRT} );

        $cmd = "$sortExportCmd --projectDir='$projectDir' --target=removeTemps";
        executeSingleTask( $cmd, "SYNCH_SORT2", "sortRemoveTemps", $checkPointNameRT );
    }

    #
    # Generates statistics for duplicates
    #
    # These two duplicate summarization steps can run in parallel to
    # all steps below
    #
    {
        my $summaryWaitingFor = $waitingFor;
        {
            $cmd = "$statsCmd --projectDir=$projectDir --target=duplicates";
            my $taskId = "SYNCH_DUPL2";
            executeSingleTask( $cmd, $taskId, "sortDupStats", $summaryWaitingFor );
            $summaryWaitingFor = $taskId;
        }
        {
            # use "REPORT" taskId to prevent reports from being run in
            # parallel (this makes html page registration safe)
            $cmd = "$reportsCmd --projectDir=$projectDir --target=duplicates";
            my $taskId = "REPORT";
            executeSingleTask( $cmd, $taskId, "sortDupReport", $summaryWaitingFor );
        }
    }

    # temp file removal is triggered by the completion of all export file merging:
    my $taskLabelBAM      = "sortMerge to BAM";
    my $checkPointNameBAM = "SYNCH_MERGE_BAM_DONE";
    my $checkPointRefBAM  = checkPointInit( $checkPointNameBAM, $taskLabelBAM );

    for my $chrom (@chromsBuild) {
        next if (isSpliceJunctionChrom($chrom, %CONF_PROJ));
        my $checkPointChromNameBAM = "SYNCH_MERGE_BAM_$chrom\_DONE";
        my $checkPointChromRefBAM  = checkPointInit( $checkPointChromNameBAM, "sortMerge to BAM for $chrom" );
        my $binCount = $buildChromsBinSizes{$chrom};
        for ( my $i = 0 ; $i < $binCount; $i++ ) {
            my $binId = sprintf "%04d", $i;
            my $taskId = "build$chrom/$binId";
            printLog( "merging to Build $taskId\n", 4 );
            $cmd = "$splitCmd --projectDir=$projectDir"
              . " --chrom='$chrom' --binId=$binId --target=merge";
            executeArrayTask( $cmd, $taskId, $waitingFor, %{$checkPointChromRefBAM} );
        }    # for
        executeCheckPoint( %$checkPointChromRefBAM );
        addTask2checkPoint( $checkPointChromNameBAM , %$checkPointRefBAM );

        my $checkPointChromName = "SYNCH_MERGE_$chrom\_DONE";
        my $checkPointChromRef  = checkPointInit( $checkPointChromName, "sortMerge for $chrom" );

        my $concatBamCmd = "$concatBamScript --projectDir=$projectDir --chrom=$chrom";
        executeArrayTaskEx( $concatBamCmd, "SORTED2BAM_$chrom", "Merging BAMs for $chrom", $checkPointChromNameBAM , %$checkPointChromRef );

        executeCheckPoint( %$checkPointChromRef );
        addTask2checkPoint( $checkPointChromName , %$checkPointRef );
    }    # for
    executeCheckPoint( %$checkPointRefBAM );
    $waitingFor = $checkPointNameBAM;

    if ($isRemoveTemps) {
        $cmd = "$splitCmd --projectDir='$projectDir' --target=removeTemps";
        executeSingleTask( $cmd, "SYNCH_SORT2", "sortRemoveTemps", $waitingFor );
    }    # if
}    # else

# make sure NMNM BAMs are also done before we declare bin/sort
# finished
tryAddTask2CheckPoint( "NMNM2BAM", %$checkPointRef );
executeCheckPoint( %{$checkPointRef} );


1;
__END__
