#!/bin/bash

: "${DEBUG_EXEC:=false}"
: "${SETUP_ONLY:=false}"
: "${CUSTOM_JAR_EXEC:=}"
: "${SERVER_RUNNER:=mc-server-runner}"
: "${PRE_START_SCRIPT:=}"

# shellcheck source=start-utils
. "$(dirname "$0")/start-utils"
isDebugging && set -x

function runPreStartScript() {
  if [[ ! $PRE_START_SCRIPT ]]; then
    return
  fi
  if [[ ! -x $PRE_START_SCRIPT ]]; then
    logError "PRE_START_SCRIPT $PRE_START_SCRIPT is not an executable file"
    exit 1
  fi
  log "Running pre-start script $PRE_START_SCRIPT..."
  if ! "$PRE_START_SCRIPT"; then
    logError "Pre-start script $PRE_START_SCRIPT failed, so the server will not be started"
    exit 1
  fi
}

baseDataDir=/data
tmpServerIconPath=/tmp/icon.img
serverIconPath=${baseDataDir}/server-icon.png
mcHealthEnvPath=${baseDataDir}/.mc-health.env
bootstrapPath=${baseDataDir}/bootstrap.txt

if [ -n "$ICON" ]; then
    if [ ! -e server-icon.png ] || isTrue "${OVERRIDE_ICON}"; then
      log "Using server icon from $ICON..."
      if isURL "$ICON"; then
        # Not sure what it is yet...call it "img"
        if ! get -o "$tmpServerIconPath" "$ICON"; then
          logError "Failed to download icon from $ICON"
          exit 1
        fi
        ICON="$tmpServerIconPath"
        iconSrc="url"
      elif [ -f "$ICON" ]; then
        iconSrc="file"
      else
        logError "$ICON does not appear to be a URL or existing file"
        exit 1
      fi
      read -r -a specs < <(identify "$ICON" | awk 'NR == 1 { print $2, $3 }')
      if [ "${specs[0]} ${specs[1]}" = "PNG 64x64" ]; then
        if [ $iconSrc = url ]; then
          mv -f "$tmpServerIconPath" "$serverIconPath"
        else
          cp -f "$ICON" "$serverIconPath"
        fi
      elif [ "${specs[0]}" = GIF ]; then
        log "Converting GIF image to 64x64 PNG..."
        convert "$ICON"[0] -resize 64x64! "$serverIconPath"
      else
        log "Converting image to 64x64 PNG..."
        convert "$ICON" -resize 64x64! "$serverIconPath"
      fi
    fi
fi

SERVER_DIR="$baseDataDir"
if [[ ${FTB_DIR:-} ]]; then
  SERVER_DIR="$FTB_DIR"
fi

function addAgents() {
  local agents=$1 outDir=$2 glob=$3 option=$4

  mkdir -p "$outDir"
  if ! mc-image-helper mcopy \
    --glob="$glob" \
    --scope=var-list \
    --to="$outDir" \
    "$agents"; then
    logError "Failed to get agents from $agents"
    exit 1
  fi

  # The manifest lists the files that the list resolved to, also in subdirectories, as for destination<source entries
  local manifest="$outDir/.var-list-manifest.json"
  if [ -f "$manifest" ]; then
    while read -r agent; do
      JVM_OPTS="${JVM_OPTS} ${option}:${outDir}/${agent}"
    done < <(jq -r '.files[]' "$manifest" | sort)
  fi
}

if isFamily NATIVE; then
  : # Native server, so no JVM to load agents into
else
  if [[ -v JVM_AGENTS ]]; then
    addAgents "$JVM_AGENTS" /data/agents/jvm '*.so' -agentpath
  fi
  if [[ -v JAVA_AGENTS ]]; then
    addAgents "$JAVA_AGENTS" /data/agents/java '*.jar' -javaagent
  fi
fi

# shellcheck source=start-finalExec-log4j
. "$(dirname "$0")/start-finalExec-log4j"

# Optional disable console
if ! isFamily NATIVE && versionLessThan 1.14 && [[ ${CONSOLE,,} = false ]]; then
  EXTRA_ARGS+=" --noconsole"
fi

# Optional disable GUI for headless servers
if ! isFamily NATIVE && [[ ${GUI,,} = false ]]; then
  EXTRA_ARGS+=" nogui"
fi

expandedDOpts=
if [ -n "$JVM_DD_OPTS" ]; then
      for dopt in $JVM_DD_OPTS
      do
          expandedDOpts="${expandedDOpts} -D${dopt/:/=}"
      done
fi

if isTrue "${ENABLE_JMX}"; then
  : "${JMX_PORT:=7091}"
  JVM_OPTS="${JVM_OPTS}
  -Dcom.sun.management.jmxremote.local.only=false
  -Dcom.sun.management.jmxremote.port=${JMX_PORT}
  -Dcom.sun.management.jmxremote.rmi.port=${JMX_PORT}
  -Dcom.sun.management.jmxremote.authenticate=false
  -Dcom.sun.management.jmxremote.ssl=false
  -Dcom.sun.management.jmxremote.host=${JMX_BINDING:-0.0.0.0}
  -Djava.rmi.server.hostname=${JMX_HOST:-localhost}"

  log "JMX is enabled. Make sure you have port forwarding for ${JMX_PORT}"
