#!/bin/bash
#
# Script to start bc-web.
#
# usage:
#   bc-web [--cluster name] [server][:port] ...
#   bc-web --version
#   bc-web --help
#
# for full details see: https://beyondcron.com/docs/bc-web.html
#
# Copyright 2023 BeyondCron Pty Ltd and related entities / All rights reserved.

realPath() {
  path=$1
  target=$(readlink "${path}")

  while [ -n "${target}" ]; do
    path=$(cd $(dirname "${path}") && cd $(dirname "${target}") && pwd -P)/$(basename "${target}")
    target=$(readlink ${path})
  done

  if [ -d "${path}" ]; then
    path=$(cd "${path}" && pwd -P)
  elif [ -f "${path}" ]; then
    path=$(cd $(dirname "${path}") && pwd -P)/$(basename "${path}")
  fi

  echo "${path}"
}

usage() {
    echo "usage: $0 [--cluster <name>] [<server>][:<port>] ..."
    echo "       $0 --version"
    echo "       $0 --help"
}

self=$(realPath "$0")
dir=$(dirname "${self}")
name=$(basename "${self}")
rootDir=$(dirname "${dir}")

export BEYONDCRON_BIN_DIR=dir

# print help and exit
if [ "$1" == '--help' ] || [ "$1" == '-?' ]; then
  usage
  exit 0

elif [ "$1" == '--version' ] || [ "$1" == '-v' ]; then
  showVersion=true

# define the cluster name
elif [ "$1" == '--cluster' ] || [ "$1" == '-c' ]; then
  shift
  if [ -n "$1" ]; then
    export BEYONDCRON_CLUSTER_NAME=$1
    shift
  else
    echo "$0: cluster name is undefined" >&2
    exit 1
  fi

# unknown flag
elif [ -n "$1" ] || [ "$(echo "$1" | cut -c1)" == '-' ]; then
  exec 1>&2
  usage
  exit 1
fi

