#!/bin/bash

if [ ! -z "$SHELL_DEBUG" ]; then
  set -x
fi

#---------------------------------------------------------------------------------------------------
function realpath {
  echo "$(cd "$(dirname "$1")"; pwd)"/"$(basename "$1")";
}

function setRHELLikeOs() {
  local isRedHatLikeOS="false"
  if [[ -f "/etc/os-release" && "$(cat /etc/os-release)" =~ rhel ]]; then
    isRedHatLikeOS="true"
  fi
  export IS_RHEL_OS="${isRedHatLikeOS}"
}

#---------------------------------------------------------------------------------------------------
# Starts an enterprise search process with a given name by running a given command via Rails runner
function run_enterprise_search {
  # Find jruby jar to be used to start the application
  JRUBY_JAR=$(find "$ENT_SEARCH_WAR_ROOT/lib" -type f -name 'jruby*complete*.jar')
  JRUBY_STDLIB=$(find "$ENT_SEARCH_WAR_ROOT/lib" -type f -name 'jruby*stdlib*.jar')

  # Prepare the environment for rubygems and bundler to use vendored gems
  export GEM_PATH="$ENT_SEARCH_WAR_ROOT/gems"
  export GEM_HOME="$ENT_SEARCH_WAR_ROOT/gems"
  export BUNDLE_GEMFILE="$ENT_SEARCH_WAR_ROOT/Gemfile"
  export BUNDLE_FROZEN=1

  # Use jemalloc as malloc implementation if available
  setRHELLikeOs
  if [[ "${IS_RHEL_OS:-}" != "true" ]]; then
    JEMALLOC_LOCATION=`whereis libjemalloc.so.2 | cut -d " " -f 2`
    if [[ -z "${JEMALLOC_LOCATION}" ]]; then
      echo "libjemalloc2 is recommended as memory allocation library. Consider installing libjemalloc2 for running Enterprise Search"
    else
      export LD_PRELOAD=$JEMALLOC_LOCATION
    fi
  fi

  # This should match the config.bundle_without value in config/warble.rb
  export BUNDLE_WITHOUT='crawler:development:crawler_development:test:crawler_test:cypress_test:assets:togo_not_bundled'

  # Start the main jruby process
  exec "$_JAVA" -cp "$JRUBY_STDLIB:$JRUBY_JAR" "${ENT_SEARCH_JAVA_OPTS[@]}" \
          org.jruby.Main -r rubygems -x"$ENT_SEARCH_WAR_ROOT" -S bin/enterprise-search-internal $@
}

#---------------------------------------------------------------------------------------------------
# Sets up the set of java options for running an Enterprise Search application server
function setup_app_server_java_opts {
  # Configure Java GC logging and log rotation if needed
  if [[ "${JAVA_GC_LOGGING:-}" == "true" ]]; then
    export JAVA_GC_LOG_DIR=${JAVA_GC_LOG_DIR:-"${log_directory:-log}"} # Where to put the files
    export JAVA_GC_LOG_KEEP_FILES=${JAVA_GC_LOG_KEEP_FILES:-10}        # How many files to keep
    export JAVA_GC_LOG_MAX_FILE_SIZE=${JAVA_GC_LOG_MAX_FILE_SIZE:-10m} # How big GC logs could get before log rotation

    # Make sure the GC logs directory exists
    mkdir -p "$JAVA_GC_LOG_DIR"

    # Configure GC logging (Java 9+ uses a different set of options)
    if [ "$MAJOR_JAVA_VERSION" == "8" ]; then
      ENT_SEARCH_JAVA_OPTS+=(
        # GC log tuning
        '-XX:+PrintGCDetails'
        '-XX:+PrintGCDateStamps'
        '-XX:+PrintTenuringDistribution'
        '-XX:+PrintGCApplicationStoppedTime'

        # Log rotation settings
        '-XX:+UseGCLogFileRotation'
        "-XX:NumberOfGCLogFiles=${JAVA_GC_LOG_KEEP_FILES:-10}"
        "-XX:GCLogFileSize=${JAVA_GC_LOG_MAX_FILE_SIZE}"

        # The file to use
        "-Xloggc:${JAVA_GC_LOG_DIR}/gc.log"
      )
    else
      ENT_SEARCH_JAVA_OPTS+=(
        "-Xlog:gc*,gc+age=trace,safepoint:file=${JAVA_GC_LOG_DIR}/gc.log:utctime,pid,tags:filecount=${JAVA_GC_LOG_KEEP_FILES:-10},filesize=${JAVA_GC_LOG_MAX_FILE_SIZE}"
      )
    fi
  fi

  # Add java options used by the application server only (gc logging, potentially different heap size, etc)
  ENT_SEARCH_JAVA_OPTS+=( $APP_SERVER_JAVA_OPTS )
}

#---------------------------------------------------------------------------------------------------
set -eu

unset BUNDLE_APP_CONFIG
unset BUNDLE_BIN_PATH
unset BUNDLE_GEMFILE
unset BUNDLE_PATH
unset BUNDLER_VERSION
unset GEM_HOME
unset GEM_PATH
unset RUBYLIB
unset RUBYOPT

