#!/bin/sh
#
# Copyright 2009-2011 the original author or authors.
#
# Licensed 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.
#

#-------------------------------------------
# OS specific support
#-------------------------------------------

OS_CYGWIN=false
OS_MSYS=false
OS_DARWIN=false
case "`uname`" in
  CYGWIN* )
    OS_CYGWIN=true
    ;;
  Darwin* )
    OS_DARWIN=true
    ;;
  MINGW* )
    OS_MSYS=true
    ;;
esac

# For Cygwin, ensure paths are in UNIX format before anything is touched.
# When they are used by Groovy, Groovy's script will convert them appropriately.
if $OS_CYGWIN; then
    GROOVY_HOME=`cygpath --unix --ignore "$GROOVY_HOME"`
    GROOVYSERV_HOME=`cygpath --unix --ignore "$GROOVYSERV_HOME"`
    CLASSPATH=`cygpath --unix --ignore --path "$CLASSPATH"`

    # TODO Original Groovy's shell scirpt uses only HOME instead of USERPROFILE.
    # In GroovyServ, let it be in order to unify the work directory for both cygwin and BAT.
    HOME=`cygpath --unix --ignore "$USERPROFILE"`
fi

#-------------------------------------------
# Parse arguments
#-------------------------------------------

while [ $# -gt 0 ]; do
    case $1 in
        -v)
            GROOVYSERV_OPTS="$GROOVYSERV_OPTS -Dgroovyserver.verbose=true"
            shift
            ;;
        -q)
            QUIET=true
            shift
            ;;
        -p)
            shift
            GROOVYSERVER_PORT=$1
            shift
            ;;
        -k)
            DO_KILL=KILL_ONLY
            shift
            ;;
        -r)
            DO_KILL=RESTART
            shift
            ;;
        *)
            echo "usage: `basename $0` [options]"
            echo "options:"
            echo "  -v         verbose output to the log file"
            echo "  -q         suppress starting messages"
            echo "  -k         kill the running groovyserver"
            echo "  -r         restart the running groovyserver"
            echo "  -p <port>  specify the port to listen"
            exit 1
            ;;
    esac
done

#-------------------------------------------
# Common function
#-------------------------------------------

error_log() {
    local MESSAGE="$1"
    /bin/echo "$MESSAGE" 1>&2
}

info_log() {
    local MESSAGE="$1"
    if [ ! $QUIET ]; then
        /bin/echo "$MESSAGE" 1>&2
    fi
}

resolve_symlink() {
    local TARGET=$1

    # if target is symbolic link
    if [ -L $TARGET ]; then
        local ORIGINAL_FILEPATH=`readlink $TARGET`

        # if original is specified as absolute path
        if [ $(echo $ORIGINAL_FILEPATH | cut -c 1) = "/" ]; then
            echo "$ORIGINAL_FILEPATH"
        else
            echo "$(dirname $TARGET)/$ORIGINAL_FILEPATH"
        fi
    else
        echo "$TARGET"
    fi
}

expand_path() {
    local TARGET=$1
    if [ -d "$TARGET" ]; then
        echo $(cd $TARGET && pwd -P)
    elif [ -f "$TARGET" ]; then
        local TARGET_RESOLVED=$(resolve_symlink $TARGET)
        local FILENAME=$(basename $TARGET_RESOLVED)
        local DIR_EXPANDED="$(expand_path $(dirname $TARGET_RESOLVED))"
        echo "$DIR_EXPANDED/$FILENAME"
    else
        echo "$TARGET"
    fi
}

#-------------------------------------------
# Find groovy command
#-------------------------------------------

if [ "$GROOVY_HOME" != "" ]; then
    info_log "Groovy home directory: $GROOVY_HOME"
    GROOVY_BIN="$GROOVY_HOME/bin/groovy"
    if [ ! -x "$GROOVY_BIN" ]; then
        error_log "ERROR: Not found a groovy command in GROOVY_HOME: $GROOVY_BIN"
        exit 1
    fi
    info_log "Groovy command path: $GROOVY_BIN (found at GROOVY_HOME)"
elif which groovy >/dev/null 2>&1; then
    info_log "Groovy home directory: (none)"
    GROOVY_BIN=`which groovy`
    info_log "Groovy command path: $GROOVY_BIN (found at PATH)"
else
    error_log "ERROR: Not found a groovy command. Required either PATH having groovy command or GROOVY_HOME"
    exit 1
fi

#-------------------------------------------
# Resolve GROOVYSERV_HOME
#-------------------------------------------

if [ "$GROOVYSERV_HOME" = "" ]; then
    GROOVYSERV_HOME="$(dirname $(dirname $(expand_path $0)))"

    # for Homebrew in Mac OS X
    if [ -d $GROOVYSERV_HOME/libexec ]; then
        GROOVYSERV_HOME="$GROOVYSERV_HOME/libexec"
    fi
else
    GROOVYSERV_HOME=`expand_path "$GROOVYSERV_HOME"`
fi
ls $GROOVYSERV_HOME/lib/groovyserv-*.jar >/dev/null 2>&1
if [ ! $? -eq 0 ]; then
    error_log "ERROR: Not found a valid GROOVYSERV_HOME directory: $GROOVYSERV_HOME"
    exit 1
fi
info_log "GroovyServ home directory: $GROOVYSERV_HOME"

#-------------------------------------------
# Find groovyclient command
#-------------------------------------------

GROOVYCLIENT_BIN="$GROOVYSERV_HOME/bin/groovyclient"
if [ ! -x "$GROOVYCLIENT_BIN" ]; then
    error_log "ERROR: Not found a groovyclient command in GROOVYSERV_HOME: $GROOVYCLIENT_BIN"
    exit 1
fi

