#!/bin/bash -e

function assertTarFileSpecified()
{
    if [ -z "${TARFILE}" ]
    then
        printHelp
        printError "Error: Tar filename has not been specified"
    fi
}

function getJdkExecutable()
{
    local _list_conf_files=$1
    local _exe_name=$2

    local _jdk_executable=""
    for _conf_file in $_list_conf_files
    do
        if [ -n "${_conf_file}" ] && [ -f "${_conf_file}" ]
        then
            local _java_home=$(grep -i 'JAVA_HOME=' $_conf_file  | cut -f2 -d'=')
            if [ -n "$_java_home" ]
            then
                _jdk_executable=$_java_home/bin/$_exe_name
                break
            fi
        fi
    done

    if [ -z "$_jdk_executable" ]
    then
        printError "Cannot find $_exe_name"
    fi

	if [ ! -x $_jdk_executable ]
	then
        printError "$_jdk_executable is not executable"
	fi

    echo $_jdk_executable
}

function getListOfLogFiles()
{
    local _dir=$1

    local _log_files=""
    local _pwd=$PWD

    if [ -d $_dir ]
    then
        cd $_dir

        baseServerLogDirArray=$(find -name "*.log"  -o \( -path "*/log/*" -name "*.xml" \) | sort -u)

        for i in ${baseServerLogDirArray[@]}
        do
            _log_files=${_log_files}" "$(readlink -f $i)
        done

        cd $_pwd
    fi

    echo ${_log_files}
}

function createOutputDirectory()
{
    mktemp -d logcapture.temp-XXX
}

function createLogFileCapturingDaemons()
{
    local _original_log_dir=$1
    local _captured_dir=$2

    if [ -d "${_original_log_dir}" ]
    then
        local _original_log_files=$(getListOfLogFiles "${_original_log_dir}")
    
        for _original_log in ${_original_log_files}
        do
            local _captured_log_file=${_captured_dir}/$(convertToRelativePath "${_original_log}" "${_original_log_dir}")
            mkdir -p $(dirname ${_captured_log_file})
            tail -n 0 -F ${_original_log} > ${_captured_log_file} &
            CAPTURE_PROC_IDS="${CAPTURE_PROC_IDS} $!"
        done
    fi
}

function copyNewLogFileOutput()
{
    local _output_dir=$(createOutputDirectory)
    local _fas_output_dir=${_output_dir}/FAS
    local _mb_output_dir=${_output_dir}/MB
    CAPTURE_PROC_IDS=""

    if [ -n "${FAS_BASE_DIR}" ]
    then
        createLogFileCapturingDaemons "${FAS_BASE_DIR}" "${_fas_output_dir}"
    fi

    if [ -n "${MB_HOME_DIR}" ]
    then
        createLogFileCapturingDaemons "${MB_HOME_DIR}" "${_mb_output_dir}"
    fi

    if [ -n "${DO_PCAP}" ]
    then
        local _capture_cmd=""
        if [ -x /usr/sbin/tcpdump ]
        then
            _capture_cmd="tcpdump -q -s0 -vvv -w ${_output_dir}/tcpdump.pcap "
        elif [ -x /usr/sbin/tshark ]
        then
            _capture_cmd="tshark -w ${_output_dir}/tshark.pcap "
        fi

        if [ -n "${_capture_cmd}" ]
        then
            ${_capture_cmd} -i any 2>/dev/null &
            CAPTURE_PROC_IDS="${CAPTURE_PROC_IDS} $!"
        fi
    fi

    if [ -n "$DO_VMSTAT" ]
    then
        vmstat 2 > ${_output_dir}/vmstat.out &
        CAPTURE_PROC_IDS="${CAPTURE_PROC_IDS} $!"
    fi

    trap "killCopyingBgroundProcesses \"${CAPTURE_PROC_IDS}\"" INT TERM
    trap "collateAllFiles \"${_output_dir}\" \"${_fas_output_dir}\" \"${_mb_output_dir}\" \"${TARFILE}\"" EXIT

    echo "*****************************************************"
    echo "* Capturing files to directory ${_output_dir}  *"
    echo "* Press <CTL>-C when ready to tar up captured files *"
    echo "*****************************************************"
    wait ${CAPTURE_PROC_IDS}
}

# Returns a relative path of the first argument.
# The second argument contains a list of directory names to strip from the first argument
# e.g If the first arg is "/foo/bar/file.txt" and the second argument contained "/foo", the returned string would be
# "bar/file.txt"
function convertToRelativePath()
{
    local _log_file=$1
    local _base_dir_list=$2

    for _dir in ${_base_dir_list}
    do
        if [ -n "${_dir}" ]
        then
            local _base_dir=""
            case ${_dir} in
                */) _base_dir="${_dir}" ;;
                *) _base_dir="${_dir}/" ;;
            esac
            _log_file=${_log_file#${_base_dir}}
        fi
    done

    echo ${_log_file}
}


function killCopyingBgroundProcesses()
{
    local _ppids="$1"

    echo -e "\nKilling daemon processes, please wait..."
    kill ${_ppids}
}

#Gets the PIDs that are children of the FAS Process Controller
function getFasChildPids()
{
    local _ps_controller_search_string="-D\\[Process Controller]"
    local _controller_pid=$(ps -ef | grep " ${_ps_controller_search_string}"| grep -vw grep | awk '{print $2}')
    if [ -n "${_controller_pid}" ]
    then
        echo $(ps --no-headers -o pid --ppid ${_controller_pid})
    fi
}

