#!/bin/bash

# Source utility functions.
source $OPENSHIFT_CARTRIDGE_SDK_BASH
source "${OPENSHIFT_NODEJS_DIR}/lib/util"
source "${OPENSHIFT_NODEJS_DIR}/lib/nodejs_context"

STOPTIMEOUT=10
FMT="%a %b %d %Y %H:%M:%S GMT%z (%Z)"

OPENSHIFT_NODEJS_WATCHDIR="${OPENSHIFT_DATA_DIR}.nodewatch"
mkdir -p ${OPENSHIFT_NODEJS_WATCHDIR}

function status() {
  if is_cartridge_running; then
    client_result "Application is running"
  else
    client_result "Application is not running"
  fi
}  #  End of function  status.

function start() {
  echo "Starting NodeJS cartridge"

  if is_cartridge_running; then
    echo "Application is already running"
    return 0
  fi

  envf="$OPENSHIFT_NODEJS_DIR/configuration/node.env"

  #  Source environment if it exists.
  [ -f "$envf" ]  &&  source "$envf"

  #  Ensure we have script file.
  node_app=${node_app:-"server.js"}

  pushd "$OPENSHIFT_REPO_DIR" > /dev/null
  echo "`date +"$FMT"`: Starting application '$OPENSHIFT_APP_NAME' ..."
  if [ ! -f "$OPENSHIFT_REPO_DIR/package.json" ]; then
      echo "    Script       = $node_app"
      echo "    Script Args  = $node_app_args"
      echo "    Node Options = $node_opts"
  fi


  if [ -f "${OPENSHIFT_REPO_DIR}package.json" ]; then
      supervisor_opts="$(get_main_script_from_package_json)"
      node_cmd="npm start -d"
  else
      #  Backward compatibility for apps without package.json
      print_missing_package_json_warning
      supervisor_opts="$node_opts $node_app $node_app_args"
      node_cmd="node $node_opts $node_app $node_app_args"
  fi

  if use_npm; then
    echo "*** NodeJS supervisor is disabled due to .openshift/markers/use_npm"
    echo "*** Starting application using: $node_cmd"
    nodejs_context "nohup $node_cmd |& /usr/bin/logshifter -tag nodejs &"
  else
    # Users are allowed to use OPENSHIFT_NODEJS_WATCH env to specify
    # comma-delimited list of folders or js files to watch for changes.
    #
    if [ -n "$OPENSHIFT_NODEJS_WATCH" ]; then
      supervisor_watch_opts="--watch ${OPENSHIFT_NODEJS_WATCH}"
    else
      echo "//$(date +%s)" > ${OPENSHIFT_NODEJS_WATCHDIR}/watcher.js
      supervisor_watch_opts="--watch ${OPENSHIFT_NODEJS_WATCHDIR}"
    fi
    nodejs_context "nohup supervisor -e 'node|js|coffee' -p ${OPENSHIFT_NODEJS_POLL_INTERVAL:-10000} ${supervisor_watch_opts} -- $supervisor_opts |& /usr/bin/logshifter -tag nodejs &"
  fi

  retries=3
  while [ $retries -gt 0 ]; do
    cart_pid=$(cartridge_pid)
    [ -n "${cart_pid}" ] && break
    sleep 1
    let retries=${retries}-1
  done

  # ensure file is created before printing it to show startup status
  sleep 2

  popd > /dev/null
  if [ -n "${cart_pid}" ]; then
      echo "$cart_pid" > "$OPENSHIFT_NODEJS_PID_DIR/cartridge.pid"
  else
      echo "Application '$OPENSHIFT_APP_NAME' failed to start" 1>&2 1
  fi
}

function stop() {
    echo "Stopping NodeJS cartridge"

    if cartridge_pidfile_exists; then
      cart_pid=$(cat $OPENSHIFT_NODEJS_PID_DIR/cartridge.pid)
      running_cart_pid=$(cartridge_pid)

      if ! is_cartridge_running; then
        echo "Warning: Application '${OPENSHIFT_APP_NAME}' is currently not running."
      fi

      echo "`date +"$FMT"`: Stopping application '$OPENSHIFT_APP_NAME' ..."

      /bin/kill $cart_pid
      ret=$?

      if [ $ret -eq 0 ]; then
        TIMEOUT="$STOPTIMEOUT"
        while [ $TIMEOUT -gt 0 ]  && is_cartridge_running ; do
          /bin/kill -0 "$cart_pid" >/dev/null 2>&1 || break
          sleep 1
          let TIMEOUT=${TIMEOUT}-1
        done
      fi

      if is_supervisor_running; then
        supervisor=$(supervisor_bin)
        if [ -n "$supervisor" ]; then
          pkill -f "${supervisor}" 2>&1 || :
        fi
      elif is_node_running; then
        node=$(node_bin)
        if [ -n "$node" ]; then
          pkill -f "${node}" 2>&1 || :
        fi
      fi

      # Kill remaining 'node' processes.
      # When running under 'use_npm', the npm will ignore the 'kill' calls above
      # and keep running. Killing all node processes will put 'npm' down.
      #
      if [ -n "$(node_pid)" ]; then
        kill $(node_pid)
      fi

      if is_cartridge_running ; then
        echo "Warning: Application '$OPENSHIFT_APP_NAME' unable to stop. Use force-stop to kill."
      else
        echo "`date +"$FMT"`: Stopped Node application '$OPENSHIFT_APP_NAME'"
        rm -f $OPENSHIFT_NODEJS_PID_DIR/cartridge.pid
      fi

    else
      if [ -n "$(cartridge_pid)" ]; then
        echo "Warning: Application '$OPENSHIFT_APP_NAME' exists without a pid file.  Use force-stop to kill."
      fi
    fi
}

