#!/usr/bin/env perl
# PROJECT: CASAVA
# MODULE:  $RCSfile: runSortExport.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::PostAlignment::Sequencing::Config qw(loadConfiguration %runsConfig
  %CONF_APP %CONF_PROJ %CONF_RUN readProjectParameters);
use Casava::Common::IOLib;
use Casava::TaskManager qw(configureWorkflow executeSingleTask checkPointInit
    executeArrayTask executeArrayTaskEx executeCheckPoint);
use Casava::PostAlignment::Sequencing::SamLib qw(checkSamtoolsBin);

my $usage =
    "runSortExport.pl [options]\n"
  . "\t--projectDir - Destination Dir is the directory to store the sorted files\n"
    . "\t--buildFile - build specification file";
my $projectDir = "";
my $buildFilePath = '';
my $help       = 0;
my $prevTarget = '';
my $argvStr    = join ' ', @ARGV;
my $result     = GetOptions(
    "projectDir=s" => \$projectDir,
    "buildFile=s"  => \$buildFilePath,
    "prevTarget=s" => \$prevTarget,
    "help|h"       => \$help
);
errorExit "ERROR: Incorrect number of arguments\n$usage"
  unless ( $projectDir ne "" );
loadConfiguration( $projectDir );
#############################################################
# Configuration
my $cmd                 = "";
my $scriptDir           = '@CASAVA_FULL_LIBEXECDIR@';
my $binSize             = $CONF_PROJ{binSizeBuild};
my $timeStampFormat     = $CONF_APP{formatTimeStamp};
my $dateFormat          = $CONF_APP{formatDate};
my $now_string          = strftime( $dateFormat, localtime );
my $date                = $now_string;
my $hostname            = hostname();
my $sortExportCmd       = File::Spec->catfile($scriptDir, $CONF_APP{cmdExport});
my $notMapped2BamScript = File::Spec->catfile($scriptDir, 'notMapped2bam.pl');
my $outputDir           = $CONF_PROJ{dirBuildExport};
my $confDir             = $CONF_APP{dirConf};
my $confFile            = $CONF_APP{projectConf};

my $isKeepAllReads      = ((defined $CONF_PROJ{sortKeepAllReads}) and $CONF_PROJ{sortKeepAllReads});
my $isKeepUnmappedReads = $isKeepAllReads;
#############################################################

if ($help) {
    print $usage;
    exit(0);
}    # if

if ( $outputDir eq "" ) {
    errorExit $usage;
}    # if

printLog( "Running $hostname:[$0 $argvStr]\n", 4 );

# configuration-time check for samtools binary and logging the path of which version was found:
checkSamtoolsBin(%CONF_PROJ);

my %projectChromsBinSizes = ();
readProjectParameters( %projectChromsBinSizes, "PROJECT_BIN_SIZES", $projectDir);
my @chroms = keys %projectChromsBinSizes;

my $waitingFor = "N/A";

configureWorkflow( $CONF_PROJ{isWorkflow}, $CONF_PROJ{workflowFile} );

# Run Some basic QC on data. This is duplicated at the moment 12/03/2009.
# The other check is performed when configure is run
$cmd = "$sortExportCmd --projectDir=$projectDir --target=check";
executeSingleTask( $cmd, 'SYNCH_EXPORT1', "export1", $waitingFor );
$waitingFor = "SYNCH_EXPORT1";

# Split export sets into bins. Each export set will have its own Chrom/bin structure
{
    my $taskLabel      = "export2";
    my $checkPointName = "SYNCH_EXPORT2";
    my $checkPointRef  = checkPointInit( $checkPointName, $taskLabel );

    my $exportSetIndex = 1;
    for my $exportSet (sort
    # it is important to ensure the same ordering of export files in sets for scenarios that
    # require file-by-file comparison of data. For example for automated validation.
        {
            (defined $a->{Read1} ? $a->{Read1} : $a->{Read2})
                                  cmp
            (defined $b->{Read1} ? $b->{Read1} : $b->{Read2})
        } @{$runsConfig{exportFiles}}) 
    {
            
        # derive our command line
        my $taskId = "EXP_LANE_SPLIT_$exportSetIndex";
        $cmd = "$sortExportCmd --projectDir=$projectDir --exportSet=$exportSetIndex";

        $cmd .= " --read1Export=" . $exportSet->{Read1} if $exportSet->{Read1};
        $cmd .= " --read2Export=" . $exportSet->{Read2} if $exportSet->{Read2};
        
        if($CONF_PROJ{readMode} eq "single") {
            $cmd .= " --target=splitSingle";
        } else {
            $cmd .= " --target=split";
        }
        
        if ($buildFilePath) {
            $cmd .= " --buildFile=$buildFilePath";
        }
        
        executeArrayTaskEx( $cmd, $taskId, "Split export set $exportSetIndex", $waitingFor , %{$checkPointRef});
        $exportSetIndex++;
    }
    
    executeCheckPoint( %{$checkPointRef} );
    $waitingFor = $checkPointName;
}

# Store information about exported lanes in Read.idx
$cmd = "$sortExportCmd --projectDir=$projectDir --target=commit";
executeSingleTask( $cmd, "SYNCH_EXPORT3", "export3", $waitingFor );
$waitingFor = "SYNCH_EXPORT3";

if ( $CONF_PROJ{readMode} ne 'single' ) {

    # merge bins from lanes into Chrom/bin structure
    {
        my $taskLabel      = "export5";
        my $checkPointName = "SYNCH_EXPORT5";
        my $checkPointRef  = checkPointInit( $checkPointName, $taskLabel );

        if($isKeepUnmappedReads)
        {
            # merge bins from lanes into Chrom/bin structure for NMs
            $cmd =
              "$sortExportCmd --projectDir=$projectDir --target=mergeNMNM";
            executeArrayTask( $cmd, "NMNM", $waitingFor, %{$checkPointRef} );
        }

        executeCheckPoint( %{$checkPointRef} );
        $waitingFor = $checkPointName;
    }
}
else {
    if($isKeepUnmappedReads)
    {
        # merge bins from lanes into Chrom/bin structure for NMs
        $cmd = "$sortExportCmd --projectDir=$projectDir --target=mergeNMNM";
        executeSingleTask( $cmd, "NMNM", "export4", $waitingFor );
    }
}    # else


if($isKeepUnmappedReads)
{  # convert contents of NMNM directory to BAM
    my $taskLabel      = "Convert NMNM files to BAM";
    my $checkPointName = "NMNM2BAM";
    my $checkPointRef  = checkPointInit( $checkPointName, $taskLabel );

    my $nmnmWaitingFor = "NMNM";
    my $nTasks = $CONF_APP{NMNMTasks};
    for(my $i=0;$i<$nTasks;++$i){
        $cmd = "$notMapped2BamScript --taskId=$i --projectDir=$projectDir";
        executeArrayTaskEx( $cmd, "NMNM2BAM_$i","Convert NMNM files to BAM $i", $nmnmWaitingFor, %$checkPointRef);
    }
    executeCheckPoint( %{$checkPointRef} );
    $nmnmWaitingFor = $checkPointName;
    my $listFile = File::Spec->catfile( $CONF_PROJ{dirBuildParsed}, $CONF_APP{TAG_NMNM}, "tmp.list");
    executeSingleTask("rm -f $listFile","NMNM2BAM_finish","",$nmnmWaitingFor);
}