function collateAllFiles()
{
    local _output_dir=$1
    local _fas_output_dir=$2
    local _mb_output_dir=$3

    echo "Collating information, please wait..."

    if [ -n "$DO_THREADS" ] || [ -n "$DO_MEMORY" ]
    then
        local _ps_server_search_string="-D\\[Server:"
        local _fas_server_candidates=$(getFasChildPids)
        for _pid in ${_fas_server_candidates}
        do
            local _fas_server_name=$(ps --no-headers -o command --pid ${_pid}| grep " ${_ps_server_search_string}" | awk '{print $2}')
            # ^^^ $1 is "/.../java", $2 is "-D[Server:...]" (output from the ps command)
            if [ -n "${_fas_server_name}" ]
            then
                _fas_server_name=${_fas_server_name#${_ps_server_search_string}} #Strip the "-D[Server:" from the beginning
                _fas_server_name=${_fas_server_name%]} #Strip the trailing ']'

                [ -n "$DO_THREADS" ] && $JSTACK_EXE $_pid > ${_fas_output_dir}/servers/${_fas_server_name}/thread.dump
                [ -n "$DO_MEMORY" ] && $JMAP_EXE -dump:live,format=b,file=${_fas_output_dir}/servers/${_fas_server_name}/heap.bin $_pid >/dev/null
            fi
        done

        local _mb_pid=$(ps -ef | grep ' -jar rtp-proxy.jar'| grep -v grep | awk '{print $2}')
        if [ -n "$_mb_pid" ]
        then
            [ -n "$DO_THREADS" ] && $JSTACK_EXE $_mb_pid > ${_mb_output_dir}/thread.dump
            [ -n "$DO_MEMORY" ] && $JMAP_EXE -dump:live,format=b,file=${_mb_output_dir}/heap.bin $_mb_pid
        fi
    fi

    if [ -n "$DO_CONFIG" ]
    then
        if [ -n "$FAS_CONF_DIR" ]
        then
            mkdir -p ${_fas_output_dir}/configuration/
            local _conf_file_list=$(find ${FAS_CONF_DIR} -maxdepth 1 -type f)
            cp ${_conf_file_list} ${_fas_output_dir}/configuration/
        fi

        if [ -n "$MB_HOME_DIR" ]
        then
            cp -r ${MB_HOME_DIR}/*.properties ${_mb_output_dir}/
        fi
    fi

    echo "Creating tar file ${TARFILE} from directory ${_output_dir}"
    mkdir -p $(dirname ${TARFILE})
    tar -C ${_output_dir} -cf ${TARFILE} .

    if [ -z "${DO_NOT_CLEAN}" ]
    then
        rm -rf ${_output_dir}
    fi
}

function printError()
{
    echo
    echo "Error: " $* 1>&2
    exit 1
}

function printHelp()
{
    cat << EOF

Usage: $(basename $0) [-c] [-j] [-m] [-t] -f tarfile
    Archives log files to the specified tar file

    -f, --tar-file	   	The name of the tar file
Optional:
    -c, --config        Optional: This will include configuration files
    -t, --threads       Optional: This will include thread dumps of AS and MB in the tar file
    -m, --memory        Optional: This will include heap memory dumps of AS and MB in the tar file
    -n, --do-not-clean  Optional: Do NOT clean up output directory at end of run
    -p, --capture-pcap  Optional: Capture network traffic in a pcap file
    -v, --vmstat        Optional: This will include vmstat output in the tar file
    -a, --all           Optional: All optional options
    -h, --help          Display this help message
EOF
}

############################
#          Main            #
############################
progname=$(basename $0)

TEMP=$(getopt -o hcmnptavf: --long help,config,tar-file,memory,do-not-clean,capture-pcap,threads,all,vmstat: \
     -n ${progname} -- "$@")

if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi

eval set -- "$TEMP"
while true ; do
	case "$1" in
		-c|--config)		DO_CONFIG=true;	shift 1;; 
		-f|--tar-file)		TARFILE=$2;	shift 2;;
		-t|--threads)		DO_THREADS=true;	shift 1;; 
		-m|--memory)		DO_MEMORY=true;	shift 1;; 
		-n|--do-not-clean)	DO_NOT_CLEAN=true;	shift 1;; 
		-p|--capture-pcap)	DO_PCAP=true;	shift 1;; 
		-v|--vmstat)		DO_VMSTAT=true;	shift 1;; 
		-a|--all)			DO_MEMORY=true;	DO_THREADS=true; DO_VMSTAT=true; DO_CONFIG=true; DO_PCAP=true; shift 1;; 
		-h|--help)			help=true;	shift 1;; 
		--) shift; break;;
		*) echo "Internal error!"; exit 1;;
	esac
done

if [ "${help}" != "" ]
then
    printHelp
    exit 1
fi

assertTarFileSpecified

TE_INSTALL_DIR=$(ps -ef | grep [F]AS/domain/servers/appserver | sed 's/^.*-jar //' | sed 's/FAS.*//g')

if [ -z "$TE_INSTALL_DIR" ]
then
    echo "Unable to determine base directory of Trial Environment. It may not be running. Start it and try again."
    exit 1
fi



FAS_HOME_DIR=${TE_INSTALL_DIR}"FAS"
FAS_BASE_DIR=$FAS_HOME_DIR/domain
FAS_CONF_DIR=${FAS_BASE_DIR}/configuration

MB_HOME_DIR=${TE_INSTALL_DIR}"fusion_media_broker"


[ -n "$DO_MEMORY" ] && JMAP_EXE=$(getJdkExecutable "$FAS_CONF $MB_CONF" jmap)
[ -n "$DO_THREADS" ] && JSTACK_EXE=$(getJdkExecutable "$FAS_CONF $MB_CONF" jstack)

copyNewLogFileOutput