fi

# shellcheck source=start-finalExec-jvmFlags
. "$(dirname "$0")/start-finalExec-jvmFlags"

# Handle GTNH args
if isType "GTNH"; then
  expandedDOpts="${expandedDOpts} -Dfml.readTimeout=180"
  java_major_version=$(mc-image-helper java-release)
  if (( java_major_version == 8 )); then
    debug "Setting GTNH java8 args."
    JVM_XX_OPTS="${JVM_XX_OPTS}
    -XX:+UseStringDeduplication
    -XX:+UseCompressedOops
    -XX:+UseCodeCacheFlushing
    "
  elif (( java_major_version >= 17 )); then
    debug "Setting GTNH java17+ args."
    expandedDOpts="${expandedDOpts} @java9args.txt"
  fi
fi

if [[ ${INIT_MEMORY} || ${MAX_MEMORY} ]]; then
  log "Setting initial memory to ${INIT_MEMORY:=${MEMORY}} and max to ${MAX_MEMORY:=${MEMORY}}"
  if isPercentage "$INIT_MEMORY"; then
    JVM_OPTS="-XX:InitialRAMPercentage=$(getPercentageValue "${INIT_MEMORY}") ${JVM_OPTS}"
  elif [[ ${INIT_MEMORY} ]]; then
    JVM_OPTS="-Xms${INIT_MEMORY} ${JVM_OPTS}"
  fi

  if isPercentage "$MAX_MEMORY"; then
    JVM_OPTS="-XX:MaxRAMPercentage=$(getPercentageValue "${MAX_MEMORY}") ${JVM_OPTS}"
  elif [[ ${MAX_MEMORY} ]]; then
    JVM_OPTS="-Xmx${MAX_MEMORY} ${JVM_OPTS}"
  fi
fi

function copyFilesForCurseForge() {
  if [ ! -e "${FTB_DIR}/server-icon.png" ] && [ -e "$serverIconPath" ]; then
    cp -f "$serverIconPath" "${FTB_DIR}/"
  fi

  cp -f ${baseDataDir}/eula.txt "${FTB_DIR}/"
}

if isFamily NATIVE; then
  # Native server, always probed with the modern server list ping
  rm -f "$mcHealthEnvPath"
elif versionLessThan 'b1.8'; then
  echo "
DISABLE_HEALTHCHECK=true
  " > "$mcHealthEnvPath"
elif versionLessThan 1.3; then
  echo "
MC_HEALTH_EXTRA_ARGS=(
  --use-old-server-list-ping
)
  " > "$mcHealthEnvPath"
elif versionLessThan 1.7; then
  echo "
MC_HEALTH_EXTRA_ARGS=(
  --use-server-list-ping
)
  " > "$mcHealthEnvPath"
elif isTrue "$USES_PROXY_PROTOCOL"; then
  echo "
MC_HEALTH_EXTRA_ARGS=(
  --use-proxy
)
  " > "$mcHealthEnvPath"
else
  rm -f "$mcHealthEnvPath"
fi

mcServerRunnerArgs=(
--stop-duration "${STOP_DURATION:-60}s"
)
if isTrue "${CREATE_CONSOLE_IN_PIPE:-false}"; then
  mcServerRunnerArgs+=(--named-pipe "${CONSOLE_IN_NAMED_PIPE:-/tmp/minecraft-console-in}")
fi
if [[ ${STOP_SERVER_ANNOUNCE_DELAY} ]]; then
  mcServerRunnerArgs+=(--stop-server-announce-delay "${STOP_SERVER_ANNOUNCE_DELAY}s")
fi
if [[ ${STOP_SERVER_DELAY_COMMAND} ]]; then
  mcServerRunnerArgs+=(--stop-server-delay-command "${STOP_SERVER_DELAY_COMMAND}")
fi
if isTrue "${ENABLE_SSH}"; then
  mcServerRunnerArgs+=(--remote-console)
fi

if [[ ${TYPE} == "CURSEFORGE" && "${SERVER}" ]]; then
  copyFilesForCurseForge

  if ! cd "${FTB_DIR}"; then
    logError "Can't go into ${FTB_DIR}"
    exit 1
  fi
  log "Starting CurseForge server in ${FTB_DIR}..."
  runPreStartScript
  if isTrue "${DEBUG_EXEC}"; then
    set -x
  fi
  exec ${SERVER_RUNNER} ${bootstrapArgs} "${mcServerRunnerArgs[@]}" -- java $JVM_XX_OPTS $JVM_OPTS $expandedDOpts -jar "$(basename "${SERVER}")" "$@" $EXTRA_ARGS
elif [[ ${TYPE} == "CURSEFORGE" ]]; then
  mcServerRunnerArgs+=(--shell bash)

  copyFilesForCurseForge

if isPercentage "$INIT_MEMORY" || isPercentage "$MAX_MEMORY"; then
# Convert to bytes
if ! NORM_INIT_MEM=$(normalizeMemSize "$INIT_MEMORY"); then
  exit 1
