#!/bin/bash

# Copyright (c) 2002-2014 "Neo Technology,"
# Network Engine for Objects in Lund AB [http://neotechnology.com]
#
# This file is part of Neo4j.
#
# Neo4j is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.


function show_java_requirements() {
  echo "* Please use Oracle(R) Java(TM) 7 to run Neo4j Server. Download \"Java Platform (JDK) 7\" from:"
  echo "  http://www.oracle.com/technetwork/java/javase/downloads/index.html"
}

function show_installation_instructions() {
  echo "* Please see http://docs.neo4j.org/ for Neo4j Server installation instructions."
}

# getconfig <filename>
#   - plain key-value pairs become environment variables
#   - keys have '.' chars changed to '_'
#   - keys of the form KEY.# (where # is a number) are concatenated
#     into a single environment variable named KEY
function getconfig {
  if [ -e "$1" ]; then
    while read line ; do
      if [[ ${line} =~ ^([^#\s][^=]+)=(.+)$ ]]; then
        key=`echo ${BASH_REMATCH[1]} | sed 's/\./_/g'`
        value="${BASH_REMATCH[2]}"
        if [[ ${key} =~ ^(.*)_([0-9]+)$ ]]; then
          key="${BASH_REMATCH[1]}"
        fi
        if [[ ${!key} ]]; then
          export ${key}="${!key} ${value}"
        else
          export ${key}="$value"
        fi
      fi
    done < "$1"
  fi
}

function getconfigquoted {
  if [ -e "$1" ]; then
    while read line ; do
      if [[ ${line} =~ "^([^#\s][^=]+)=(.+)$" ]]; then
        key=`echo ${BASH_REMATCH[1]} | sed 's/\./_/g'`
        value="${BASH_REMATCH[2]}"
        if [[ ${key} =~ "^(.*)(_[0-9]+)?$" ]]; then
          key=${BASH_REMATCH[1]}
        fi
        if [[ ${!key} ]]; then
          export ${key}="${!key} ${value}"
        else
          export ${key}="$value"
        fi
      fi
    done < "$1"
  fi
}

# Detect java and set JAVACMD on successful find.
findjava() {
  # OS specific support.  $var _must_ be set to either true or false.
  cygwin=false;
  darwin=false;
  case "`uname`" in
    CYGWIN*) cygwin=true ;;
    Darwin*) darwin=true
           if [ -z "$JAVA_VERSION" ] ; then
             JAVA_VERSION="CurrentJDK"
           else
             echo "Using Java version: $JAVA_VERSION"
           fi
           if [ -z "$JAVA_HOME" ] ; then
             JAVA_HOME=`/usr/libexec/java_home -v 1.7`
           fi
           ;;
  esac

  if [ -z "$JAVA_HOME" ] ; then
    if [ -r /etc/gentoo-release ] ; then
      JAVA_HOME=`java-config --jre-home`
    fi
  fi

  # For Cygwin, ensure paths are in UNIX format before anything is touched
  if $cygwin ; then
    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
    [ -n "$CLASSPATH" ] && CLASSPATH=`cygpath --path --unix "$CLASSPATH"`
  fi

  # If a specific java binary isn't specified search for the standard 'java' binary
  if [ -z "$JAVACMD" ] ; then
    if [ -n "$JAVA_HOME"  ] ; then
      if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
        # IBM's JDK on AIX uses strange locations for the executables
        JAVACMD="$JAVA_HOME/jre/sh/java"
      else
        JAVACMD="$JAVA_HOME/bin/java"
      fi
    else
      if [ "`uname`" != "Darwin" ] ; then
        # Don't use default java on Darwin because it displays a misleading dialog box
        JAVACMD=`which java`
      fi
    fi
  fi
}

checkstatus() {
  if [ -e "$PID_FILE" ] ; then
    NEO4J_PID=$( cat "$PID_FILE" )
    kill -0 $NEO4J_PID 2>/dev/null || NEO4J_PID=
  fi
}

checkwriteaccess() {
    if [ $UID != 0 ] ; then
    if [ ! -w "$NEO4J_INSTANCE/data" ] ; then
      echo "ERROR: No write access to data/ directory, run either as user $NEO4J_USER or root"
      exit 1
    fi
    fi
}

reportstatus() {

  checkstatus
  detectos
  exitonnojava

  if [ $DIST_OS = "macosx" ] ; then
    getlaunchdpid
    if [ $LAUNCHDPID -gt 0 ] ; then
      echo "Instance running via launchd with PID $LAUNCHDPID"
      exit 0
    fi
    # We fall through here since if there is no launchd install we may be still running via script
  fi

  if [ -z $NEO4J_PID ] ; then
    echo "$FRIENDLY_NAME is not running"
	exit 3
  else
    echo "$FRIENDLY_NAME is running at pid $NEO4J_PID"
  fi
}

# Use findjava to set JAVACMD. If that fails ($JAVACMD is not set) then exit with failure
exitonnojava() {
  findjava

  if [ ! -x "$JAVACMD" ] ; then
    echo "ERROR: Unable to find java. (Cannot execute $JAVACMD)"
    show_java_requirements
    show_installation_instructions
    exit 1
  fi
}

# Resolve the os
detectos() {
  DIST_OS=`uname -s | tr [A-Z] [a-z] | tr -d ' '`
  case "$DIST_OS" in
    'sunos')
      DIST_OS="solaris"
      ;;
    'hp-ux' | 'hp-ux64')
      # HP-UX needs the XPG4 version of ps (for -o args)
      DIST_OS="hpux"
      UNIX95=""
      export UNIX95   
      ;;
    'darwin')
      DIST_OS="macosx"
      ;;
    'unix_sv')
      DIST_OS="unixware"
      ;;
    'os/390')
      DIST_OS="zos"
      ;;
    'cygwin')
      DIST_OS="cygwin"
      ;;
  esac
}

