#! /usr/bin/env bash

# Licensed to the Apache Software Foundation (ASF) under one or more contributor license
# agreements. See the NOTICE file distributed with this work for additional information regarding
# copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance with the License. You may obtain a
# copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software distributed under the License
# is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
# or implied. See the License for the specific language governing permissions and limitations under
# the License.

SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do
   bin="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
   SOURCE="$(readlink "$SOURCE")"
   [[ $SOURCE != /* ]] && SOURCE="$bin/$SOURCE"
done
# Set up variables needed by fluo-env.sh
export bin="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
export basedir="$( cd -P ${bin}/.. && pwd )"
export conf="$basedir/conf"
export lib="$basedir/lib"
export cmd="$1"
case "$cmd" in
  oracle|worker|init) export app="$2" ;;
esac
export FLUO_VERSION=2.0.0

if [ ! -f "$conf/fluo-env.sh" ]; then
  echo "fluo-env.sh must exist in $conf"
  exit 1
fi
source "$conf/fluo-env.sh"
export CLASSPATH
JAVA="java ${JAVA_OPTS[*]}"
if [ -f "$FLUO_CONN_PROPS" ]; then
  JAVA="$JAVA -Dfluo.conn.props=$FLUO_CONN_PROPS"
fi

deprecated_fluo_props=$conf/fluo.properties

if [[ -f "$deprecated_fluo_props" ]]; then
  echo "Fluo no longer supports running applications in YARN using Twill (Twill does not support Hadoop 3).  The presence of the file $deprecated_fluo_props implies this is desired."
  exit 1
fi

# stop if any command fails
set -e

function copy_config {
  if [ -f "$conf/$1" ]; then
    cp "$conf/$1" "$APP_CONF_DIR/"
  elif [ -f "$conf/examples/$1" ]; then
    cp "$conf/examples/$1" "$APP_CONF_DIR"
  else
    echo "Config file $1 not found in $conf or $conf/examples"
    exit 1
  fi
}

function print_usage {
  echo -e "Usage: fluo <command> (<argument> ...)\n"
  echo -e "Possible commands:\n"
  echo "  init -a <app> -p <appProps>   Initializes Fluo application for <app> using <appProps>. Run with -h to see additional args."
  echo "  remove -a <app>               Removes Fluo application for <app>"
  echo "  classpath                     Prints the classpath setup in fluo-env.sh"
  echo "  config -a <app>               Prints application configuration stored in Zookeeper for <app>"
  echo "  get-jars -a <app> -d <dir>    Copies <app> jars from DFS to local <dir>"
  echo "  list                          Lists all Fluo applications in Fluo instance"
  echo "  scan -a <app>                 Prints snapshot of data in Fluo <app>"
  echo "  status -a <app>               Prints status of Fluo application for <app>"
  echo "  oracle -a <app>               Starts Fluo Oracle process for <app>"
  echo "  worker -a <app>               Starts Fluo Worker process for <app>"
  echo "  version                       Prints the version of Fluo"
  echo "  wait -a <app>                 Waits until all notifications are processed for <app>"
  echo "  exec <app> <class> {<arg>}    Executes <class> with <args> using classpath for <app>";
  echo " "
  exit 1
}

function check_conn_props {
  if [ ! -f "$FLUO_CONN_PROPS" ]; then
    echo "$FLUO_CONN_PROPS must exist!"
    exit 1
  fi
}

function verify_app {
  if [ -z "$1" ]; then
    echo -e "The application name (set by <app>) cannot be an empty string!\n"
    print_usage
  fi
}

function check_hadoop {
  if [[ -z $HADOOP_PREFIX ]]; then
    echo "HADOOP_PREFIX needs to be set!"
    exit 1
  fi
  if [ ! -d "$HADOOP_PREFIX" ]; then
    echo "HADOOP_PREFIX=$HADOOP_PREFIX is not a valid directory.  Please correct it in your .bashrc or fluo-env.sh"
    exit 1
  fi
}

function setup_service {
  if [[ "$@" =~ ^.*-a\ *([^\ ]*).*$ ]]; then
    app=${BASH_REMATCH[1]}

    verify_app "$app"
    check_conn_props
    # create a temp dir to fetch application jars to
    app_lib=$(mktemp -d "$FLUO_TMP"/fluo-"$app"-XXXXXXXXX) || die "fatal: unable to allocate a temporary directory"
    # schedule removal of app_lib tmp dir when this script exits
    trap "rm -rf '""$app_lib""'" EXIT HUP INT QUIT TERM
    $JAVA org.apache.fluo.command.FluoProgram get-jars -d "$app_lib" "$@"
    export CLASSPATH="$conf:$app_lib/*:$CLASSPATH"
  else
    echo "Application name must be set!"
    print_usage
    exit 1
  fi
}

case "$1" in
config|get-jars)
  check_conn_props
  $JAVA org.apache.fluo.command.FluoProgram "$@"
  ;;
init)
  if [[ $2 = *"-h"* ]]; then
    $JAVA org.apache.fluo.command.FluoProgram $1 -h
    exit 0
  fi
  init_dir=$($JAVA org.apache.fluo.command.FluoProgram "$@" --retrieveProperty fluo.observer.init.dir)
  if [ -d "$init_dir" ]; then
    echo "Adding $init_dir/* to CLASSPATH"
    export CLASSPATH="$init_dir/*:$CLASSPATH"
  fi
  $JAVA org.apache.fluo.command.FluoProgram "$@"
  ;;
remove)
  if [[ $2 = *"-h"* ]]; then
    $JAVA org.apache.fluo.command.FluoProgram $1 -h
    exit 0
  fi
  $JAVA org.apache.fluo.command.FluoProgram "$@"
  ;;
oracle|worker)
  if [[ $2 = *"-h"* ]]; then
    $JAVA org.apache.fluo.command.FluoProgram $1 -h
    exit 0
  fi
  setup_service "${@:2}"
  $JAVA org.apache.fluo.command.FluoProgram "$@"
  ;;
scan)
  if [ -f "$FLUO_CONN_PROPS" ]; then
    $JAVA org.apache.fluo.command.FluoProgram "$@"
  else
    check_hadoop
    java org.apache.fluo.cluster.command.FluoCommand "$basedir" "$HADOOP_PREFIX" "$@"
  fi
  ;;
ps)
  jps -m | grep Fluo
  ;;
list)
  if [ -f "$FLUO_CONN_PROPS" ]; then
    $JAVA org.apache.fluo.command.FluoProgram "$@"
  else
    check_hadoop
    java org.apache.fluo.cluster.command.FluoCommand "$basedir" "$HADOOP_PREFIX" list app "${@:2}"
  fi
  ;;
classpath)
  echo "$CLASSPATH"
  ;;
exec)
  if [[ $2 = *"-h"* ]]; then
    $JAVA org.apache.fluo.command.FluoProgram $1 -h
    exit 0
  fi
  app=$2
  verify_app "$app"
  check_conn_props
  # create a temp dir to fetch application jars to
  app_lib=$(mktemp -d "$FLUO_TMP"/fluo-"$app"-XXXXXXXXX) || die "fatal: unable to allocate a temporary directory"
  # schedule removal of app_lib tmp dir when this script exits
  trap "rm -rf '""$app_lib""'" EXIT HUP INT QUIT TERM
  $JAVA org.apache.fluo.command.FluoProgram get-jars -d "$app_lib" -a "$app"
  export CLASSPATH="$conf:$app_lib/*:$CLASSPATH"
  $JAVA org.apache.fluo.command.FluoProgram "$@"
  ;;
status|wait)
  $JAVA org.apache.fluo.command.FluoProgram "$@"
  ;;
version)
  echo "$FLUO_VERSION"
  ;;
*)
  print_usage
esac
