#!/bin/bash
### ---
### name: 'NFCORE_SAREK:SAREK:FASTQ_ALIGN_BWAMEM_MEM2_DRAGMAP_SENTIEON:BWAMEM1_MEM (STRAN-2023-41090)'
### container: 'quay.io/biocontainers/mulled-v2-fe8faa35dbf6dc65a0f7f5d4ea12e31a79f73e40:1bd8542a8a0b42e0981337910954371d0230828e-0'
### outputs:
### - '*.bam'
### - '*.cram'
### - '*.csi'
### - '*.crai'
### - 'versions.yml'
### ...
set -e
set -u
NXF_DEBUG=${NXF_DEBUG:=0}; [[ $NXF_DEBUG > 1 ]] && set -x
NXF_ENTRY=${1:-nxf_main}

nxf_tree() {
    local pid=$1

    declare -a ALL_CHILDREN
    while read P PP;do
        ALL_CHILDREN[$PP]+=" $P"
    done < <(ps -e -o pid= -o ppid=)

    pstat() {
        local x_pid=$1
        local STATUS=$(2> /dev/null < /proc/$1/status grep -E 'Vm|ctxt')

        if [ $? = 0 ]; then
        local  x_vsz=$(echo "$STATUS" | grep VmSize | awk '{print $2}' || echo -n '0')
        local  x_rss=$(echo "$STATUS" | grep VmRSS | awk '{print $2}' || echo -n '0')
        local x_peak=$(echo "$STATUS" | grep -E 'VmPeak|VmHWM' | sed 's/^.*:\s*//' | sed 's/[\sa-zA-Z]*$//' | tr '\n' ' ' || echo -n '0 0')
        local x_pmem=$(awk -v rss=$x_rss -v mem_tot=$mem_tot 'BEGIN {printf "%.0f", rss/mem_tot*100*10}' || echo -n '0')
        local vol_ctxt=$(echo "$STATUS" | grep '\bvoluntary_ctxt_switches' | awk '{print $2}' || echo -n '0')
        local inv_ctxt=$(echo "$STATUS" | grep '\bnonvoluntary_ctxt_switches' | awk '{print $2}' || echo -n '0')
        cpu_stat[x_pid]="$x_pid $x_pmem $x_vsz $x_rss $x_peak $vol_ctxt $inv_ctxt"
        fi
    }

    pwalk() {
        pstat $1
        for i in ${ALL_CHILDREN[$1]:=}; do pwalk $i; done
    }

    pwalk $1
}

nxf_stat() {
    cpu_stat=()
    nxf_tree $1

    declare -a sum=(0 0 0 0 0 0 0 0)
    local pid
    local i
    for pid in "${!cpu_stat[@]}"; do
        local row=(${cpu_stat[pid]})
        [ $NXF_DEBUG = 1 ] && echo "++ stat mem=${row[*]}"
        for i in "${!row[@]}"; do
        if [ $i != 0 ]; then
            sum[i]=$((sum[i]+row[i]))
        fi
        done
    done

    [ $NXF_DEBUG = 1 ] && echo -e "++ stat SUM=${sum[*]}"

    for i in {1..7}; do
        if [ ${sum[i]} -lt ${cpu_peak[i]} ]; then
            sum[i]=${cpu_peak[i]}
        else
            cpu_peak[i]=${sum[i]}
        fi
    done

    [ $NXF_DEBUG = 1 ] && echo -e "++ stat PEAK=${sum[*]}\n"
    nxf_stat_ret=(${sum[*]})
}

nxf_mem_watch() {
    set -o pipefail
    local pid=$1
    local trace_file=.command.trace
    local count=0;
    declare -a cpu_stat=(0 0 0 0 0 0 0 0)
    declare -a cpu_peak=(0 0 0 0 0 0 0 0)
    local mem_tot=$(< /proc/meminfo grep MemTotal | awk '{print $2}')
    local timeout
    local DONE
    local STOP=''

    [ $NXF_DEBUG = 1 ] && nxf_sleep 0.2 && ps fx

    while true; do
        nxf_stat $pid
        if [ $count -lt 10 ]; then timeout=1;
        elif [ $count -lt 120 ]; then timeout=5;
        else timeout=30;
        fi
        read -t $timeout -r DONE || true
        [[ $DONE ]] && break
        if [ ! -e /proc/$pid ]; then
            [ ! $STOP ] && STOP=$(nxf_date)
            [ $(($(nxf_date)-STOP)) -gt 10000 ] && break
        fi
        count=$((count+1))
    done

    echo "%mem=${nxf_stat_ret[1]}"      >> $trace_file
    echo "vmem=${nxf_stat_ret[2]}"      >> $trace_file
    echo "rss=${nxf_stat_ret[3]}"       >> $trace_file
    echo "peak_vmem=${nxf_stat_ret[4]}" >> $trace_file
    echo "peak_rss=${nxf_stat_ret[5]}"  >> $trace_file
    echo "vol_ctxt=${nxf_stat_ret[6]}"  >> $trace_file
    echo "inv_ctxt=${nxf_stat_ret[7]}"  >> $trace_file
}

