#!/bin/bash
#< Swap application versions by maintaining a symlink

AWK="/usr/bin/awk"
BASENAME="/usr/bin/basename"
CUT="/usr/bin/cut"
ECHO="/bin/echo"
GREP="/usr/xpg4/bin/grep"
LN="/bin/ln"
LS="/bin/ls"
PRINTF="/usr/bin/printf"
RM="/usr/bin/rm"
WC="/usr/bin/wc"

CONF_FILE="/usr/local/etc/swapapp.conf"
## conf file lines should be as follows:
# appname:path:prefix:symlink
THIS_PROG=$( ${BASENAME} $0 )


VERBOSE=0

function print_error {
	${ECHO} "Error: $@" >&2 	
}

function printv {
	(( VERBOSE )) && {
		${ECHO} "--> $@"
	}
}

function print_usage {
	{
		${ECHO} "Usage: ${THIS_PROG} [-hv] [-c <conf_file>]  [-A|-a <application> [-l|-V <ver>]]"
		${ECHO} "       -a    Specify application"
		${ECHO} "       -c    Specify path to configuration file (default: ${CONF_FILE})"
		${ECHO} "       -h    Display this usage message"
		${ECHO} "		-l    List available versions"
		${ECHO} "		-v    Verbose mode"
		${ECHO} "       -A    List available applications"
		${ECHO} "       -V    Specify version"
	} >&2
}

function check_conf_exists {
	if [ ! -f "${CONF_FILE}" ]; then
		print_error "Could not find configuration file ${CONF_FILE}"
		exit 1
	fi
}

function list_available_applications {
	CONF_LINES=$( ${WC} -l < ${CONF_FILE} )
	if [ "${CONF_LINES}" -eq "0" ]; then
		${ECHO} "No applications configured"
		exit 0
	fi
	${PRINTF} "%-20s\t%-20s\t%-20s\t%-s\n" "Application" "Prefix" "Link" "Path"
	while read LINE; do
		NUM_FIELDS=$( ${ECHO} "${LINE}" | ${AWK} 'BEGIN { FS = ":" } { print NF }' )
		if [ "${NUM_FIELDS}" -ne "4" ]; then
			print_error "Malformed configuration line"
			exit 1
		fi
		F_APPNAME=$( ${ECHO} "${LINE}" | ${CUT} -d: -f1 )
		F_PATH=$( ${ECHO} "${LINE}" | ${CUT} -d: -f2 )
		F_PREFIX=$( ${ECHO} "${LINE}" | ${CUT} -d: -f3 )
		F_LINK=$( ${ECHO} "${LINE}" | ${CUT} -d: -f4 )
		${PRINTF} "%-20s\t%-20s\t%-20s\t%-s\n" "${F_APPNAME}" "${F_PREFIX}" "${F_LINK}" "${F_PATH}"
	done < ${CONF_FILE}
}

function list_available_versions {
	if [ -z "${APP_NAME}" ]; then
		print_error "-a option mandatory with -l"
		exit 1
	fi
	${GREP} -qs "^${APP_NAME}:" ${CONF_FILE}
	if [ "$?" -ne "0" ]; then
		print_error "${APP_NAME} is not a configured application"
		exit 1
	fi
	NUM_DEF=$( ${GREP} "^${APP_NAME}:" ${CONF_FILE} | ${WC} -l )
	if [ "${NUM_DEF}" -ne "1" ]; then
		print_error "${APP_NAME} not unique application name"
		exit 1
	fi
	LINE=$( ${GREP} "^${APP_NAME}:" ${CONF_FILE} )
	F_APPNAME=$( ${ECHO} "${LINE}" | ${CUT} -d: -f1 )
	F_PATH=$( ${ECHO} "${LINE}" | ${CUT} -d: -f2 )
	F_PREFIX=$( ${ECHO} "${LINE}" | ${CUT} -d: -f3 )
	F_LINK=$( ${ECHO} "${LINE}" | ${CUT} -d: -f4 )
	${LS} -ld ${F_PATH}/${F_PREFIX}* >/dev/null 2>&1
	if [ "$?" -ne "0" ]; then
		print_error "No installed versions of ${APP_NAME} exist"
		exit 1
	else
		${LS} -ld ${F_PATH}/${F_PREFIX}* | ${GREP} '^d' | while read LINE; do
			FILE="${LINE##*/}"
			VERSION="${FILE#apache-*}"			
			${ECHO} "${VERSION}"
		done
	fi
		
}

function change_version {
    if [ -z "${APP_NAME}" ]; then
        print_error "-a option mandatory with -l"
        exit 1
    fi
    ${GREP} -qs "^${APP_NAME}:" ${CONF_FILE}
    if [ "$?" -ne "0" ]; then
        print_error "${APP_NAME} is not a configured application"
        exit 1
    fi
    NUM_DEF=$( ${GREP} "^${APP_NAME}:" ${CONF_FILE} | ${WC} -l )
    if [ "${NUM_DEF}" -ne "1" ]; then
        print_error "${APP_NAME} not unique application name"
        exit 1
    fi
    LINE=$( ${GREP} "^${APP_NAME}:" ${CONF_FILE} )
    F_APPNAME=$( ${ECHO} "${LINE}" | ${CUT} -d: -f1 )
    F_PATH=$( ${ECHO} "${LINE}" | ${CUT} -d: -f2 )
    F_PREFIX=$( ${ECHO} "${LINE}" | ${CUT} -d: -f3 )
    F_LINK=$( ${ECHO} "${LINE}" | ${CUT} -d: -f4 )
    ${LS} -ld ${F_PATH}/${F_PREFIX}* >/dev/null 2>&1
    if [ "$?" -ne "0" ]; then
        print_error "No installed versions of ${APP_NAME} exist"
        exit 1
    else
		if [ ! -d "${F_PATH}/${F_PREFIX}${NEW_VER}" ]; then
			print_error "${F_APPNAME} version ${NEW_VER} is not installed"
			exit 1
		else
			if [ -L "${F_PATH}/${F_LINK}" ]; then
				${RM} -f ${F_PATH}/${F_LINK}
			fi
			cd ${F_PATH}
			${LN} -s ${F_PREFIX}${NEW_VER} ${F_LINK} >/dev/null 2>&1
			if [ -L "${F_PATH}/${F_LINK}" ]; then
				${ECHO} "${F_APPNAME} version ${NEW_VER} now active"
			else
				print_error "Could not activate ${F_APPNAME} version ${NEW_VER}"
				exit 1
			fi
		fi
	fi
}

#
# main()
#
while getopts ":ha:c:lvAV:" OPTION; do
	case ${OPTION} in
		"a")	APP_NAME="${OPTARG}"		;;
		"c")	CONF_FILE="${OPTARG}"		;;
		"h")	print_usage && exit 0		;;
		"l")	LIST_MODE="VER"				;;
		"v")	VERBOSE=1					;;
		"A")	LIST_MODE="APP"				;;
		"V")	NEW_VER="${OPTARG}"			;;
		*  )	print_usage && exit 1		;;
	esac
done

shift $(( ${OPTIND} - 1 ))

if [ "$#" -ne "0" ]; then
	print_usage && exit 1
fi

check_conf_exists

if [ -n "${LIST_MODE}" ]; then
	case ${LIST_MODE} in
		"APP" )	list_available_applications	;;
		"VER" )	list_available_versions		;;
		*	  ) 							;;
	esac
fi

if [ -n "${NEW_VER}" ]; then
	change_version
fi

exit 0