function restart() {
    is_cartridge_running && stop
    start
}

function build() {
    echo "Building NodeJS cartridge"
    node_modules_dir="${OPENSHIFT_REPO_DIR}node_modules/"
    saved_modules_dir="${OPENSHIFT_NODEJS_DIR}/tmp/saved.node_modules"

    # Ensure that we have the node_modules directory.
    mkdir -p $node_modules_dir

    if force_clean_build_enabled_for_latest_deployment; then
        echo "Force-clean builds are enabled. Recreating npm modules" 1>&2

        # Remove saved modules, if any.
        rm -rf $saved_modules_dir

        # Clean the npm cache. (This will clean the ~/.npm directory).
        npm cache clean

        # Link back the global modules.
        link_global_modules $OPENSHIFT_NODEJS_VERSION
    else
        # Restore the saved node_modules from prior builds.
        if [ -d "${OPENSHIFT_NODEJS_DIR}/tmp/saved.node_modules" ]; then
            for d in `ls -a ${OPENSHIFT_NODEJS_DIR}/tmp/saved.node_modules`; do
                [ -e "${node_modules_dir}$d" ]  ||  \
                  mv "${OPENSHIFT_NODEJS_DIR}/tmp/saved.node_modules/$d" "$node_modules_dir"
            done
            rm -rf "${OPENSHIFT_NODEJS_DIR}/tmp/saved.node_modules"
        fi
    fi

    #  Newer versions of Node set tmp to $HOME/tmp, which is not available
    nodejs_context "npm config set tmp $OPENSHIFT_TMP_DIR"

    # FIXME: Remove this line once we update NPM to latest version
    nodejs_context 'npm config set ca ""'

    if [ -f "${OPENSHIFT_REPO_DIR}"/deplist.txt ]; then
        mods=$(perl -ne 'print if /^\s*[^#\s]/' "${OPENSHIFT_REPO_DIR}"/deplist.txt)
        [ -n "$mods" ]  &&  print_deprecation_warning
        for m in $mods; do
            echo "Checking npm module: $m"
            echo
            if is_node_module_installed "$m"; then
                (cd "${OPENSHIFT_NODEJS_DIR}"; nodejs_context "npm update '$m'")
            else
                (cd "${OPENSHIFT_NODEJS_DIR}"; nodejs_context "npm install '$m'")
            fi
        done
    fi

    # Workaround for failure in npm install when a package in package.json
    # points to a git commit.
    # This issue occurs because we are running in the context of a
    # git post receive-hook
    unset GIT_DIR
    unset GIT_WORK_TREE

    nodejs_context /bin/bash
    if [ -f "${OPENSHIFT_REPO_DIR}"/package.json ]; then
        (cd "${OPENSHIFT_REPO_DIR}"; nodejs_context "npm install -d")
    fi
}



function post-deploy() {
    if hot_deploy_enabled_for_latest_deployment; then
      if use_npm; then
        restart
      else
        #
        # Check if supervisor is already running. If not do a restart.
        # If it is running, update the watcher.js to tell nodejs to restart
        # the node processes.
        #
        if is_supervisor_running; then
          if [[ -z ${OPENSHIFT_NODEJS_WATCH} ]]; then
            echo "//$(date +%s)" > ${OPENSHIFT_NODEJS_WATCHDIR}/watcher.js
          fi
        else
          echo "Restarting NodeJS supervisor."
          restart
        fi
      fi
    fi
}

function pre-repo-archive() {
    rm -rf ${OPENSHIFT_NODEJS_DIR}/tmp/{node_modules,saved.node_modules}

    # If the node_modules/ directory exists, then "stash" it away for redeploy.
    node_modules_dir="${OPENSHIFT_REPO_DIR}node_modules"
    if [ -d "$node_modules_dir" ]; then
      echo 'Saving away previously installed Node modules'
      mv "$node_modules_dir" "${OPENSHIFT_NODEJS_DIR}/tmp/saved.node_modules"
      mkdir -p "$node_modules_dir"
    fi
}

# Clean up any log files
function tidy() {
  client_message "Emptying nodejs logs in dir: $OPENSHIFT_LOG_DIR"
  shopt -s dotglob
  rm -rf $OPENSHIFT_LOG_DIR/nodejs.log*
  rm -rf ${OPENSHIFT_NODEJS_DIR}tmp/*
}

#
#  main():
#

# Ensure arguments.
if ! [ $# -eq 1 ]; then
    echo "Usage: $0 [start|restart|graceful|graceful-stop|stop|status]"
    exit 1
fi

# Handle commands.
case "$1" in
    start)               start       ;;
    restart|graceful)    restart     ;;
    graceful-stop|stop)  stop        ;;
    status)              status      ;;
    build)               build       ;;
    post-deploy)         post-deploy ;;
    tidy)                tidy        ;;
    pre-repo-archive)    pre-repo-archive ;;
    *) exit 0;
esac