getlaunchdpid() {
  LAUNCHDPID=$(launchctl list | grep $LAUNCHD_NAME | cut -f 1)
  if [ -z $LAUNCHDPID ] ; then
    # Not there
    LAUNCHDPID=-1
  elif [ $LAUNCHDPID = "-" ] ; then
    # There but not running
    LAUNCHDPID=0
  else
    # There and running
    LAUNCHDPID=$(($LAUNCHDPID))
  fi
}

stopit() {

  detectos
  checkstatus
  checkwriteaccess

  if [ $DIST_OS = "macosx" ] ; then
    getlaunchdpid
    if [ $LAUNCHDPID -gt 0 ] ; then
      echo "Instance running via launchd with PID $LAUNCHDPID, stopping it..."
      launchctl stop $LAUNCHD_NAME
      return
    fi
    # We fall through here since if there is no launchd install we stop manually started instance
  fi

  if [ -z $NEO4J_PID ] ; then
    echo "ERROR: $FRIENDLY_NAME not running"
    [ -e "$PID_FILE" ] && rm "$PID_FILE"
  else
    printf "Stopping $FRIENDLY_NAME [$NEO4J_PID]..."
    x=0
    while [ $x -lt $TIMEOUT ] && [ "$NEO4J_PID" != "" ]  ; do
      kill $NEO4J_PID 2>/dev/null
      printf "."
      sleep 1
      checkstatus
      x=$[$x+1]
    done
	  [  $x -eq $TIMEOUT ] && ( echo " force shutdown" ;  kill -9 $NEO4J_PID >/dev/null ) || echo " done"
	  [ -e "$PID_FILE" ] && rm  "$PID_FILE"
  fi
}

# Creates a user on the system
create_user() {
  useradd -r $1
  modify_user_config $1 "true"
  echo "Created user \"${1}\"."
}