BIN_DIR=$(dirname "$0")
BIN_DIR=$(realpath "$BIN_DIR")
APP_ROOT="$(cd "$BIN_DIR/.."; pwd)"
export APP_ROOT

CONFIG_DIR="$APP_ROOT/config"
LIB_DIR="$APP_ROOT/lib"

# Always run in production environment
export RAILS_ENV=production

# Exploded war directory containing all of our code
export ENT_SEARCH_WAR_ROOT="$APP_ROOT/lib/war"

#---------------------------------------------------------------------------------------------------
# Detect the platform
PLATFORM=$(uname -s | awk '{print tolower($0)}')
ARCH=$(uname -m)
if [ "$ARCH" == "aarch64" ]; then
  ARCH="arm64"
fi
PLATFORM_FULL="$PLATFORM-$ARCH"

# Make sure the platform is supported
if [ "$PLATFORM_FULL" != "linux-x86_64" ] && [ "$PLATFORM_FULL" != "darwin-x86_64" ] && [ "$PLATFORM_FULL" != "darwin-arm64" ] && [ "$PLATFORM_FULL" != "linux-arm64" ]; then
  echo
  echo "Elastic Enterprise Search currently only supports macOS and Linux operating systems on 64-bit platforms."
  echo
  exit 1
fi

# Vendored beats platform
BEATS_PLATFORM="$PLATFORM_FULL"
if [ "$PLATFORM" == "darwin" ] && [ "$ARCH" == "arm64" ]; then
  BEATS_PLATFORM="darwin-x86_64"
fi

# Filebeat component locations
export FILEBEAT_BIN="$BIN_DIR/vendor/filebeat/filebeat-$BEATS_PLATFORM"
export FILEBEAT_DIR="$APP_ROOT/filebeat"

# Metricbeat component locations
export METRICBEAT_BIN="$BIN_DIR/vendor/metricbeat/metricbeat-$BEATS_PLATFORM"
export METRICBEAT_DIR="$APP_ROOT/metricbeat"

#---------------------------------------------------------------------------------------------------
# shellcheck source=../lib/require_java_version.sh
source "$LIB_DIR/require_java_version.sh"

# Set the default locale
export LANG="${LANG:-en_US.UTF-8}"

# Load common environment settings
# shellcheck source=../config/env.sh
source "$CONFIG_DIR/env.sh"

# The default set of options we're going to use with java
ENT_SEARCH_JAVA_OPTS=(
  '-Dsun.jnu.encoding=UTF-8'          # Enable support for Unicode characters in file names and URLs
  '-Dfile.encoding=UTF-8'             # Enable support for Unicode content in file and IO streams
  '-Djruby.cli.warning.level=NIL'     # Disable jruby cli warnings
  '-Djava.awt.headless=true'          # Disable the java dock icon on MacOS
  '-Djruby.regexp.interruptible=true' # Make it possible to use timeout regexp matching
  '-server'                           # Enable long-term optimizations for the JVM
)

# Add the options used for both app-server and scripts
ENT_SEARCH_JAVA_OPTS+=( $JAVA_OPTS )

#---------------------------------------------------------------------------------------------------
# Configure temp directory for the product
if [[ "${ENTERPRISE_SEARCH_SYSTEM_TMP_DIR:-}" != "true" ]] && mkdir -p "$APP_ROOT/tmp" &> /dev/null; then
  # NOTE: if you change this path, change the corresponding references in the Dockerfile
  export TMPDIR=$APP_ROOT/tmp
  ENT_SEARCH_JAVA_OPTS+=( "-Djava.io.tmpdir=$TMPDIR" )
fi

#---------------------------------------------------------------------------------------------------
# Prepare config file
#---------------------------------------------------------------------------------------------------
if [[ -z "${ENT_SEARCH_CONFIG_PATH:-}" ]]; then
  export ENT_SEARCH_CONFIG_PATH="$CONFIG_DIR/enterprise-search.yml"
fi

if [[ "$ENT_SEARCH_CONFIG_PATH" != /* ]]; then
  export ENT_SEARCH_CONFIG_PATH="$APP_ROOT/$ENT_SEARCH_CONFIG_PATH"
fi

if [[ ! -a "$ENT_SEARCH_CONFIG_PATH" ]]; then
  echo "Cannot read ENT_SEARCH_CONFIG_PATH file because it does not exist, it's currently $ENT_SEARCH_CONFIG_PATH"
  echo
  exit 1
fi

if [[ ! -r "$ENT_SEARCH_CONFIG_PATH" ]]; then
  echo "Cannot read ENT_SEARCH_CONFIG_PATH file, it's currently $ENT_SEARCH_CONFIG_PATH"
  echo
  exit 1
fi

#---------------------------------------------------------------------------------------------------
# Detect if we are starting an app-server or a CLI command and enable GC logging for app-server only
if [[ "${1:-all}" == "all" ]]; then
  setup_app_server_java_opts
fi

echo "Enterprise Search is starting..."

#---------------------------------------------------------------------------------------------------
# if stdout logging is disabled (typical when running via systemd), indicate where logs can be found
if [[ "${ENT_SEARCH_QUIET_STDOUT:-}" == "true" ]]; then
  echo "Logs can be found in the location configured via the 'log_directory' setting (typically /var/log/enterprise-search)"
fi

run_enterprise_search $@
