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

#-----------------------------------------------------------------------------
# Setup Profile Environment.
#
# It is used by making start and stop calls for different regions.
# The regions are identified by a label.
# E.g:
#
#  profile_start_timing SETUP
#  <whatever setup code>
#  profile_stop_timing SETUP
#  ...
#  profile_start_timing MAIN
#  <main code>
#  profile_stop_timing MAIN
#  ...
#  profile_report <reference>
#
# The last step prints a timing table for each label with output:
#
#   SETUP       234.0
#   MAIN        26.0
#
# The timing is by default given in milliseconds.
# If, however, the <reference> is given, eg, "MAIN",
# the the timing is relative to that particular label:
#
#   SETUP       9.0
#   MAIN        1.0
#
# None of the functions are exported as the DB is a dictionary (which cannot be exported).
# Hence the profiling must be kept within one shell.
#
#-----------------------------------------------------------------------------


# DB with timing data per label
# It's a string of format:"
# "<N> <sum time> <last call to start>"
declare -A PROFILE_DB_TIMING

# on/off flag for profiling
PROFILE_ON=0

_calc() {
    awk "BEGIN{ print $* }"
}

profile_on()  { PROFILE_ON=1; }
profile_off() { PROFILE_ON=0; }
profile_clear() {
    unset PROFILE_DB_TIMING
    declare -A PROFILE_DB_TIMING
}

profile_reset_timing() {
    [[ $PROFILE_ON -eq 1 ]] || return 0
    local lbl="$1"
    [[ -n ${PROFILE_DB_TIMING["$lbl"]-} ]] && PROFILE_DB_TIMING["$lbl"]="0 0 x"
}

profile_start_timing() {
    [[ $PROFILE_ON -eq 1 ]] || return 0
    local lbl="$1"
    local data=("")
    local T=$(date +'%s%N')
    data=( ${PROFILE_DB_TIMING["$lbl"]-} )
    if [[ ${#data[@]} -gt 0 ]]; then
        N=${data[0]}
        PROFILE_DB_TIMING["$lbl"]="$((N+1)) ${data[1]} $T"
    else
        PROFILE_DB_TIMING["$lbl"]="1 0 $T"
    fi
}

profile_stop_timing() {
    [[ $PROFILE_ON -eq 1 ]] || return 0
    local lbl="$1"
    local data=( ${PROFILE_DB_TIMING["$lbl"]-} )
    [[ ${#data[@]} -gt 0 ]] || return 255
    local T=$(date +'%s%N')
    local Tstart=${data[2]}
    # if Tstart is 'x' -> no start_timing has been called
    [[ "$Tstart" == "x" ]] && return 255
    local dT=$((T-Tstart))
    local dTold=${data[1]}
    PROFILE_DB_TIMING["$lbl"]="${data[0]} $((dTold+dT)) x"
}

profile_report() {
    [[ $PROFILE_ON -eq 1 ]] || return 0
    local ref=""
    [ $# -eq 1 ] && ref="$1"
    local x=""
    local Tref=1000000.0
    local tunit="ms"
    if [[ -n $ref ]]; then
        dref=( ${PROFILE_DB_TIMING[$ref]-} )
        [[ ${#dref[@]} -gt 0 ]] && { Tref=${dref[1]}; tunit=$ref; }
    fi

    # sort keys
    local keys=""
    keys=$(for x in ${!PROFILE_DB_TIMING[@]}; do echo $x; done | sort)

    echo
    printf "%0.s~" $(seq 1 80); echo
    printf "%-30s %12s %20s\n" "LABEL" "N(calls)" "TIME[$tunit]"
    printf "%0.s~" $(seq 1 80); echo
    # loop over keys
    local sumdt=0
    local sumN=0
    for x in $keys; do
        local data=( ${PROFILE_DB_TIMING[$x]} )
        local N=${data[0]}
        local T=${data[1]}
        local dt=$(_calc "$T/$Tref")
        sumdt=$(_calc $sumdt+$dt)
        sumN=$((sumN+N))
        printf "%-30s %12d %20.3f\n" "$x" "$N" "$dt"
    done
    sumdt=$(_calc $sumdt-1.0)
    printf "%-30s %12d %20.3f\n" "Total" "$sumN" "$sumdt"
    echo
}