remove_user() {
  if [[ $wrapper_user_created == "true" ]]; then
    if [[ $HEADLESS == false ]]; then
      read -p "It appears that user \"${wrapper_user}\" was created during install. Remove that user now? [yN] " yn
    else
      yn="y"
    fi

    if [ -x '/usr/sbin/deluser' ]; then
      DELETE_CMD='/usr/sbin/deluser'
    else
      DELETE_CMD='/usr/sbin/userdel'
    fi
    
    case $yn in
      [Yy]* ) $DELETE_CMD $wrapper_user
              modify_user_config "" "true"
        ;;
      * ) echo "OK, we'll let that user live, for now." 
        ;;
    esac
  else
    echo "$FRIENDLY_NAME was running as user \"${wrapper_user}\", which remains."
  fi
}

removeservice() {
    detectos
    checkstatus
    selectinittool

    PLIST_FILE=$LAUNCHD_NAME.plist

    if [[ -d "/etc/init.d" ]]; then
      if [[ -e "/etc/init.d/${SERVICE_NAME}" ]]; then
        if [  $UID != 0 ] ; then
          eval echo  'Must be root to perform this action.'
          exit 1
        else
          if [ ! -z $NEO4J_PID ] ; then
            stopit
          fi

          if [ $INIT_TOOL == 'chkconfig' ]; then
            chkconfig --del ${SERVICE_NAME}
          else
            update-rc.d -f ${SERVICE_NAME} remove
          fi
          rm /etc/init.d/${SERVICE_NAME}
        fi

        # remove effective user, if created by install-script
        remove_user
      else
        echo "${SERVICE_NAME} not installed."
      fi

    elif [[ $DIST_OS -eq "macosx" ]] ; then
      if [[ -e ${LAUNCHD_DIR}/$PLIST_FILE ]]; then
        launchctl unload -w ${LAUNCHD_DIR}/$PLIST_FILE
        rm ${LAUNCHD_DIR}/$PLIST_FILE
      fi
    else
      echo "Sorry, don't know how to install on ${DIST_OS}."
    fi
}

# Runs before the server command, making sure that whatever should be in place is
# in place.
checkandrepairenv() {
    # Create data/log if missing, change owner if created.
    if [ ! -d "$NEO4J_HOME"/data/log ]; then
      echo "${NEO4J_HOME}/data/log was missing, recreating..."
      mkdir "$NEO4J_HOME"/data/log
      if [ $UID == 0 ] ; then
        chown $NEO4J_USER "$NEO4J_HOME"/data/log
      fi
    fi
}

# Checks system limits, warns if not proper
checklimits() {
    if [[ $DIST_OS != "macosx" ]] ; then
      if [ $UID == 0 ] ; then
        OPEN_FILES=`su $NEO4J_USER -c "ulimit -n"`
      else
        OPEN_FILES=`ulimit -n`
      fi

      if [ $OPEN_FILES -lt 40000 ]; then
        echo "WARNING: Max $OPEN_FILES open files allowed, minimum of 40 000 recommended. See the Neo4j manual."
      fi
    fi
}

selectinittool() {
  if [ -x '/sbin/chkconfig' ]; then
    INIT_TOOL='chkconfig'
  else
    INIT_TOOL='update-rc.d'
  fi
}

warn_about_java_runtime() {
  echo "WARNING! You are using an unsupported Java runtime. "
  show_java_requirements
  show_installation_instructions
}

complain_about_java_version() {
  echo "ERROR! Neo4j cannot be started using java version $JAVAVERSION. "
  show_java_requirements
  show_installation_instructions
}

# check if running Oracle JDK 7, warn if not
checkjvmcompatibility() {
  # Shut down if java version < 1.7
  JAVAVERSION=$("$JAVACMD" -version 2>&1 | awk -F '"' '/version/ {print $2}')
  if [[ "$JAVAVERSION" < "1.7" ]]; then
    complain_about_java_version
    exit 1
  fi

  $JAVACMD -version 2>&1 | egrep -q "Java HotSpot\\(TM\\) (64-Bit Server|Server|Client) VM"
  if [ $? -eq 1 ]
  then
    warn_about_java_runtime
  fi
}

checkclasspath() {
  echo $CLASSPATH | egrep -q 'neo4j-kernel-[0-9.]{2,8}-SNAPSHOT' && \
  echo -e "\nWARNING! Latest Development Build. Not intended for general-purpose use. May be unstable."
}