if [ $# -gt 0 ]; then
  export BEYONDCRON_SERVER_NAMES="$*"
fi

# find java
if [ -z "${JAVA_HOME}" ]; then
  if ( ! which java > /dev/null 2>&1 ); then
      echo "$0: could not find Java" >&2
      exit 1
  fi
  java='java'

else
  java="${JAVA_HOME}/bin/java"
  if [ ! -x "${java}" ]; then
    java="${JAVA_HOME}/jre/sh/java"
    if [ ! -x "${java}" ]; then
      echo "$0: could not find Java" >&2
      exit 1
    fi
  fi
fi

# confirm that we have found a supported version of Java
version=$( ${java} -version 2>&1 | grep version | cut -d'"' -f 2)
java_version=$( echo "$version" | cut -d'.' -f 1 )
if [[ ! "${java_version}" =~ ^[0-9]+$ ]]; then
  echo "$0: unexpected Java version number: $version" >&2
  exit 1
elif [ "${java_version}" -lt 11 ]; then
  echo "$0: Java ${java_version} is not supported, please use Java 11 or greater"
  exit 1
fi

# setup hazelcast logging and java modules
javaOpts="-Dprogram.name=${name} -Dhazelcast.logging.type=log4j2 --add-modules java.se --add-exports java.base/jdk.internal.ref=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.nio=ALL-UNNAMED --add-opens java.base/sun.nio.ch=ALL-UNNAMED --add-opens java.management/sun.management=ALL-UNNAMED --add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED"

if [ -n "${JAVA_OPTS}" ]; then
  export JAVA_OPTS="${JAVA_OPTS} ${javaOpts}"
else
  export JAVA_OPTS="${javaOpts}"
fi

# find war file
libDir="${rootDir}/lib"
warFile=$(find "${libDir}"/bc-web-*.war 2> /dev/null | sort | tail -1)
if [ -z "${warFile}" ]; then
  echo "$0: could not find bc-web war file in ${libDir}" >&2
  exit 1
fi

# define tomcat home
export CATALINA_HOME="${rootDir}/apache-tomcat"

# print version and exit
if [ -n "$showVersion" ]; then
  echo "bc-web: $(echo "${warFile}" | sed 's/.*web-//' | sed 's/.war//')"
  echo "    Java: $(${java} -jar "${warFile}")"
  echo "  Tomcat: $(grep 'Apache Tomcat Version' "${CATALINA_HOME}/RELEASE-NOTES" | awk '{print $4}')"
  exit 0
fi

# init Tomcat if not already inited, and not installed in /opt/beyondcron
if [ -z "$CATALINA_BASE" ]; then

  if [ "$rootDir" != '/opt/beyondcron' ]; then
    webappsDir="${CATALINA_HOME}/webapps"
    if [ ! -w "$webappsDir" ]; then
      echo "$0: cannot update directory ${webappsDir}" >&2
      exit 1
    fi

    # ensure that the webapps dir exists
    webappsDist="${webappsDir}.dist"
    if [ ! -e "$webappsDist" ]; then
      mv "$webappsDir" "$webappsDist"
      mkdir "$webappsDir"
    fi

    # ensure that the ROOT.war link exists and is up to date
    rootWar="${webappsDir}/ROOT.war"
    rootWarLink=$( readlink "$rootWar" 2> /dev/null )
    if [ "$rootWarLink" != "$warFile" ]; then
      if [ -e "$rootWar" ]; then
        rm "$rootWar"
      fi
      ln -s "${warFile}" "$rootWar"
    fi

    # ensure that the docs context exists
    contextDir="${CATALINA_HOME}/conf/Catalina/localhost"
    if [ ! -d "$contextDir" ]; then
      mkdir -p "$contextDir"
    fi

    docsXml="${contextDir}/docs.xml"
    if [ ! -f "$docsXml" ]; then
      echo "<Context docBase=\"${rootDir}/docs/\"/>" > "$docsXml"
    fi

    export CATALINA_BASE=$CATALINA_HOME

  else
    export CATALINA_BASE="/var/bc-web/apache-tomcat"
    if [ ! -d $CATALINA_BASE ]; then
      echo "$0: $CATALINA_BASE does not exist, please reinstall BeyondCron" >&2
      exit 1
    fi
  fi
fi

if [ ! -e $CATALINA_BASE ]; then
  echo "$0: $CATALINA_BASE does not exist" >&2
  exit 1
elif [ ! -O $CATALINA_BASE ]; then
  owner=$(stat -c '%U' "$CATALINA_BASE")
  echo "$0: $CATALINA_BASE is owned by $owner" >&2
  exit 1
fi

cmd="${CATALINA_HOME}/bin/catalina.sh"
if [ ! -e $cmd ]; then
  echo "$0: $cmd does not exist" >&2
  exit 1
elif [ ! -x $cmd ]; then
  echo "$0: cannot execute $cmd" >&2
  exit 1
fi

export CATALINA_TMPDIR="/var/tmp"

if [ -n "${BEYONDCRON_ALERT_COMMAND}" ]; then
    alertCmd=${BEYONDCRON_ALERT_COMMAND}

    aCmd=$(echo "${alertCmd}" | cut -d' '  -f1)
    if [ ! -x "${aCmd}" ]; then
        echo "$0: alert command ${aCmd} does not exist" >&2
        exit 1
    fi
fi

stopSignal=${BEYONDCRON_SIGNAL_STOP:-WINCH}
if [ $(kill -l | grep -c "${stopSignal}") -ne 1 ]; then
  echo "$0: unknown stop signal ${stopSignal}, using WINCH instead" >&2
  stopSignal=$(kill -l WINCH)
elif [[ ! "$stopSignal" =~ ^[0-9]+$ ]]; then
  stopSignal=$(kill -l $stopSignal)
fi

termSignal=$(kill -l TERM)

trapSignal=0
trap 'echo "$0: stopping ${name} after receiving signal INT" >&2; trapSignal=${termSignal}; kill -TERM $childPid' INT
trap 'echo "$0: stopping ${name} after receiving signal TERM" >&2; trapSignal=${termSignal}; kill -TERM $childPid' TERM
trap 'echo "$0: shutting down ${name}"; kill -${stopSignal} $childPid; $cmd stop' ${stopSignal}
trap '' HUP USR1 USR2

# start bc-web/tomcat and wait for it to stop
$cmd run &
childPid=$!
wait $childPid
result=$?
code=$(($result & 127))

while [ $result -ge 128 ] && [ $code -eq $trapSignal ]; do
  trapSignal=0
  wait $childPid
  result=$?
  code=$(($result & 127))
done

if [ $result -ge 128 ] && [ $code -eq $stopSignal ]; then
  code=0
fi

if [ ${code} -ne 0 ]; then
  export BEYONDCRON_DAEMON=${name}
  export BEYONDCRON_EXIT_CODE=${code}
  export BEYONDCRON_OS_USER=$(id -un)
  export BEYONDCRON_ALERT_REASON="${name} stopped unexpectedly"

  echo "$0: ${BEYONDCRON_ALERT_REASON}" >&2

  if [ -n "${alertCmd}" ]; then
      eval "${alertCmd}"
  fi

  if [ $result -ge 128 ]; then
    code=2
  fi

else
  echo "${name} shutdown"
fi

exit $code

# end