#!/bin/sh
# Convenience wrapper for easily viewing/setting options that
# the project's CMake scripts will recognize

set -e

type cmake > /dev/null 2>&1 || {
  echo "\
This package requires CMake, please install it first, then you may
use this configure script to access CMake equivalent functionality.\
" >&2;
  exit 1;
}

# Save some values for later before parsing the command line.
if [ -n "$*" ]; then
  args=$(printf " \"%s\"" $*)
fi
command="$0$args"
sourcedir="$(cd "$(dirname "$0")" && pwd)"

usage="\
Usage: $0 [OPTION]... [VAR=VALUE]...

  Installation options:
    --prefix=PREFIX       installation directory [/usr/local]
    --without-relocatable disable relocatable installations
    --package-name        sets the name of the produced package

  Convenience options:
    --debug    sets --build-type=Debug, --log-level=trace, and --with-asan
    --release  sets --build-type=Release
    --ci-build sets --build-type=CI, --log-level=trace, and --with-asan

  Build options:
    --generator=GENERATOR     CMake generator to use (see cmake --help)
    --build-dir=DIR           directory where to perform build [build]
    --build-type=DIR          CMake build type [RelWithDebInfo]
    --extra-flags=STRING      additional compiler flags
    --show-time-report        print information where time was spent during
                              compilation
    --show-time-trace         generate tracing JSON for compilation time
                              profiling
    --more-warnings           enables most warnings on GCC and Clang
    --without-tests           build without unit tests
    --with-zeek-to-vast       build with zeek-to-vast
    --with-lsvast             build with lsvast
    --with-dscat              build with dscat
    --with-example-plugin     build with example plugin
    --with-plugin=DIR         build with plugin in given directory
    --with-plugin-autoloading always enable all bundled plugins

  Debugging:
    --log-level=LEVEL     maximum compile-time log level
                          (quiet,error,warning,info,verbose,debug,trace)
    --caf-log-level=LEVEL maximum compile-time log level for CAF
                          (quiet,error,warning,info,debug,trace)
    --without-assertions  disable assertions
    --without-exceptions  disable C++ exceptions
    --without-dtrace      disable USDT tracepoints
    --with-asan           enable AddressSanitizer
    --with-ubsan          enable Undefined Behavior Sanitizer

  Required packages:
    --with-arrow=PATH       path to Apache Arrow install root
    --without-arrow         explicitly disable Apache Arrow integration
    --with-caf=PATH         path to CAF install root or build directory
    --with-bundled-caf      build CAF from the submodule
    --with-flatbuffers=PATH path to FlatBuffers install root
    --with-yaml-cpp=PATH    path to yaml-cpp install root
    --with-simdjson=PATH    path to simdjson install root
    --with-fmt=PATH         path to {fmt} install root
    --with-spdlog=PATH      path to spdlog install root

  Optional packages:
    --with-broker=PATH    path to Broker install root (required for
                          zeek-to-vast)
    --with-bundled-broker build Broker from the submodule
    --with-doxygen=PATH   path to Doxygen install root
    --with-jemalloc=PATH  link against jemalloc
    --with-openssl=PATH   path to OpenSSL install root
    --with-pcap=PATH      path to libpcap install root

  Influential Environment Variables (only on first invocation):
    CXX             C++ compiler command
    CXXFLAGS        C++ compiler flags (overrides defaults)
    LDFLAGS         Additional linker flags
    CMAKE_GENERATOR Selects a custom generator
"

# Function to append a CMake cache entry definition to the
# CMakeCacheEntries variable
#   $1 is the cache entry variable name
#   $2 is the cache entry variable type
#   $3 is the cache entry variable value
append_cache_entry() {
  CMakeCacheEntries="$CMakeCacheEntries -D \"$1:$2=$3\""
}

# Set defaults
builddir=build
CMakeCacheEntries=""
append_cache_entry CMAKE_BUILD_TYPE STRING ${CMAKE_BUILD_TYPE:-RelWithDebInfo}

# Parse custom environment variable to initialize CMakeGenerator.
if [ -n "$CMAKE_GENERATOR" ]; then
  CMakeGenerator="$CMAKE_GENERATOR"
fi

# Parse command line arguments.
while [ $# -ne 0 ]; do
  case "$1" in
    -*=*)
      optarg="$(echo "$1" | sed 's/[-_a-zA-Z0-9]*=//')"
      ;;
    *)
      optarg=
      ;;
  esac
  case "$1" in
    --help|-h)
      echo "${usage}" 1>&2
      exit 1
      ;;
