#!/bin/bash -e

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

MB_HOME_DIR=${TE_INSTALL_DIR}"media_broker"

FAS_HOME_DIR=${TE_INSTALL_DIR}"FAS"

FAS_BASE_DIR=${FAS_HOME_DIR}"/domain"
FAS_LOG_DIR=${FAS_BASE_DIR}

# FAS configuration directory
FAS_CONF_DIR=${FAS_BASE_DIR}"/configuration"
# FAS log directory
FAS_LOG_DIR=${FAS_BASE_DIR}"/servers/"

APPSERVER_HOME_DIR=${FAS_LOG_DIR}"appserver-registrar"
LB_HOME_DIR=${FAS_LOG_DIR}"loadbalancer-registrar"
APPSERVER_CONF=$FAS_HOME_DIR/domain/configuration/

# Get the current directory
PRESENT_DIR=$PWD
cd $PRESENT_DIR

# Change to each log directory

ALL_DIR_FILES=""

for dir in $MB_HOME_DIR $FAS_LOG_DIR $APPSERVER_HOME_DIR $LB_HOME_DIR
do
  if [ -e $dir ]
  then
   cd $dir

   baseServerLogDirArray=( `find . -name '*.log' | sort -u` )

   for i in ${baseServerLogDirArray[@]}
   do
     logFile="${dir}/${i}"

     ALL_DIR_FILES=${ALL_DIR_FILES}" "${logFile}
   done
  fi
done

# Change back to the current directory before continuing with this script
cd $PRESENT_DIR

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

function assertValidInterfaceSpecified()
{
    if [ -n "${DO_PCAP}" ]
    then
        AVAILABLE_INTERFACES=`tcpdump -D`

        if [[ "${AVAILABLE_INTERFACES}" =~ "${INTERFACE_NAME}" ]]; then
            echo "Capturing interface: ${INTERFACE_NAME}"
        else
            echo "Error: The specified interface was not found"
            printHelp
        fi
    fi
}

function getJdkExecutable()
{
    local _exe_name=$1

    local _java_home=`which java | sed 's/.\{4\}$//'`

    local _jdk_executable=$_java_home$_exe_name

    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 createOutputDirectory()
{
    mktemp -d logcapture.temp-XXX
}

function createLogFileCapturingDaemons()
{
    local _captured_dir=$1

    local _original_log_files=${ALL_DIR_FILES}
    
    for _original_log in ${_original_log_files}
    do
        local _captured_log_file=${_captured_dir}${_original_log}

        mkdir -p $(dirname ${_captured_log_file})
        tail -n 0 -F ${_original_log} > ${_captured_log_file} &
        CAPTURE_PROC_IDS="${CAPTURE_PROC_IDS} $!"
    done
}

function copyNewLogFileOutput()
{
    local _output_dir=$(createOutputDirectory)
    CAPTURE_PROC_IDS=""

    createLogFileCapturingDaemons "${_output_dir}"

    if [ -n "${DO_PCAP}" ]
    then
        if [ -e /usr/sbin/tcpdump ]
        then
            tcpdump -i ${INTERFACE_NAME} -q -s0 -vvv -w ${_output_dir}/tcpdump.pcap  &
            CAPTURE_PROC_IDS="${CAPTURE_PROC_IDS} $!"
       elif [ -x /usr/sbin/tshark ]
        then
            tshark -i ${INTERFACE_NAME} -w ${_output_dir}/tshark.pcap  &
            CAPTURE_PROC_IDS="${CAPTURE_PROC_IDS} $!"
        fi
    fi

    trap "killCopyingBgroundProcesses \"${CAPTURE_PROC_IDS}\"" INT TERM
    trap "collateAllFiles \"${_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 $(pgrep -P ${_controller_pid})
    fi
}

function collateAllFiles()
{
    local _output_dir=$1

    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 -p ${_pid} -o command | sed 1d | 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_LOG_DIR}${_fas_server_name}/thread.dump
                [ -n "$DO_MEMORY" ] && $JMAP_EXE -dump:live,format=b,file=${FAS_LOG_DIR}${_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_HOME_DIR}/thread.dump
            [ -n "$DO_MEMORY" ] && $JMAP_EXE -dump:live,format=b,file=${MB_HOME_DIR}/heap.bin $_mb_pid
        fi
    fi

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

        if [ -n "$MB_HOME_DIR" ]
        then
            cp -r ${MB_HOME_DIR}/*.properties ${_output_dir}/${MB_HOME_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] [-t] [-m] [-n] [-p interface] -f tarfile
    Archives log files to the specified tar file

    -f	   	The name of the tar file
Optional:
    -c      Optional: This will include configuration files
    -t      Optional: This will include thread dumps of AS and MB in the tar file
    -m      Optional: This will include heap memory dumps of AS and MB in the tar file
    -n      Optional: Do NOT clean up output directory at end of run
    -p      Optional: Capture network traffic from a specific interface in a pcap file e.g. -p en0
    -a      Optional: All optional options
    -h      Display this help message
EOF
}

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

TEMP=`getopt hcmnp:taf: $*`

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

eval set -- "$TEMP"
while true ; do
	case "$1" in
		-c)		DO_CONFIG=true;	shift 1;; 
		-f)		TARFILE=$2;	shift 2;;
		-t)		DO_THREADS=true;	shift 1;; 
		-m)		DO_MEMORY=true;	shift 1;; 
		-n)	    DO_NOT_CLEAN=true;	shift 1;; 
		-p)	    DO_PCAP=true;	INTERFACE_NAME=$2;  shift 2;; 
		-a)		DO_MEMORY=true;	DO_THREADS=true; DO_CONFIG=true; shift 1;; 
		-h)		help=true;	shift 1;; 
		--) shift; break;;
		*) echo "Internal error!"; exit 1;;
	esac
done

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

assertTarFileSpecified
assertValidInterfaceSpecified

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

copyNewLogFileOutput