fi
if ! NORM_MAX_MEM=$(normalizeMemSize "$MAX_MEMORY"); then
  exit 1
fi
# Convert bytes to MB
((NORM_INIT_MEM/=1048576))
((NORM_MAX_MEM/=1048576))

  cat > "${FTB_DIR}/settings-local.sh" <<EOF
export MIN_RAM="${NORM_INIT_MEM}M"
export MAX_RAM="${NORM_MAX_MEM}M"
export JAVA_PARAMETERS="${JVM_XX_OPTS} ${JVM_OPTS} $expandedDOpts"
EOF
else
  cat > "${FTB_DIR}/settings-local.sh" <<EOF
export MIN_RAM="${INIT_MEMORY}"
export MAX_RAM="${MAX_MEMORY}"
export JAVA_PARAMETERS="${JVM_XX_OPTS} ${JVM_OPTS} $expandedDOpts"
EOF
fi

  # patch CurseForge cfg file, if present
  if [ -f "${FTB_DIR}/settings.cfg" ] && [[ ${MAX_MEMORY} ]]; then
    if isPercentage "$MAX_MEMORY"; then
      sed -i "s/MAX_RAM=[^;]*/MAX_RAM=${NORM_MAX_MEM}M/" "${FTB_DIR}/settings.cfg"
    else
      sed -i "s/MAX_RAM=[^;]*/MAX_RAM=${MAX_MEMORY}/" "${FTB_DIR}/settings.cfg"
    fi
  fi

  if ! cd "${FTB_DIR}"; then
    logError "Can't go into ${FTB_DIR}"
    exit 1
  fi
  log "Running FTB ${FTB_SERVER_START} in ${FTB_DIR} ..."

  finalArgs="${FTB_SERVER_START}"

  if isTrue "${SETUP_ONLY}"; then
    echo "SETUP_ONLY: ${finalArgs}"
    exit
  fi

  if isTrue "${DEBUG_EXEC}"; then
    set -x
  fi
  if [ -f "${FTB_DIR}/variables.txt" ]; then
      JVM_ARGS="${JVM_XX_OPTS} ${JVM_OPTS} $expandedDOpts"
      JVM_ARGS=${JVM_ARGS//$'\n'/}
      sed -i "s~JAVA_ARGS=.*~JAVA_ARGS=\"${JVM_ARGS}\"~" "${FTB_DIR}/variables.txt"
  fi
  runPreStartScript
  exec ${SERVER_RUNNER} "${mcServerRunnerArgs[@]}" -- "${finalArgs[@]}"
elif [[ $SERVER =~ run.sh ]]; then
  log "Using Forge supplied run.sh script..."
  echo $JVM_XX_OPTS $JVM_OPTS $expandedDOpts > user_jvm_args.txt
  if isTrue "${SETUP_ONLY}"; then
    echo "SETUP_ONLY: bash ${SERVER}"
    exit
  fi
  runPreStartScript
  if isTrue "${DEBUG_EXEC}"; then
    set -x
  fi
  exec ${SERVER_RUNNER} "${mcServerRunnerArgs[@]}" --shell bash -- "${SERVER}" $EXTRA_ARGS
elif isFamily NATIVE; then
  # Native server, so no JVM arguments
  if [[ ! -x "$SERVER" ]]; then
    log "Making $SERVER executable"
    if ! chmod +x "$SERVER"; then
      logError "Failed to make $SERVER executable"
      exit 1
    fi
  fi

  if isTrue "${SETUP_ONLY}"; then
    echo "SETUP_ONLY: ${SERVER}"
    exit
  fi

  runPreStartScript
  if isTrue "${DEBUG_EXEC}"; then
    set -x
  fi

  log "Starting the Minecraft server..."
  # shellcheck disable=SC2086
  exec ${SERVER_RUNNER} ${bootstrapArgs} "${mcServerRunnerArgs[@]}" -- "${SERVER}" "$@" $EXTRA_ARGS
else
  # If we have a bootstrap.txt file... feed that in to the server stdin
  if [ -f $bootstrapPath ]; then
    bootstrapArgs="--bootstrap $bootstrapPath"
  fi

  log "Starting the Minecraft server..."

  # Specifically want the variables to expand to args, so...
  # shellcheck disable=SC2206
  finalArgs=(
    $JVM_XX_OPTS
    $JVM_OPTS
    $expandedDOpts
  )

  if [[ $CUSTOM_JAR_EXEC ]]; then
    # shellcheck disable=SC2206
    finalArgs+=($CUSTOM_JAR_EXEC)
  else
    finalArgs+=(-jar "$SERVER")
  fi

  # shellcheck disable=SC2206
  finalArgs+=(
    "$@" $EXTRA_ARGS
  )

  if isTrue "${SETUP_ONLY}"; then
    echo "SETUP_ONLY: java ${finalArgs[*]}"
    exit
  fi

  runPreStartScript
  if isTrue "${DEBUG_EXEC}"; then
    set -x
  fi

  exec ${SERVER_RUNNER} ${bootstrapArgs} "${mcServerRunnerArgs[@]}" -- java "${finalArgs[@]}"
fi
