#!/bin/sh

set -e

#
# DEFAULT VARIABLE GENERATORS
#

jvm_args() {
	MEMORY="${MEMORY:-1G}"
	printf -- "-Xms$MEMORY -Xmx$MEMORY "
	printf -- "-XX:+UseG1GC -XX:+ParallelRefProcEnabled -XX:MaxGCPauseMillis=200 "
	printf -- "-XX:+UnlockExperimentalVMOptions -XX:+DisableExplicitGC -XX:+AlwaysPreTouch "
	printf -- "-XX:G1NewSizePercent=30 -XX:G1MaxNewSizePercent=40 -XX:G1HeapRegionSize=8M "
	printf -- "-XX:G1ReservePercent=20 -XX:G1HeapWastePercent=5 -XX:G1MixedGCCountTarget=4 "
	printf -- "-XX:InitiatingHeapOccupancyPercent=15 -XX:G1MixedGCLiveThresholdPercent=90 "
	printf -- "-XX:G1RSetUpdatingPauseTimePercent=5 -XX:SurvivorRatio=32 -XX:+PerfDisableSharedMem "
	printf -- "-XX:MaxTenuringThreshold=1 "
}

#
# ENV VARS
#

SERVER_DIR="$(realpath ${SERVER_DIR:-./server})"
JVMARGS=${JVMARGS:-$(jvm_args)}

#
# PREDEFINE VARS
#

MCLAUNCHER_INFO=""
MCLAUNCHER_BINARY=""
MCLAUNCHER_QUIET=1

#
# HELPERS
#

error() {
	printf '\x1b[31m[ERROR]\t\x1b[0m%s\n' "$*" > /dev/stderr
	exit 1;
}

log() {
	if [ "$MCLAUNCHER_QUIET" -eq 0 ]; then
		printf '\x1b[0m[LOG]\t%s\n' "$*" > /dev/stderr
	fi
}

step() {
	if [ "$MCLAUNCHER_QUIET" -eq 0 ]; then
		printf '\x1b[36m[STEP]\t\x1b[0m%s\n' "$*" > /dev/stderr
	fi
}

get_key() {
	echo "$MCLAUNCHER_INFO" | grep "$1=" | awk -F '=' '{ print $2 }'
}

#
# INFO STEP
# gets the up to date information from mcjar
#

info_step() {
	step "info"

	# getting latest info from mcjar
	MCLAUNCHER_INFO="$(mcjar -a)"

	[ "$MCLAUNCHER_QUIET" -eq 1 ] || echo "$MCLAUNCHER_INFO";
}

#
# BINARY STEP
# attempts to find the current binary installed on the system
#

binary_step_forge() {
	jar_name="$(get_key "JAR_NAME")"
	jar_prefix="${jar_name%-installer.jar}"
	suffixs="$(echo ".jar;-shim.jar;-universal.jar" | tr ";" "\n")"

	IFS=$'\n'
	for suffix in $suffixs; do
		if [ -f "$SERVER_DIR/$jar_prefix$suffix" ]; then
			MCLAUNCHER_BINARY="$jar_prefix$suffix"
			return;
		fi
	done
}

binary_step_default() {
	jar_name="$(get_key "JAR_NAME")"
	if [ -f "$SERVER_DIR/$jar_name" ]; then
		MCLAUNCHER_BINARY="$jar_name"
	fi
}

binary_step() {
	step "binary"

	MCLAUNCHER_BINARY=""
	type="$(get_key "MC_TYPE")"
	case "$type" in
		"forge")
			binary_step_forge
			;;
		*)
			binary_step_default
			;;
	esac

	if [ "$MCLAUNCHER_BINARY" != "" ]; then
		log "found binary '$MCLAUNCHER_BINARY'"
	else
		log "could not locate binary... will download"
	fi
}

#
# DOWNLOAD STEP
# download the binary if it needs to needs updated
#

download_step() {
	step "download"

	if [ "$MCLAUNCHER_BINARY" != "" ]; then
		log "jar is up to date... skipping"
		return;
	fi

	# clean up old files
	rm -f "$SERVER_DIR"/*.jar
	rm -f "$SERVER_DIR"/*.jar.log
	rm -f "$SERVER_DIR"/*.bat
	rm -f "$SERVER_DIR/run.sh"

	# update the jar
	log "jar is out of date... updating"
	jar_url="$(get_key "JAR_URL")"
	jar_name="$(get_key "JAR_NAME")"
	log "downloading '$jar_url'"
	wget -q "$jar_url" -O "$SERVER_DIR/$jar_name"
	MCLAUNCHER_BINARY="$jar_name"
}

#
# INSTALL STEP
# some mc types need an extra install step to setup the server files before running
#

install_step_forge() {
	log "installing forge server"
	jar_name="$(get_key "JAR_NAME")"
	java -jar "$SERVER_DIR/$jar_name" --installServer

	binary_step_forge
	if [ "$MCLAUNCHER_BINARY" = "" ]; then
		error "could not locate forge binary"
	fi
}

install_step() {
	step "install"

	type="$(get_key "MC_TYPE")"
	case "$type" in
		"forge")
			install_step_forge
			;;
		*)
			log "install step not needed for '$type'"
			;;
	esac
}

#
# EXECUTE STEP
# run the thing!!!!!!
#

execute_step_default() {
	jar_name="$(get_key "JAR_NAME")"
	exec java $JVMARGS -jar "$SERVER_DIR/$jar_name" nogui
}

execute_step_forge() {
	if [ -f "$SERVER_DIR/run.sh" ]; then
		echo "$JVMARGS" > "$SERVER_DIR/user_jvm_args.txt"
		chmod +x "$SERVER_DIR/run.sh"
		exec "$SERVER_DIR/run.sh" nogui
	else
		exec java $JVMARGS -jar "$SERVER_DIR/$MCLAUNCHER_BINARY" nogui
	fi
}

execute_step() {
	step "execute"

	echo "eula=true" > "$SERVER_DIR/eula.txt"

	type="$(get_key "MC_TYPE")"
	case "$type" in
		"forge")
			execute_step_forge
			;;
		*)
			execute_step_default
			;;
	esac
}

chk_command() {
	if ! command -v "$1" > /dev/null; then
		>&2 echo "error: command '$1' could not be found"
		exit 1
	fi
}

help() {
	printf "usage: mclauncher [options]\n\n"
	printf "options:\n"
	printf "\t-h\tshow this message\n"
	printf "\t-l\tshow logging (verbose)\n\n"
	printf "environment:\n"
	printf "\tsee 'mcjar -h' for environment\n"
}

chk_command mcjar
chk_command java
chk_command awk
chk_command getopts

while getopts "hl" arg 2>/dev/null; do
	case "$arg" in
		h)
			help
			exit 0
			;;
		l)
			MCLAUNCHER_QUIET=0
			;;
		?)
			error "unknown option"
			;;
	esac;
done;

mkdir -p "$SERVER_DIR"
cd "$SERVER_DIR"

info_step
binary_step
download_step
install_step
execute_step