#!/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/>.
#

# This script creates a file import description based on user input.
# Modes
# 1.  DIRECTORY
#     label using a counter OR basename of file
# 1.1 no extension -> all files
# 1.2 with ext     -> select *.ext
#
# 2.  DIRECTORY + LABEL MAP FILE
#     map file contains pairs <label> <filename>
#     only the basename of the filename is used

set -u
echoerr() {
    echo "${@}" 1>&2
}
# ensure consistent sorting
LANG=C

#--------------------------------------------------------
# variables to be set

# default by label
_BYCOUNTER=0

# if set to 1, expand to full dir
_EXPAND_DIR=0

# relabel
_RELABEL="+"

# output
_FOUTPUT=/dev/stdout

# counter padding - set by setPadding
_CPAD=0

# extension of input data
_EXTENSION=""

# file with label map
_LABEL_MAP=""

#--------------------------------------------------------
# get options
OPTIND=1
while getopts :cdnp:o:x:l: OPT; do
    case "$OPT" in
        c)  _BYCOUNTER=1
            ;;
        d)  _EXPAND_DIR=1
            ;;
        n)  _RELABEL=""
            ;;
        p)  _CPAD="$OPTARG"
            ;;
        o)  _FOUTPUT="$OPTARG"
            ;;
        x)  _EXTENSION="$OPTARG"
            ;;
        l)  _LABEL_MAP="$OPTARG"
            ;;
    esac
done

# if label map is selected, reset bycounter, extension and relabel
if [[ -n $_LABEL_MAP ]]; then
    _BYCOUNTER=0
    _EXTENSION=""
    _RELABEL="+"
fi

# ensure relabel is active with counter
(( _BYCOUNTER == 1 )) && _RELABEL="+"

#--------------------------------------------------------
# check remaining arguments
shift $(expr $OPTIND - 1 )
[[ $# -ge 1 ]] || {
    echo
    echo "usage: $0 [-c | -d | -n | -p <padding> | -o <output> | -x <extension> | -l <label map>] [<path>] ]"
    echo " -c             : label using a zero padded counter, otherwise use the file basename as label"
    echo " -d             : expand directory to absolute path"
    echo " -n             : do not relabel, ie do not add a '+' to the labels, only with -l"
    echo " -p <padding>   : force zero padding of given size - if not set it's based on the nr of files"
    echo " -l <lblmap>    : optional, map between labels and files found in <path>"
    echo " -x <extension> : optional, file extension to be selected in <path>"
    echo " -o <output>    : output file, if none is given it is stdev"
    echo
    echo "Files are selected either by path+optional extension or a collection of files."
    echo
    exit 0
}

farg=( $@ )
DATA_PATH=""
if [[ ${#farg[@]} -eq 1 ]]; then
    DATA_PATH="$1"
    [[ -d $DATA_PATH ]] || { echoerr "error: data path not readable $DATA_PATH"; exit 255; }
fi

if [[ ! -d $DATA_PATH ]]; then
    echoerr "error: no valid data path is given - path must be the last argument"
    exit 255
fi
   
#--------------------------------------------------------
# set the zero padding based on the nr of files
setPadding() {
    (( _CPAD == 0 )) || return
    local n=$1
    local np=$(awk "BEGIN{print log($n)/log(10);}")
    if [[ $np == ${np//./ } ]]; then
        _CPAD=$np
    else
        _CPAD=$(awk "BEGIN{print int(1+$np);}")
    fi
    local nx=$(awk "BEGIN{print int(10^$_CPAD);}")
    (( n > nx )) && _CPAD=$((_CPAD+1))
}

expandDir() {
    local f="$1"
    local fdir=$(dirname "$f")
    local edir=$(cd "$fdir" && pwd)
    echo "${edir}"/$(basename "$f")
}

#--------------------------------------------------------
# fill label map using given map file
fillLabelMap() {
    local ec=0
    [[ -f $_LABEL_MAP ]] || { echoerr "error: label map file does not exist $_LABEL_MAP"; return 255; }
    while read line; do
        local elems=( $line )
        local label="${_RELABEL}${elems[0]}"
        local fname=$DATA_PATH/$(basename "${elems[1]}")
        [[ -f "$fname" ]] || { echoerr "error: missing file $fname"; ec=1; }
        echo "$label $fname"
    done < $(grep -v '^#' $_LABEL_MAP)
    return $ec
}

fillLabelMapCounter() {
    local nfiles=$(ls $DATA_PATH/*$_EXTENSION | wc -l)
    setPadding $nfiles
    local N=0
    for x in $DATA_PATH/*$_EXTENSION; do
        local label=$_RELABEL$(printf "%0${_CPAD}d " $N)
        local fname=$x
        [[ -f "$fname" ]] || { echoerr "error: missing file $fname"; ec=1; }
        echo "$label $fname"
        N=$((N+1))
    done
    return $ec
}

fillLabelMapBasename() {
    local N=0
    for x in $DATA_PATH/*$_EXTENSION; do
        local label=$(basename $x)
        local fname=$x
        echo "$_RELABEL${label%%.*} $fname"
    done
    return 0
}

process() {
    if [[ -f "$_LABEL_MAP" ]]; then
        fillLabelMap || { echoerr "error: failed building import file from label map $_LABEL_MAP"; return 255; }
        
    elif (( _BYCOUNTER == 1 )); then
        fillLabelMapCounter || { echoerr "error: failed building import file from data path, labels are counters"; return 255; }

    else
        fillLabelMapBasename || { echoerr "error: failed building import file from data path, labels are reduced file names"; return 255; }
    fi
    return 0
}

#--------------------------------------------------------

echo "saving output to $_FOUTPUT"
ec=0
{
    process
    ec=$?
} > $_FOUTPUT
[[ $ec -eq 0 ]] || rm -f $_FOUTPUT
