#!/bin/bash

# Settings

declare JAR_NAME="mule-runtime-upgrade-tool-0.7.0-beta2.jar"
declare JAVA_BIN="java"
declare REQUIRED_BASH="3.2.57"
declare REQUIRED_JAVA="1.8.0"

# Global resources

declare C_GREY="\e[38;5;240m"		# Color grey
declare C_RESET="\e[39m"			# Color reset

# Global variables

declare JAVA_PATH
declare ACTION
declare MULE_HOME_OUTDATED
declare MULE_HOME_UPDATED

# Strings

declare -a MSG
MSG[0]="ERROR: %s version is %s, minimum required is %s\n"
MSG[1]="ERROR: Java binary not found neither in JAVA nor in JAVA_HOME, exiting\n"
MSG[2]="ERROR: Please use absolute paths for MULE_HOMEs\n"
MSG[3]="INFO: Mule Agent is outdated, running upgrade\n"
MSG[4]="INFO: Upgrading Mule Agent from %s to %s\n"
MSG[5]="INFO: Upgrade terminated with status %d\n"
MSG[6]="INFO: Mule Agent already up to date, skipping update\n"
MSG[7]="INFO: Mule Agent is not installed, stepping into the product upgrade\n"
MSG[8]="ERROR: MULE_HOME cannot be accessed\n"
MSG[9]="WARNING: Directory mule-agent-plugin will be deleted, please check the right path was chosen:\n\t%s\nAnd confirm with [y/n]: "
MSG[10]="INFO: Deleting content at %s\n"
MSG[11]="INFO: Extracting backup content from %s\n"
MSG[12]="ERROR: There was an error while trying to read the rollback directory at <%s>, or the backup file at <%s>\n"
MSG[13]="INFO: Rollback interrupted by user\n"
MSG[14]="INFO: Rollback completed\n"
MSG[15]="INFO: Backup file of Mule Agent not found, stepping into the product rollback\n"

function compare_versions () {

	declare -i ERR=0
	declare NAME

	NAME="${1}"                       # Set ${NAME}
	IFS="." read -a CUR <<< "${2}"    # Set ${CUR}
	IFS="." read -a REQ <<< "${3}"    # Set ${REQ}

	# Compare versions

	if [ ${CUR[0]} -lt ${REQ[0]} ]; then
		ERR=1
	elif [ ${CUR[0]} -eq ${REQ[0]} ]; then
		if [ ${CUR[1]} -lt ${REQ[1]} ]; then
			ERR=1
		elif [ ${CUR[1]} -eq ${REQ[1]} ]; then
			if [ ${CUR[2]} -lt ${REQ[2]} ]; then
				ERR=1
			fi
		fi
	fi

	# Report error

	if [ ${ERR} -ne 0 ]; then
		return 1
	else
		return 0
	fi
}

function check_bash_version () {

	declare -a \
		VERSION \
		ARGS

	declare \
		NAME \
		CUR \
		REQ

	VERSION[0]="${BASH_VERSINFO[@]:0:3}"
	VERSION[1]="${VERSION[0]// /.}"

	NAME="Bash"
	CUR="${VERSION[1]}"
	REQ="${REQUIRED_BASH}"
	ARGS=( ${NAME} ${CUR} ${REQ} )

	compare_versions ${ARGS[@]}
	if [ ${?} -ne 0 ]; then
		printf "${MSG[0]}" "${NAME}" "${CUR}" "${REQ}" 1>&2
		exit 1
	else
		return 0
	fi
}

function search_java_bin () {

	declare -i ERR=0

	# Search java in PATH
	# Look at JAVA_HOME if there's nothing in PATH

	type -p ${JAVA_BIN} &>/dev/null
	if [ ${?} -ne 0 ]; then
		JAVA_PATH="${JAVA_HOME}/bin/${JAVA_BIN}"
		if [ -f ${JAVA_PATH} ]; then
			if [ ! -x "${JAVA_PATH}" ]; then
				ERR=1
			fi
		else
			ERR=1
		fi
		if [ ${ERR} ]; then
			printf "${MSG[1]}"
			exit 1
		fi
	else
		JAVA_PATH=$(type -p ${JAVA_BIN})
	fi

	return 0
}