# -- Installation options ------------------------------------------------------
    --prefix=*)
      prefix="$optarg"
      ;;
    --without-relocatable)
      append_cache_entry VAST_ENABLE_RELOCATABLE_INSTALLATIONS BOOL no
      ;;
    --package-name=*)
      append_cache_entry CPACK_PACKAGE_FILE_NAME STRING "$optarg"
      append_cache_entry CPACK_SET_DEST_DIR BOOL yes
      append_cache_entry CPACK_GENERATOR STRING TGZ
      ;;
# -- Convenience options -------------------------------------------------------
    --debug)
      append_cache_entry CMAKE_BUILD_TYPE STRING Debug
      append_cache_entry VAST_ENABLE_ASAN BOOL yes
      # TODO: eventually, we also want to enable MORE_WARNINGS
      ;;
    --release)
      append_cache_entry CMAKE_BUILD_TYPE STRING Release
      ;;
    --ci-build)
      append_cache_entry CMAKE_BUILD_TYPE STRING CI
      append_cache_entry VAST_ENABLE_ASAN BOOL yes
      ;;
# -- Build options -------------------------------------------------------------
    --generator=*)
      CMakeGenerator="$optarg"
      ;;
    --build-dir=*)
      builddir="$optarg"
      ;;
    --build-type=*)
      append_cache_entry CMAKE_BUILD_TYPE STRING "$optarg"
      ;;
    --show-time-report)
      append_cache_entry VAST_ENABLE_TIME_REPORT BOOL yes
      ;;
    --show-time-trace)
      append_cache_entry VAST_ENABLE_TIME_TRACE BOOL yes
      ;;
    --more-warnings)
      append_cache_entry VAST_ENABLE_MORE_WARNINGS BOOL yes
      ;;
    --without-tests)
      append_cache_entry VAST_ENABLE_UNIT_TESTS BOOL no
      ;;
    --with-zeek-to-vast)
      append_cache_entry VAST_ENABLE_ZEEK_TO_VAST BOOL yes
      ;;
    --with-dscat)
      append_cache_entry VAST_ENABLE_DSCAT BOOL yes
      ;;
    --with-lsvast)
      append_cache_entry VAST_ENABLE_LSVAST BOOL yes
      ;;
    --with-example-plugin)
      if [ -z "${plugins}" ]; then
        plugins="${sourcedir}/examples/plugins/example"
      else
        plugins="${plugins};${sourcedir}/examples/plugins/example"
      fi
      ;;
    --with-plugin=*)
      plugin_parent_dir="$(dirname "$optarg")"
      if ! [ -d "$plugin_parent_dir" ]; then
        >&2 echo "not a directory: $plugin_parent_dir"
        exit 1
      fi
      plugin_dir="$(cd "$plugin_parent_dir"; pwd)/$(basename "$optarg")"
      if ! [ -d "$plugin_dir" ]; then
        >&2 echo "not a directory: $plugin_dir"
        exit 1
      fi
      if [ -z "${plugins}" ]; then
        plugins="${plugin_dir}"
      else
        plugins="${plugins};${plugin_dir}"
      fi
      ;;
    --with-plugin-autoloading)
      append_cache_entry VAST_ENABLE_PLUGIN_AUTOLOADING BOOL yes
      ;;
# -- Debugging -----------------------------------------------------------------
    --log-level=*)
      append_cache_entry VAST_LOG_LEVEL STRING \
        "$(echo "$optarg" |  tr '[a-z]' '[A-Z]')"
      ;;
    --caf-log-level=*)
      append_cache_entry VAST_CAF_LOG_LEVEL STRING \
        "$(echo "$optarg" |  tr '[a-z]' '[A-Z]')"
      ;;
    --without-assertions)
      append_cache_entry VAST_ENABLE_ASSERTIONS BOOL no
      ;;
    --without-exceptions)
      append_cache_entry VAST_ENABLE_EXCEPTIONS BOOL no
      ;;
    --without-dtrace)
      # The USDT concept was invented for DTrace on Solaris, and thus for
      # historical reasons the option to enable USDT support is commonly called
      # `--with-dtrace`, even though on linux it has nothing to do with dtrace.
      append_cache_entry VAST_ENABLE_SDT no
      ;;
    --with-asan)
      append_cache_entry VAST_ENABLE_ASAN BOOL yes
      ;;
    --with-ubsan)
      append_cache_entry VAST_ENABLE_UBSAN BOOL yes
      ;;
