#!/usr/bin/env bash
#
# orthologer - Pipeline for deducing orthology from fasta files.
# Copyright (C) 2005-2023 E. Zdobnov lab: F. Tegenfeldt
# <fredrik.tegenfeldt@unige.ch> based on code by E. Kriventseva
#
# This file is part of orthologer.
#
# orthologer is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# orthologer is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with orthologer.  If not, see <http://www.gnu.org/licenses/>.
#
#
# Run given aligner algorithm AND find BRH's
# The command line format is
#   run_alignbrh.sh <label Query>,<label DB>
#
#--- check if environment is ok -----------------
[[ "${LOADED_COMMON_ORTHODB_SH+1}" == "" ]] && echo "ERROR $0 : main config has not been loaded" 1>&2 && exit 255
#------------------------------------------------

[[ $# -eq 1 ]] || fatal_msg "usage: $0 <label Query,label DB,nthreads>;<...>;<...>;..."
input="$1"
inparr=( $(tokenize ";" $input) )

#OUTPUT_MAYBE_BRH=0
#if [[ ${ALIGNMENT_LABEL} == "MMSEQS" ]]; then
#    if (( MMSEQS_ALIGN_MODE == 1 )); then
#        # use 'mmseqs search'
#        ALIGNMENT_SCRIPT=${ALIGNMENT_SCRIPT//_mmseqs/_smmseqs}
##    elif (( MMSEQS_ALIGN_MODE == 2 )); then
##        # use 'mmseqs rbh' if A and B are different, otherwise 'mmseqs search'
##        ALIGNMENT_SCRIPT=${ALIGNMENT_SCRIPT//_mmseqs/_mmseqs_brh}
##        OUTPUT_MAYBE_BRH=1
#    fi
#fi

info_msg "Alignment script: $ALIGNMENT_SCRIPT"

# setup environment
# 1. alignment options common to all
# 2. tmp files to be used for all
__ALIGNMENT_OPTS=""
source $ALIGNMENT_SCRIPT
(( ALIGNMENT_EC )) && fatal_msg "Aligner disabled! Please choose another one - mmseqs or diamond"
nok=0
nerr=0

# make tmp fasta and output files
tmpout=""
tmpdir=""

tmp_make_dir tmpdir "align"        || exit 255

info_msg "Sequences DB dir : $DIR_PROJECT_SEQUENCES" 

# assoc array of files to copy
# results[<tmpfile>] = <target file>

move_files="echo 'move files'"

# used by run_makebrh_base
fuzzyOpts=""
if [[ $MAKEBRH_NALT -gt 1 ]]; then
    fuzzyOpts="--Nalt $MAKEBRH_NALT --fsepmax $MAKEBRH_FSEPMAX"
fi

fsAprev=""
fsBprev=""
fBA=""
# loop over all pairs of A,B
for args in ${inparr[@]}; do
    argsarr=( $(tokenize "," $args) )
    [[ ${#argsarr[@]} -eq 3 ]] || fatal_msg "run_alignment.sh: invalid input ($input), expected comma separated list <idA0,idB0,N;idA1,idB2,N;...> but got <$input>";

    # label pair A,B
    A="${argsarr[0]}"
    B="${argsarr[1]}"

    # check if labels are equal
    equal=0
    [[ $A == $B ]] && equal=1

    # nr of threads
    nthreads=${argsarr[2]}

    # temporary output with the final name
    fAB="$tmpdir/${A}_${B}.${EXT_ALIGN}"
    
    info_msg "Starting alignment job <$A,$B> with N(threads)=$nthreads"

    # get fasta names - without potential compression extension
    fsA="${DIR_PROJECT_SEQUENCES}/${A}.${EXT_FASTA_SELECTED}"
    fsB="${DIR_PROJECT_SEQUENCES}/${B}.${EXT_FASTA_SELECTED}"

    # target file name
    fAlign="${DIR_PROJECT_PWC}/$A/${A}_${B}.${EXT_ALIGN}"
    fBRH="${DIR_PROJECT_PWC}/$A/${A}_${B}.${EXT_BRH}"

    # these will be softlinks to the original fasta
    tmpA="$tmpdir/${A}.${EXT_FASTA_SELECTED}"
    tmpB="$tmpdir/${B}.${EXT_FASTA_SELECTED}"
    
    # softlink DB files wrt tmpA and tmpB
    # this will also verify the existance of the formatdb files
    if [[ $fsA != $fsAprev ]]; then
        ln -sf  "$fsA" "$tmpA" || exit 255
        link_formatdb_files "$fsA" "$tmpA" || exit 255
    fi

    # check if A B are equal
    if (( equal == 0 )); then
        if [[ $fsB != $fsBprev ]]; then
            ln -sf  "$fsB" "$tmpB" || exit 255
            link_formatdb_files "$fsB" "$tmpB" || exit 255
        fi
    else
        # labels are the same -> use the same files as input
        tmpB="$tmpA"
    fi

    # save last A
    fsAprev="$fsA"
    fsBprev="$fsB"

    # run alignment
    source "$ALIGNMENT_SCRIPT" "$tmpA" "$tmpB" "$fAB" $nthreads
    if (( ALIGNMENT_EC == 0 )); then
        move_files="$move_files && mv -f $fAB $fAlign"
        nok=$((nok+1))
    else
        eval $move_files
        fatal_msg "failed finding alignment for key pair [$A,$B] with error $ALIGNMENT_EC"
    fi
    info_msg "alignment done"

    # continue with BRH files only if alignment matrix is half
    # OR if A==B then there is no BRH by definition
    if (( ALIGNMENT_MATRIX == 0 )) || (( equal )); then
        info_msg "skipping BRH part (running full matrix or A==B)"
        info_msg "DONE alignment job <$A,$B>, exit code = $ALIGNMENT_EC"
        continue
    fi
    
    # create BRH files
    if (( ALIGNMENT_EC == 0 )); then
        info_msg "extract BRHs"
        
        # nthreads, fAB, fBA, fuzzyOpts are already set
        # just need to set output
        output="$tmpdir/${A}_${B}.${EXT_BRH}"
        
        # run makebrh, uses the variable nthreads,fAB,fBA,output and fuzzyOpts
        source $DIR_ORTHOLOGER/bin/run_makebrh_base.sh 

        if [[ $MAKEBRH_EC -ne 0 ]]; then
            eval $move_files
            fatal_msg "failed finding BRHs for key pair [$A,$B] with error $MAKEBRH_EC"
        fi
        chmod 644 "$output"
        move_files="$move_files && mv -f $output $fBRH"
        
        info_msg "extracting BRHs DONE"
    fi
    
    info_msg "DONE alignbrh job <$A,$B>, exit code = $ALIGNMENT_EC"
    
done

# move all files
verbose_info_msg "MOVING FILES: $move_files"
eval $move_files
[[ $? -eq 0 ]] || nerr=$((nerr+1))

# check if any errors
[[ $nerr -eq 0 ]] || fatal_msg "Completed $nok succesfully and $nerr with errors"
info_msg "DONE - completed $nok alignments"

###profile_report "ALIGNMENT"