function check_java_version () {

	declare -a \
		JAVA_INFO \
		VERSION \
		ARGS

	declare \
		NAME \
		CUR \
		REQ

	IFS=$'\n'
	JAVA_INFO=( $( ${JAVA_PATH} -version 2>&1 ) )
	VERSION[0]="${JAVA_INFO[0]#*\"}"
	VERSION[1]="${VERSION[0]%\"*}"
	VERSION[2]="${VERSION[1]%_*}"

	NAME="Java"
	CUR="${VERSION[2]}"
	REQ="${REQUIRED_JAVA}"
	ARGS=( ${NAME} ${CUR} ${REQ} )

	compare_versions ${ARGS[@]}
	if [ ${?} -ne 0 ]; then
		printf "${MSG[0]}" "${NAME}" "${CUR}" "${REQ}" 1>&2
		exit 1
	else
		return 0
	fi
}

function run_validations() {

	check_bash_version
	search_java_bin
	check_java_version

	return 0
}

function parse_arguments () {

	# Read parameters to extract the MULE_HOMEs

	while [ -n "${1}" ]; do
		case "${1}" in

			"upgrade" | "rollback")
				ACTION="${1}"
				;;

			-o | -o=* | --old-mule-distro | --old-mule-distro=* )
				if [[ "${1}" == *=* ]]; then
					MULE_HOME_OUTDATED="${1#*=}"
				else
					shift 1
					test ${1} && MULE_HOME_OUTDATED="${1}"
				fi
				;;

			-n | -n=* | --new-mule-distro | --new-mule-distro=* )
				if [[ "${1}" == *=* ]]; then
					MULE_HOME_UPDATED="${1#*=}"
				else
					shift 1
					test ${1} && MULE_HOME_UPDATED="${1}"
				fi
				;;
	    esac
	    shift 1;
	done

	# Check that MULE_HOMEs are readable and avoid relative paths

	for i in "${MULE_HOME_OUTDATED}" "${MULE_HOME_UPDATED}"; do
		if [ ! -z "${i}" ]; then
			if [ -d "${i}" ]; then
				if [[ ! ${i} =~ ^/ ]]; then
					printf "${MSG[2]}" 1>&2
					exit 1
				fi
			else
				printf "${MSG[8]}" 1>&2
				exit 1
			fi
		fi
	done

	return 0
}