# ------------------------------------------
# GroovyServ's work directory
# ------------------------------------------

GROOVYSERV_WORK_DIR="$HOME/.groovy/groovyserv"
if [ ! -d "$GROOVYSERV_WORK_DIR" ]; then
    mkdir -p "$GROOVYSERV_WORK_DIR"
fi
info_log "GroovyServ work directory: $GROOVYSERV_WORK_DIR"

#-------------------------------------------
# Port and PID and Cookie
#-------------------------------------------

PORT=${GROOVYSERVER_PORT:-1961}
GROOVYSERV_OPTS="$GROOVYSERV_OPTS -Dgroovyserver.port=$PORT"
GROOVYSERV_PID_FILE="$GROOVYSERV_WORK_DIR/pid-$PORT"
GROOVYSERV_COOKIE_FILE="$GROOVYSERV_WORK_DIR/cookie-$PORT"
IS_SERVER_AVAILABLE="env GROOVYSERVER_PORT=$PORT $GROOVYCLIENT_BIN -Cwithout-invoking-server -e \"\""
EXPIRED_PID_FILE="( cd \"$GROOVYSERV_WORK_DIR\" && find . -name pid-$PORT -mmin +1 )"

#-------------------------------------------
# Setup classpath
#-------------------------------------------

info_log "Original classpath: ${CLASSPATH:-(none)}"
if [ "$CLASSPATH" = "" ]; then
    export CLASSPATH="$GROOVYSERV_HOME/lib/*"
else
    export CLASSPATH="${GROOVYSERV_HOME}/lib/*:${CLASSPATH}"
fi
info_log "GroovyServ default classpath: $CLASSPATH"

#-------------------------------------------
# Setup other variables
#-------------------------------------------

# -server option for JVM (for performance) (experimental)
export JAVA_OPTS="$JAVA_OPTS -server"

#-------------------------------------------
# Kill process if specified
#-------------------------------------------

if [ "$DO_KILL" != "" ]; then
    if [ -f "$GROOVYSERV_PID_FILE" ]; then
        EXISTED_PID=`cat "$GROOVYSERV_PID_FILE"`
        ps -p $EXISTED_PID >/dev/null 2>&1
        if [ $? -eq 0 ]; then
            kill -9 $EXISTED_PID
            info_log "Killed groovyserver of $EXISTED_PID($PORT)"
        else
            info_log "Process of groovyserver of $EXISTED_PID($PORT) not found"
        fi
        rm -f "$GROOVYSERV_PID_FILE"
        rm -f "$GROOVYSERV_COOKIE_FILE"
    else
        info_log "PID file $GROOVYSERV_PID_FILE not found"
    fi
    if [ "$DO_KILL" = "KILL_ONLY" ]; then
        exit 0
    fi
    info_log "Restarting groovyserver"
fi

#-------------------------------------------
# Check duplicated invoking
#-------------------------------------------

if [ -f "$GROOVYSERV_PID_FILE" ]; then
    EXISTED_PID=`cat "$GROOVYSERV_PID_FILE"`

    # if connecting to server is succeed, return with warning message
    $IS_SERVER_AVAILABLE > /dev/null 2>&1
    if [ $? -eq 0 ]; then
        error_log "WARN: groovyserver is already running as $EXISTED_PID($PORT)"
        exit 1
    fi

    # if PID file doesn't expired, terminate the sequence of invoking server
    if [ "`sh -c \"$EXPIRED_PID_FILE\"`" = "" ]; then
        error_log "WARN: Another process may be starting groovyserver."
        exit 1
    fi
fi

#-------------------------------------------
# Invoke server
#-------------------------------------------

if [ "$DEBUG" != "" ]; then
    echo "Invoking server for DEBUG..."
    echo "$GROOVY_BIN" $GROOVYSERV_OPTS -e "org.jggug.kobo.groovyserv.GroovyServer.main(args)"
    "$GROOVY_BIN" $GROOVYSERV_OPTS -e "org.jggug.kobo.groovyserv.GroovyServer.main(args)"
    exit 0
else
    nohup "$GROOVY_BIN" $GROOVYSERV_OPTS -e "org.jggug.kobo.groovyserv.GroovyServer.main(args)" > /dev/null 2>&1 &
fi

#-------------------------------------------
# Store PID
#-------------------------------------------

sleep 1
PID=$!
ps -p $PID | grep $PID > /dev/null
if [ $? -eq 0 ]; then
    echo $PID > "$GROOVYSERV_PID_FILE"
else
    error_log "ERROR: Failed to store PID into file $GROOVYSERV_PID_FILE"
    error_log "Rerun for debug..."
    "$GROOVY_BIN" $GROOVYSERV_OPTS -e "org.jggug.kobo.groovyserv.GroovyServer.main(args)" &
    exit 1
fi

#-------------------------------------------
# Wait for available
#-------------------------------------------

if [ ! $QUIET ]; then
    /bin/echo -n "Starting" 1>&2
fi

while true; do
    if [ ! $QUIET ]; then
        /bin/echo -n "." 1>&2
    fi
    sleep 1

    # waiting until cookie filed is created
    if [ ! -f "$GROOVYSERV_COOKIE_FILE" ]; then
        continue
    fi

    # if connecting to server is succeed, return successfully
    $IS_SERVER_AVAILABLE > /dev/null 2>&1
    if [ $? -eq 0 ]; then
        break
    fi

    # if PID file was expired while to connect to server is failing, error
    if [ "`sh -c \"$EXPIRED_PID_FILE\"`" != "" ]; then
        error_log "ERROR: Timeout. Confirm if groovyserver $PID($PORT) is running."
        exit 1
    fi
done

info_log
info_log "groovyserver $PID($PORT) is successfully started"