nxf_write_trace() {
    echo "nextflow.trace/v2"           > $trace_file
    echo "realtime=$wall_time"         >> $trace_file
    echo "%cpu=$ucpu"                  >> $trace_file
    echo "cpu_model=$cpu_model"        >> $trace_file
    echo "rchar=${io_stat1[0]}"        >> $trace_file
    echo "wchar=${io_stat1[1]}"        >> $trace_file
    echo "syscr=${io_stat1[2]}"        >> $trace_file
    echo "syscw=${io_stat1[3]}"        >> $trace_file
    echo "read_bytes=${io_stat1[4]}"   >> $trace_file
    echo "write_bytes=${io_stat1[5]}"  >> $trace_file
}

nxf_trace_mac() {
    local start_millis=$(nxf_date)

    /usr/bin/env bash -C -e -u -o pipefail .command.sh

    local end_millis=$(nxf_date)
    local wall_time=$((end_millis-start_millis))
    local ucpu=''
    local cpu_model=''
    local io_stat1=('' '' '' '' '' '')
    nxf_write_trace
}

nxf_fd() {
    local FD=11
    while [ -e /proc/$$/fd/$FD ]; do FD=$((FD+1)); done
    echo $FD
}

nxf_trace_linux() {
    local pid=$$
    command -v ps &>/dev/null || { >&2 echo "Command 'ps' required by nextflow to collect task metrics cannot be found"; exit 1; }
    local num_cpus=$(< /proc/cpuinfo grep '^processor' -c)
    local cpu_model=$(< /proc/cpuinfo grep '^model name' | head -n 1 | awk 'BEGIN{FS="\t: "} { print $2 }')
    local tot_time0=$(grep '^cpu ' /proc/stat | awk '{sum=$2+$3+$4+$5+$6+$7+$8+$9; printf "%.0f",sum}')
    local cpu_time0=$(2> /dev/null < /proc/$pid/stat awk '{printf "%.0f", ($16+$17)*10 }' || echo -n 'X')
    local io_stat0=($(2> /dev/null < /proc/$pid/io sed 's/^.*:\s*//' | head -n 6 | tr '\n' ' ' || echo -n '0 0 0 0 0 0'))
    local start_millis=$(nxf_date)
    trap 'kill $mem_proc' ERR
    
    /usr/bin/env bash -C -e -u -o pipefail .command.sh &
    local task=$!

    mem_fd=$(nxf_fd)
    eval "exec $mem_fd> >(nxf_mem_watch $task)"
    local mem_proc=$!

    wait $task

    local end_millis=$(nxf_date)
    local tot_time1=$(grep '^cpu ' /proc/stat | awk '{sum=$2+$3+$4+$5+$6+$7+$8+$9; printf "%.0f",sum}')
    local cpu_time1=$(2> /dev/null < /proc/$pid/stat awk '{printf "%.0f", ($16+$17)*10 }' || echo -n 'X')
    local ucpu=$(awk -v p1=$cpu_time1 -v p0=$cpu_time0 -v t1=$tot_time1 -v t0=$tot_time0 -v n=$num_cpus 'BEGIN { pct=(p1-p0)/(t1-t0)*100*n; printf("%.0f", pct>0 ? pct : 0) }' )

    local io_stat1=($(2> /dev/null < /proc/$pid/io sed 's/^.*:\s*//' | head -n 6 | tr '\n' ' ' || echo -n '0 0 0 0 0 0'))
    local i
    for i in {0..5}; do
        io_stat1[i]=$((io_stat1[i]-io_stat0[i]))
    done

    local wall_time=$((end_millis-start_millis))
    [ $NXF_DEBUG = 1 ] && echo "+++ STATS %CPU=$ucpu TIME=$wall_time I/O=${io_stat1[*]}"

    echo "nextflow.trace/v2"           > $trace_file
    echo "realtime=$wall_time"         >> $trace_file
    echo "%cpu=$ucpu"                  >> $trace_file
    echo "cpu_model=$cpu_model"        >> $trace_file
    echo "rchar=${io_stat1[0]}"        >> $trace_file
    echo "wchar=${io_stat1[1]}"        >> $trace_file
    echo "syscr=${io_stat1[2]}"        >> $trace_file
    echo "syscw=${io_stat1[3]}"        >> $trace_file
    echo "read_bytes=${io_stat1[4]}"   >> $trace_file
    echo "write_bytes=${io_stat1[5]}"  >> $trace_file

    [ -e /proc/$mem_proc ] && eval "echo 'DONE' >&$mem_fd" || true
    wait $mem_proc 2>/dev/null || true
    while [ -e /proc/$mem_proc ]; do nxf_sleep 0.1; done
}