function setup_mule_agent () {

	# If the Mule Agent is installed in the current Mule distro, check
	# if the new distro ships a newer version of the Mule Agent
	# If it does, update current Mule Agent by taking it from the newer
	# distro

	if [ "${ACTION}" = "upgrade" ]; then

		declare -a \
			OUTDATED_JAR \
			UPDATED_JAR \
			OLD_VER \
			NEW_VER \
			ARGS \
			FILES

		declare \
			NAME \
			CUR \
			REQ

		# When upgrading, we need both -o and -n

		if [ -z "${MULE_HOME_OUTDATED}" -o -z "${MULE_HOME_UPDATED}" ]; then
			# The JAR will take care of this condition, return instead of exit:
			return 1
		fi

		OUTDATED_JAR=$( echo -n ${MULE_HOME_OUTDATED}/*plugins/mule-agent-plugin/lib/mule-agent-api-*.*.*.jar )
		UPDATED_JAR=$( echo -n ${MULE_HOME_UPDATED}/tools/agent-setup-*.*.*-amc-final.jar )

		# 1. Is the Agent installed?

		if [ -f ${OUTDATED_JAR} ]; then

				# 2. Get current version number from the above file

				OLD_VER[0]=${OUTDATED_JAR}
				OLD_VER[1]=${OLD_VER[0]##*/}
				OLD_VER[2]=${OLD_VER[1]%*.jar}
				OLD_VER[3]=${OLD_VER[2]##*-}

				# 3. Get the version number from the latest distribution

				NEW_VER[0]=${UPDATED_JAR}
				NEW_VER[1]=${NEW_VER[0]##*/}
				NEW_VER[2]=${NEW_VER[1]%-amc-final.jar}
				NEW_VER[3]=${NEW_VER[2]#agent-setup-}

				# 4. Compare versions

				NAME="Mule Agent"
				CUR="${OLD_VER[3]}"
				REQ="${NEW_VER[3]}"
				ARGS=( ${NAME} ${CUR} ${REQ} )

				compare_versions ${ARGS[@]}

				# 5. If comparison returned no error, upgrade

				if [ ${?} -ne 0 ]; then

					# These are the files we need to migrate manually
					FILES=(
						"bin/amc_setup*"
						"tools/agent-setup*"
					)

					printf "${MSG[3]}"
					printf "${MSG[4]}" "${OLD_VER[3]}" "${NEW_VER[3]}"

					# Copy individual files manually
					command \cp -f ${MULE_HOME_UPDATED}/${FILES[0]} ${MULE_HOME_OUTDATED}/bin/
					command \cp -f ${MULE_HOME_UPDATED}/${FILES[1]} ${MULE_HOME_OUTDATED}/tools/

					# Run the upgrade, output is greyed out
					echo -e "${C_GREY}"
					command ${JAVA_PATH} ${JAVA_OPTS} -jar "${UPDATED_JAR}" --update --mule-home "${MULE_HOME_OUTDATED}"
					echo -e "${C_RESET}"

					# Upgrade completed
					printf "${MSG[5]}" ${?}
				else
					printf "${MSG[6]}"
				fi
		else
			printf "${MSG[7]}"
			return 0
		fi

	elif [ "${ACTION}" = "rollback" ]; then

		declare \
			INSTALL_DIR \
			BACKUP_FILE

		INSTALL_DIR=$( echo -n ${MULE_HOME_OUTDATED}/*plugins/mule-agent-plugin )
		BACKUP_FILE=$( echo -n ${MULE_HOME_OUTDATED}/tools/mule-agent-backup.zip )

		# 1. Verify parameters: We only need -o when rolling-back

		if [ -z "${MULE_HOME_OUTDATED}" ]; then
			return 1
		fi

		# 2. Verify whether or not it's possible to do a rollback:

		if [ ! -f "${BACKUP_FILE}" ]; then
			printf "${MSG[15]}"
			return 0
		fi

		# 3. Rollback required, ask confirmation to the user

		printf "${MSG[9]}" "${INSTALL_DIR}"
		read input

		if [ "${input}" = "y" ]; then
			if [ -d "${INSTALL_DIR}" -a -f "${BACKUP_FILE}" ]; then

				# 1. Delete old content
				printf "${MSG[10]}" "${INSTALL_DIR}"
				command \rm -rf "${INSTALL_DIR}"

				# 2. Extract backup
				printf "${MSG[11]}" "${BACKUP_FILE}"
				command \unzip "${BACKUP_FILE}" -d "${INSTALL_DIR}"

				# 3. Print a nice message and return 0
				printf "${MSG[14]}"
				return 0

			else
				# Something is missing, ask the user to check
				printf "${MSG[12]}" "${INSTALL_DIR}" "${BACKUP_FILE}"
				exit 1
			fi
		else
			# User did not accept conditions, exit
			printf "${MSG[13]}"
			exit 1
		fi
	fi

	return 0
}

function run_program () {
	declare JAR

	JAR="${0%\/*}/${JAR_NAME}"
	command ${JAVA_PATH} ${JAVA_OPTS} -jar ${JAR} ${@}

	return 0
}

function main () {

	# Do some checks
	run_validations

	# Parse arguments to get MULE_HOMEs
	parse_arguments "${@}"

	# If a MULE_HOME is found, check Agent in there
	setup_mule_agent

	# Run the JAR
	run_program "${@}"
}

main "${@}" && exit 0 || exit 1
