#!/bin/bash

function get_remote_debugging_port() {
    service_type=$1
    case "$service_type" in
        "registry")
            if [[ $REMOTE_DEBUGGING_PORT_REGISTRY =~ ^[0-9]+$ ]]; then
                port=$REMOTE_DEBUGGING_PORT_REGISTRY
            elif [[ $REMOTE_DEBUGGING_PORT =~ ^[0-9]+$ ]]; then
                port=$REMOTE_DEBUGGING_PORT
            fi
            ;;
        "metadata")
            if [[ $REMOTE_DEBUGGING_PORT_METADATA =~ ^[0-9]+$ ]]; then
                port=$REMOTE_DEBUGGING_PORT_METADATA
            elif [[ $REMOTE_DEBUGGING_PORT =~ ^[0-9]+$ ]]; then
                port=$((REMOTE_DEBUGGING_PORT+1))
            fi
            ;;
        "data")
            if [[ $REMOTE_DEBUGGING_PORT_DATA =~ ^[0-9]+$ ]]; then
                port=$REMOTE_DEBUGGING_PORT_DATA
            elif [[ $REMOTE_DEBUGGING_PORT =~ ^[0-9]+$ ]]; then
                port=$((REMOTE_DEBUGGING_PORT+2))
            fi
            ;;
        "api")
            if [[ $REMOTE_DEBUGGING_PORT_API =~ ^[0-9]+$ ]]; then
                port=$REMOTE_DEBUGGING_PORT_API
            elif [[ $REMOTE_DEBUGGING_PORT =~ ^[0-9]+$ ]]; then
                port=$((REMOTE_DEBUGGING_PORT+3))
            fi
            ;;
        "webconsole")
            if [[ $REMOTE_DEBUGGING_PORT_WEBCONSOLE =~ ^[0-9]+$ ]]; then
                port=$REMOTE_DEBUGGING_PORT_WEBCONSOLE
            elif [[ $REMOTE_DEBUGGING_PORT =~ ^[0-9]+$ ]]; then
                port=$((REMOTE_DEBUGGING_PORT+4))
            fi
            ;;
        "s3")
            if [[ $REMOTE_DEBUGGING_PORT_S3 =~ ^[0-9]+$ ]]; then
                port=$REMOTE_DEBUGGING_PORT_S3
            elif [[ $REMOTE_DEBUGGING_PORT =~ ^[0-9]+$ ]]; then
                port=$((REMOTE_DEBUGGING_PORT+5))
            fi
            ;;
    esac
    if [ -z "$port" ]; then echo 0; else echo $port; fi
}

if [ -z $QUOBYTE_BASEDIR ]; then
  BASE_DIR="/"
else
  BASE_DIR=$QUOBYTE_BASEDIR/
fi

if [ -r ${QUOBYTE_BASEDIR}/etc/default/quobyte ]; then
  . ${QUOBYTE_BASEDIR}/etc/default/quobyte
fi

LIB_DIR=opt/quobyte/lib/
GWT_LIB_DIR=${LIB_DIR}gwt/
S3_BROWSER_ASSETS=${LIB_DIR}s3_browser
# Keep java version checks in sync with
# ../packaging/installer/install_quobyte script
MIN_SUPPORTED_JAVA_VERSION=11
MAX_SUPPORTED_JAVA_VERSION=21
PREFERRED_JAVA_VERSION=21

export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8

# Pick a JVM installation, prefer 'alternatives' over Java 11 over Java 1.8
# Can be overriden for example with setting JAVA_HOME in a systemd override:
#    Environment=JAVA_HOME=/usr/lib/jvm/jre-1.8.0
JAVA_BIN="/usr/bin/java"
if [ -n "$JAVA_HOME" ]; then
  JAVA_BIN="${JAVA_HOME}/bin/java"
elif [ -x /etc/alternatives/java ]; then
  JAVA_BIN=/etc/alternatives/java
fi