nxf_trace() {
    local trace_file=.command.trace
    touch $trace_file
    if [[ $(uname) = Darwin ]]; then
        nxf_trace_mac
    else
        nxf_trace_linux
    fi
}
# bash helper functions
nxf_cp_retry() {
    local max_attempts=1
    local timeout=10
    local attempt=0
    local exitCode=0
    while (( $attempt < $max_attempts ))
    do
      if "$@"
        then
          return 0
      else
        exitCode=$?
      fi
      if [[ $exitCode == 0 ]]
      then
        break
      fi
      nxf_sleep $timeout
      attempt=$(( attempt + 1 ))
      timeout=$(( timeout * 2 ))
    done
}

nxf_parallel() {
    IFS=$'\n'
    local cmd=("$@")
    local cpus=$(nproc 2>/dev/null || < /proc/cpuinfo grep '^process' -c)
    local max=$(if (( cpus>4 )); then echo 4; else echo $cpus; fi)
    local i=0
    local pid=()
    (
    set +u
    while ((i<${#cmd[@]})); do
        local copy=()
        for x in "${pid[@]}"; do
          # if the process exist, keep in the 'copy' array, otherwise wait on it to capture the exit code
          # see https://github.com/nextflow-io/nextflow/pull/4050
          [[ -e /proc/$x ]] && copy+=($x) || wait $x
        done
        pid=("${copy[@]}")

        if ((${#pid[@]}>=$max)); then
          nxf_sleep 0.2
        else
          eval "${cmd[$i]}" &
          pid+=($!)
          ((i+=1))
        fi
    done
    for p in "${pid[@]}"; do
        wait $p
    done
    )
    unset IFS
}

# custom env variables used for azcopy opts
export AZCOPY_BLOCK_SIZE_MB=4
export AZCOPY_BLOCK_BLOB_TIER=None

nxf_az_upload() {
    local name=$1
    local target=${2%/} ## remove ending slash
    local base_name="$(basename "$name")"
    local dir_name="$(dirname "$name")"

    if [[ -d $name ]]; then
      if [[ "$base_name" == "$name" ]]; then
        azcopy cp "$name" "$target?$AZ_SAS" --recursive --block-blob-tier $AZCOPY_BLOCK_BLOB_TIER --block-size-mb $AZCOPY_BLOCK_SIZE_MB
      else
        azcopy cp "$name" "$target/$dir_name?$AZ_SAS" --recursive --block-blob-tier $AZCOPY_BLOCK_BLOB_TIER --block-size-mb $AZCOPY_BLOCK_SIZE_MB
      fi
    else
      azcopy cp "$name" "$target/$name?$AZ_SAS" --block-blob-tier $AZCOPY_BLOCK_BLOB_TIER --block-size-mb $AZCOPY_BLOCK_SIZE_MB
    fi
}

nxf_az_download() {
    local source=$1
    local target=$2
    local basedir=$(dirname $2)
    local ret
    mkdir -p "$basedir"

    ret=$(azcopy cp "$source?$AZ_SAS" "$target" 2>&1) || {
        ## if fails check if it was trying to download a directory
        mkdir -p $target
        azcopy cp "$source/*?$AZ_SAS" "$target" --recursive >/dev/null || {
            rm -rf $target
            >&2 echo "Unable to download path: $source"
            exit 1
        }
    }
}

nxf_sleep() {
  sleep $1 2>/dev/null || sleep 1;
}

nxf_date() {
    local ts=$(date +%s%3N);
    if [[ ${#ts} == 10 ]]; then echo ${ts}000
    elif [[ $ts == *%3N ]]; then echo ${ts/\%3N/000}
    elif [[ $ts == *3N ]]; then echo ${ts/3N/000}
    elif [[ ${#ts} == 13 ]]; then echo $ts
    else echo "Unexpected timestamp value: $ts"; exit 1
    fi
}

nxf_env() {
    echo '============= task environment ============='
    env | sort | sed "s/\(.*\)AWS\(.*\)=\(.\{6\}\).*/\1AWS\2=\3xxxxxxxxxxxxx/"
    echo '============= task output =================='
}

nxf_kill() {
    declare -a children
    while read P PP;do
        children[$PP]+=" $P"
    done < <(ps -e -o pid= -o ppid=)

    kill_all() {
        [[ $1 != $$ ]] && kill $1 2>/dev/null || true
        for i in ${children[$1]:=}; do kill_all $i; done
    }

    kill_all $1
}

nxf_mktemp() {
    local base=${1:-/tmp}
    mkdir -p "$base"
    if [[ $(uname) = Darwin ]]; then mktemp -d $base/nxf.XXXXXXXXXX
    else TMPDIR="$base" mktemp -d -t nxf.XXXXXXXXXX
    fi
}

nxf_fs_copy() {
  local source=$1
  local target=$2
  local basedir=$(dirname $1)
  mkdir -p $target/$basedir
  cp -fRL $source $target/$basedir
}

nxf_fs_move() {
  local source=$1
  local target=$2
  local basedir=$(dirname $1)
  mkdir -p $target/$basedir
  mv -f $source $target/$basedir
}

nxf_fs_rsync() {
  rsync -rRl $1 $2
}

nxf_fs_rclone() {
  rclone copyto $1 $2/$1
}

nxf_fs_fcp() {
  fcp $1 $2/$1
}

on_exit() {
    exit_status=${nxf_main_ret:=$?}
    printf -- $exit_status  > .exitcode
    set +u
    exit $exit_status
}

on_term() {
    set +e
    [[ "$pid" ]] && nxf_kill $pid
}

nxf_launch() {
    /bin/bash .command.run nxf_trace
}

nxf_stage() {
    true
    # stage input files
    nxf_az_download 'https://hhibiobatchstorage.blob.core.windows.net/nextflow-work/work/tmp/ff/fabe7df72cfa6a62db317447c681d5/bin' $PWD/.nextflow-bin
    chmod +x $PWD/.nextflow-bin/* || true
    downloads=(true)
    rm -f 0001.STRAN-2023-41090-L001_1.fastp.fastq.gz
    rm -f 0001.STRAN-2023-41090-L001_2.fastp.fastq.gz
    rm -f 0002.STRAN-2023-41090-L001_2.fastp.fastq.gz
    rm -f 0003.STRAN-2023-41090-L001_2.fastp.fastq.gz
    rm -f 0002.STRAN-2023-41090-L001_1.fastp.fastq.gz
    rm -f 0003.STRAN-2023-41090-L001_1.fastp.fastq.gz
    rm -f 0004.STRAN-2023-41090-L001_1.fastp.fastq.gz
    rm -f bwa
    rm -f 0004.STRAN-2023-41090-L001_2.fastp.fastq.gz
    downloads+=("nxf_az_download 'https://hhibiobatchstorage.blob.core.windows.net/nextflow-work/work/02/1c14bcfb7ebe2a3c40632de2e6d8ea/0001.STRAN-2023-41090-L001_1.fastp.fastq.gz' 0001.STRAN-2023-41090-L001_1.fastp.fastq.gz")
    downloads+=("nxf_az_download 'https://hhibiobatchstorage.blob.core.windows.net/nextflow-work/work/02/1c14bcfb7ebe2a3c40632de2e6d8ea/0001.STRAN-2023-41090-L001_2.fastp.fastq.gz' 0001.STRAN-2023-41090-L001_2.fastp.fastq.gz")
    downloads+=("nxf_az_download 'https://hhibiobatchstorage.blob.core.windows.net/nextflow-work/work/02/1c14bcfb7ebe2a3c40632de2e6d8ea/0002.STRAN-2023-41090-L001_2.fastp.fastq.gz' 0002.STRAN-2023-41090-L001_2.fastp.fastq.gz")
    downloads+=("nxf_az_download 'https://hhibiobatchstorage.blob.core.windows.net/nextflow-work/work/02/1c14bcfb7ebe2a3c40632de2e6d8ea/0003.STRAN-2023-41090-L001_2.fastp.fastq.gz' 0003.STRAN-2023-41090-L001_2.fastp.fastq.gz")
    downloads+=("nxf_az_download 'https://hhibiobatchstorage.blob.core.windows.net/nextflow-work/work/02/1c14bcfb7ebe2a3c40632de2e6d8ea/0002.STRAN-2023-41090-L001_1.fastp.fastq.gz' 0002.STRAN-2023-41090-L001_1.fastp.fastq.gz")
    downloads+=("nxf_az_download 'https://hhibiobatchstorage.blob.core.windows.net/nextflow-work/work/02/1c14bcfb7ebe2a3c40632de2e6d8ea/0003.STRAN-2023-41090-L001_1.fastp.fastq.gz' 0003.STRAN-2023-41090-L001_1.fastp.fastq.gz")
    downloads+=("nxf_az_download 'https://hhibiobatchstorage.blob.core.windows.net/nextflow-work/work/02/1c14bcfb7ebe2a3c40632de2e6d8ea/0004.STRAN-2023-41090-L001_1.fastp.fastq.gz' 0004.STRAN-2023-41090-L001_1.fastp.fastq.gz")
    downloads+=("nxf_az_download 'https://hhibiobatchstorage.blob.core.windows.net/nextflow-work/work/64/e69731cd9d1b1a09cc5bb2e7063a81/bwa' bwa")
    downloads+=("nxf_az_download 'https://hhibiobatchstorage.blob.core.windows.net/nextflow-work/work/02/1c14bcfb7ebe2a3c40632de2e6d8ea/0004.STRAN-2023-41090-L001_2.fastp.fastq.gz' 0004.STRAN-2023-41090-L001_2.fastp.fastq.gz")
    nxf_parallel "${downloads[@]}"
}

nxf_unstage() {
    true
    nxf_az_upload .command.out 'https://hhibiobatchstorage.blob.core.windows.net/nextflow-work/work/0f/9d58dfbe102a22fbebebf933e65807' || true
    nxf_az_upload .command.err 'https://hhibiobatchstorage.blob.core.windows.net/nextflow-work/work/0f/9d58dfbe102a22fbebebf933e65807' || true
    nxf_az_upload .command.trace 'https://hhibiobatchstorage.blob.core.windows.net/nextflow-work/work/0f/9d58dfbe102a22fbebebf933e65807' || true
    [[ ${nxf_main_ret:=0} != 0 ]] && return
    uploads=()
    IFS=$'\n'
    for name in $(eval "ls -1d *.bam *.cram *.csi *.crai versions.yml" | sort | uniq); do
        uploads+=("nxf_az_upload '$name' 'https://hhibiobatchstorage.blob.core.windows.net/nextflow-work/work/0f/9d58dfbe102a22fbebebf933e65807'")
    done
    unset IFS
    nxf_parallel "${uploads[@]}"
}

nxf_main() {
    trap on_exit EXIT
    trap on_term TERM INT USR2
    trap '' USR1

    [[ "${NXF_CHDIR:-}" ]] && cd "$NXF_CHDIR"
    NXF_SCRATCH=''
    [[ $NXF_DEBUG > 0 ]] && nxf_env
    echo start > .command.begin
    set +u
    set -u
    export PYTHONNOUSERSITE="1"
    export R_PROFILE_USER="/.Rprofile"
    export R_ENVIRON_USER="/.Renviron"
    export JULIA_DEPOT_PATH="/usr/local/share/julia"
    export PATH="$PWD/.nextflow-bin:$AZ_BATCH_NODE_SHARED_DIR/bin/:$PATH"
    export AZCOPY_LOG_LOCATION="$PWD/.azcopy_log"
    export AZ_SAS="sv=2024-05-04&st=2026-07-10T10%3A06%3A03Z&se=2026-07-12T10%3A06%3A03Z&skoid=581ced30-0003-4984-ae98-6f7ad741d64a&sktid=6cafdd50-12af-44a6-a6ee-4038c64f56bb&skt=2026-07-10T10%3A06%3A03Z&ske=2026-07-12T10%3A06%3A03Z&sks=b&skv=2024-05-04&sr=c&sp=racwdltm&sig=ufOH5eHSlFmtA9bVEyWw57zn1LtHlm6jTHzZgu%2BhFO4%3D"
    [[ $NXF_SCRATCH ]] && cd $NXF_SCRATCH
    export NXF_TASK_WORKDIR="$PWD"
    nxf_stage

    set +e
    (set -o pipefail; (nxf_launch | tee .command.out) 3>&1 1>&2 2>&3 | tee .command.err) &
    pid=$!
    wait $pid || nxf_main_ret=$?
    nxf_unstage
}

$NXF_ENTRY