# -- Required packages ---------------------------------------------------------
    --with-arrow=*)
      append_cache_entry ARROW_ROOT_DIR PATH "$optarg"
      ;;
    --without-arrow)
      append_cache_entry VAST_ENABLE_ARROW BOOL no
      ;;
    --with-caf=*)
      append_cache_entry CAF_ROOT_DIR PATH "$optarg"
      ;;
    --with-bundled-caf)
      append_cache_entry VAST_ENABLE_BUNDLED_CAF BOOL yes
      ;;
    --with-flatbuffers=*)
      append_cache_entry FLATBUFFERS_ROOT_DIR PATH "$optarg"
      ;;
    --with-yaml-cpp=*)
      append_cache_entry YAML_CPP_ROOT PATH "$optarg"
      ;;
    --with-simdjson=*)
      append_cache_entry SIMDJSON_ROOT PATH "$optarg"
      ;;
    --with-fmt=*)
      append_cache_entry FMT_ROOT PATH "$optarg"
      ;;
    --with-spdlog=*)
      append_cache_entry SPDLOG_ROOT PATH "$optarg"
      ;;
# -- Optional packages ---------------------------------------------------------
    --with-broker=*)
      append_cache_entry BROKER_ROOT_DIR PATH "$optarg"
      ;;
    --with-bundled-broker)
      append_cache_entry VAST_ENABLE_BUNDLED_BROKER BOOL yes
      ;;
    --with-doxygen=*)
      append_cache_entry Doxygen_ROOT_DIR PATH "$optarg"
      ;;
    --with-jemalloc|--with-jemalloc=*)
      append_cache_entry VAST_ENABLE_JEMALLOC BOOL yes
      append_cache_entry jemalloc_ROOT_DIR PATH "$optarg"
      ;;
    --with-openssl=*)
      append_cache_entry OPENSSL_ROOT_DIR PATH "$optarg"
      ;;
    --with-pcap=*)
      append_cache_entry PCAP_ROOT_DIR PATH "$optarg"
      ;;
    *)
      echo "Invalid option '$1'.  Try $0 --help to see available options."
      exit 1
      ;;
  esac
  shift
done

if [ -d "$builddir" ]; then
  # If build directory exists, check if it has a CMake cache
  if [ -f "$builddir/CMakeCache.txt" ]; then
    # If the CMake cache exists, delete it so that this configuration
    # is not tainted by a previous one
    rm -f "$builddir/CMakeCache.txt"
  fi
else
  mkdir -p "$builddir"
fi

append_cache_entry VAST_PLUGINS STRING "${plugins}"

if [ ! -z "$prefix" ]; then
  case "$prefix" in
    /*)
      absolute_prefix="$prefix"
      ;;
    *)
      case "$builddir" in
        /*)
          absolute_prefix="$builddir/$prefix"
          ;;
        *)
          absolute_prefix="$PWD/$builddir/$prefix"
          ;;
      esac
      ;;
  esac
  # TODO: We should remove VAST_PREFIX.
  append_cache_entry VAST_PREFIX PATH "$absolute_prefix"
  append_cache_entry CMAKE_INSTALL_PREFIX PATH "$absolute_prefix"
fi

cd "$builddir"

# In order to support spaces in paths, we use eval to re-evaluate the command
# line before passing it to CMake.
cmake=cmake
if [ -n "$CMakeGenerator" ]; then
  cmake="$cmake -G \"$CMakeGenerator\""
fi
cmake="$cmake $CMakeCacheEntries \"$sourcedir\""
eval $cmake

printf "#!/bin/sh\n\n" > config.status
printf "# Switch to the source of this build directory.\n" >> config.status
printf "cd \"$sourcedir\"\n\n" >> config.status
printf "# Invoke the command to configure this build.\n" >> config.status
if [ -n "$CC" ]; then
  printf 'CC="%s" ' "$CC" >> config.status
fi
if [ -n "$CXX" ]; then
  printf 'CXX="%s" ' "$CXX" >> config.status
fi
if [ -n "$CXXFLAGS" ]; then
  printf 'CXXFLAGS="%s" ' "$CXXFLAGS" >> config.status
fi
printf "$command\n" $@ >> config.status
chmod u+x config.status