if [ ! -x ${JAVA_BIN} ]; then
  echo "No JVM installation found. Set alternatives or JAVA_HOME accordingly"
  exit 1
fi

# E.g. 1.8.0_191 or 11.0.1.
JAVA_MAJOR_VERSION=$($JAVA_BIN -version 2>&1 | \
  awk '/version/ { gsub(/"/, "", $3); split($3, a, "."); \
    if (a[1] == 1) { print int(a[2]) } else { print int(a[1]); } }')
JAVA_CP=$(echo ${BASE_DIR}${LIB_DIR}*.jar | tr ' ' ':')
JAVA_GWT_CP=$(echo ${BASE_DIR}${GWT_LIB_DIR}*.jar | tr ' ' ':')

if [ -z "$JAVA_MAJOR_VERSION" ] || \
   [ $JAVA_MAJOR_VERSION -lt $MIN_SUPPORTED_JAVA_VERSION ] || \
   [ $JAVA_MAJOR_VERSION -gt $MAX_SUPPORTED_JAVA_VERSION ]; then
  echo "Java Runtime ($JAVA_BIN) has version $JAVA_MAJOR_VERSION which is not" \
    "supported. Please use version $PREFERRED_JAVA_VERSION."
  exit 1
fi

if [ -z "$JAVA_OPTIONS" ]; then
  # WARNING: These options will be ignored if JAVA_OPTIONS are set in
  # /etc/default/quobyte
  JAVA_OPTIONS="\
 -XX:+RelaxAccessControlCheck\
 -XX:+UseThreadPriorities\
 -XX:+PreserveFramePointer\
 -XX:-OmitStackTraceInFastThrow\
 -Dfile.encoding=UTF-8\
 -Dsun.jnu.encoding=UTF-8"

  if [[ $JAVA_MAJOR_VERSION -ge 11 && "${QUOBYTE_JAVA_GC:-ZGC}" = "ZGC" ]]; then
    # For Java 11 and later, we want to enable ZGC by default.
    if [ $JAVA_MAJOR_VERSION -lt 17 ]; then
      JAVA_OPTIONS="$JAVA_OPTIONS -XX:+UnlockExperimentalVMOptions"
    fi
    JAVA_OPTIONS="$JAVA_OPTIONS -XX:+UseZGC"
  elif [[ "${QUOBYTE_JAVA_GC:-G1GC}" = "G1GC" ]]; then
    # For version pre Java 11, we want to keep using G1C.
    JAVA_OPTIONS="$JAVA_OPTIONS\
   -XX:+UseG1GC\
   -XX:MaxGCPauseMillis=25\
   -XX:+ExplicitGCInvokesConcurrent"
  else
    echo -n "A combination of $($JAVA_BIN -version 2>&1|head -n1) and a garbage collector "
    echo -n "QUOBYTE_JAVA_GC=$QUOBYTE_JAVA_GC is not supported by the Quobyte team. "
    echo "If you insist to use it anyway, please populate the JAVA_OPTIONS variable accordingly."
    exit 1
  fi
fi

if [ $JAVA_MAJOR_VERSION -gt 8 ]; then
  # Java 9 tightened modularization and warns when reflection is used for some
  # symbol which is not exported by the module. Ignore this.
  if [ $JAVA_MAJOR_VERSION -lt 17 ]; then
    JAVA_OPTIONS="$JAVA_OPTIONS\
    -XX:+UnlockExperimentalVMOptions --illegal-access=warn"
  fi
  JAVA_OPTIONS="$JAVA_OPTIONS\
 --add-opens=java.base/java.nio=ALL-UNNAMED\
 --add-opens=java.base/java.lang=ALL-UNNAMED\
 --add-opens=java.management/sun.management=ALL-UNNAMED\
 --add-opens=java.base/sun.nio.ch=ALL-UNNAMED\
 --add-opens=java.base/sun.net.dns=ALL-UNNAMED"
fi


if [ -n "$JAVA_EXTRA_OPTIONS" ]; then
  JAVA_OPTIONS="$JAVA_OPTIONS $JAVA_EXTRA_OPTIONS"
fi

if [ -z "$MAX_MEM_JAVA" ]; then
  MAX_MEM_JAVA="4G"
fi

if [ "$ENABLE_ASSERTIONS" = "true" ]
then
    JAVA_OPTIONS="$JAVA_OPTIONS -ea"
fi

if [ -n "$QUOBYTE_CLIENT_OPTIONS" ]; then
  export QUOBYTE_CLIENT_OPTIONS
fi

PORT=$(get_remote_debugging_port "$1")
if [[ "$PORT" -ne 0 ]]; then
  if [ $JAVA_MAJOR_VERSION -ge 9 ]; then
    JAVA_OPTIONS="$JAVA_OPTIONS -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:$PORT"
  else
    JAVA_OPTIONS="$JAVA_OPTIONS -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=$PORT"
  fi
fi

WAR_PARAM=""
case "$1" in
    "registry")
        MAIN_CLASS="com.quobyte.registry.RegistryService"
        JAVA_MEM_OPTIONS="-Xmx${MAX_MEM_REGISTRY:-${MAX_MEM_JAVA}}"
        if [ -n "${MIN_MEM_REGISTRY}" ]; then JAVA_MEM_OPTIONS="${JAVA_MEM_OPTIONS} -Xms${MIN_MEM_REGISTRY}"; fi
        if [ -n "${MAX_BUFFER_OTHER}" ]; then JAVA_MEM_OPTIONS="${JAVA_MEM_OPTIONS} -XX:MaxDirectMemorySize=${MAX_BUFFER_OTHER} -Dquobyte.maxDirectSize=${MAX_BUFFER_OTHER}"; fi
        JAVA_OPTIONS="${JAVA_OPTIONS} ${JAVA_MEM_OPTIONS} -Djava.library.path=\"${BASE_DIR}${LIB_DIR}\""
        ;;
    "metadata")
        MAIN_CLASS="com.quobyte.metadata.MetadataService"
        JAVA_MEM_OPTIONS="-Xmx${MAX_MEM_METADATA:-${MAX_MEM_JAVA}}"
        if [ -n "${MIN_MEM_METADATA}" ]; then JAVA_MEM_OPTIONS="${JAVA_MEM_OPTIONS} -Xms${MIN_MEM_METADATA}"; fi
        if [ -n "${MAX_BUFFER_METADATA}" ]; then JAVA_MEM_OPTIONS="${JAVA_MEM_OPTIONS} -XX:MaxDirectMemorySize=${MAX_BUFFER_METADATA} -Dquobyte.maxDirectSize=${MAX_BUFFER_METADATA}"; fi
        JAVA_OPTIONS="${JAVA_OPTIONS} ${JAVA_MEM_OPTIONS} -Djava.library.path=\"${BASE_DIR}${LIB_DIR}\""
        ;;
    "data")
        MAIN_CLASS="com.quobyte.data.DataService"
        JAVA_MEM_OPTIONS="-Xmx${MAX_MEM_DATA:-${MAX_MEM_JAVA}}"
        if [ -n "${MIN_MEM_DATA}" ]; then JAVA_MEM_OPTIONS="${JAVA_MEM_OPTIONS} -Xms${MIN_MEM_DATA}"; fi
        if [ -n "${MAX_BUFFER_DATA}" ]; then JAVA_MEM_OPTIONS="${JAVA_MEM_OPTIONS} -XX:MaxDirectMemorySize=${MAX_BUFFER_DATA} -Dquobyte.maxDirectSize=${MAX_BUFFER_DATA}"; fi
        JAVA_OPTIONS="${JAVA_OPTIONS} ${JAVA_MEM_OPTIONS} -Djava.library.path=\"${BASE_DIR}${LIB_DIR}\""
        ;;
    "api")
        MAIN_CLASS="com.quobyte.api.ApiService"
        JAVA_MEM_OPTIONS="-Xmx${MAX_MEM_API:-${MAX_MEM_JAVA}}"
        if [ -n "${MIN_MEM_API}" ]; then JAVA_MEM_OPTIONS="${JAVA_MEM_OPTIONS} -Xms${MIN_MEM_API}"; fi
        if [ -n "${MAX_BUFFER_OTHER}" ]; then JAVA_MEM_OPTIONS="${JAVA_MEM_OPTIONS} -XX:MaxDirectMemorySize=${MAX_BUFFER_OTHER} -Dquobyte.maxDirectSize=${MAX_BUFFER_OTHER}"; fi
        JAVA_OPTIONS="${JAVA_OPTIONS} ${JAVA_MEM_OPTIONS} -Djava.library.path=\"${BASE_DIR}${LIB_DIR}\""
        ;;
    "webconsole")
        MAIN_CLASS="com.quobyte.webconsole.WebconsoleService"
        JAVA_MEM_OPTIONS="-Xmx${MAX_MEM_WEBCONSOLE:-${MAX_MEM_JAVA}}"
        if [ -n "${MIN_MEM_WEBCONSOLE}" ]; then JAVA_MEM_OPTIONS="${JAVA_MEM_OPTIONS} -Xms${MIN_MEM_WEBCONSOLE}"; fi
        if [ -n "${MAX_BUFFER_OTHER}" ]; then JAVA_MEM_OPTIONS="${JAVA_MEM_OPTIONS} -XX:MaxDirectMemorySize=${MAX_BUFFER_OTHER} -Dquobyte.maxDirectSize=${MAX_BUFFER_OTHER}"; fi
        JAVA_OPTIONS="${JAVA_OPTIONS} ${JAVA_MEM_OPTIONS} -Djava.library.path=\"${BASE_DIR}${LIB_DIR}\""
        WAR_PARAM="--war ${BASE_DIR}${LIB_DIR}webconsole.war"
        JAVA_CP=${JAVA_CP}:${JAVA_GWT_CP}
        ;;
    "s3")
        MAIN_CLASS="com.quobyte.s3.S3ProxyService"
        JAVA_MEM_OPTIONS="-Xmx${MAX_MEM_S3:-${MAX_MEM_JAVA}}"
        if [ -n "${MIN_MEM_S3}" ]; then JAVA_MEM_OPTIONS="${JAVA_MEM_OPTIONS} -Xms${MIN_MEM_S3}"; fi
        if [ -n "${MAX_BUFFER_S3}" ]; then JAVA_MEM_OPTIONS="${JAVA_MEM_OPTIONS} -XX:MaxDirectMemorySize=${MAX_BUFFER_S3} -Dquobyte.maxDirectSize=${MAX_BUFFER_S3}"; fi
        JAVA_OPTIONS="${JAVA_OPTIONS} ${JAVA_MEM_OPTIONS} -Djava.library.path=\"${BASE_DIR}${LIB_DIR}\""
        JAVA_CP=${JAVA_CP}:${S3_BROWSER_ASSETS}
        ;;
    *)
        echo "ERROR: '$1' is no valid Quobyte service name."
        exit 1
        ;;
esac

if [[ -n "$ENABLE_ASAN" ]]
then
	#export ASAN_OPTIONS=halt_on_error=false
	if [[ -e "$ENABLE_ASAN" ]]
	then
		libasan="$ENABLE_ASAN"
	else
		# This requires clang to be installed
		libasan="$(clang -print-file-name=libclang_rt.asan.so)"
		export ASAN_SYMBOLIZER_PATH=`which llvm-symbolizer`
	fi
	if [[ ! -e "$libasan" ]]
	then
		echo "ENABLE_ASAN is selected but couldn't find libasan, exiting"
		exit 1
	fi
	export LD_PRELOAD="$LD_PRELOAD $libasan"
fi

shift
_JAVA_OPTIONS=$JAVA_OPTIONS CLASSPATH=$JAVA_CP exec $JAVA_BIN -server $MAIN_CLASS $WAR_PARAM $@
