#!/bin/bash
# /etc/init.d/minecraft

if [ -L $0 ]
then
    source `readlink -e $0 | sed "s:[^/]*$:config:"`
else
    source `echo $0 | sed "s:[^/]*$:config:"`
fi

if [ "$SERVICE" == "" ]
then
    echo "Couldn't load config file, please edit config.example and rename it to config"
    logger -t minecraft-init "Couldn't load config file, please edit config.example and rename it to config"
    exit
fi

ME=`whoami`
as_user() {
    if [ $ME == $USERNAME ] ; then
        bash -c "$1"
    else
        su $USERNAME -s /bin/bash -c "$1"
    fi
}

is_running(){
    # Checks for the minecraft servers screen session
    # returns true if it exists.
    pidfile=${MCPATH}/${SCREEN}.pid

    if [ -r "$pidfile" ]
    then
        pid=$(head -1 $pidfile)
        if ps ax | grep -v grep | grep ${pid} | grep "${SCREEN}" > /dev/null
        then
            return 0
        else 
            if [ -z "$isInStop" ]
            then
                if [ -z "$roguePrinted" ]
                then
                    roguePrinted=1
                    echo "Rogue pidfile found!"
                fi
            fi
            return 1
        fi
    else
        if ps ax | grep -v grep | grep "${SCREEN} ${INVOCATION}" > /dev/null
        then
            echo "No pidfile found, but server's running."
            echo "Re-creating the pidfile."
            
            pid=$(ps ax | grep -v grep | grep "${SCREEN} ${INVOCATION}" | cut -f1 -d' ')
            check_permissions
            as_user "echo $pid > $pidfile"

            return 0
        else
            return 1
        fi
    fi
}

mc_start() {
    pidfile=${MCPATH}/${SCREEN}.pid
    check_permissions

    as_user "cd $MCPATH && screen -dmS $SCREEN $INVOCATION"
    as_user "screen -list | grep '\.$SCREEN' | cut -f1 -d'.' | tr -d -c 0-9 > $pidfile"

    #
    # Waiting for the server to start
    #
    seconds=0
    until is_running 
    do
        sleep 1
        seconds=$seconds+1
        if [[ $seconds -eq 5 ]]
        then
            echo "Still not running, waiting a while longer..."
        fi
        if [[ $seconds -ge 120 ]]
        then
            echo "Failed to start, aborting."
            exit 1
        fi
    done
    echo "$SERVICE is running."
}

mc_command() {
    if is_running
    then
        as_user "screen -p 0 -S $SCREEN -X eval 'stuff \"$(eval echo $FORMAT)\"\015'"
    else
        echo "$SERVICE was not running. Not able to run command."
    fi
}

mc_saveoff() {
    if is_running
    then
        echo "$SERVICE is running... suspending saves"
        mc_command save-off
        mc_command save-all
        sync
        sleep 10
    else
        echo "$SERVICE was not running. Not suspending saves."
    fi
}

mc_saveon() {
    if is_running
    then
        echo "$SERVICE is running... re-enabling saves"
        mc_command save-on
    else
        echo "$SERVICE was not running. Not resuming saves."
    fi
}

mc_say() {
    if is_running
    then
        echo "Said: $1"
        mc_command "say $1"
    else
        echo "$SERVICE was not running. Not able to say anything."
    fi
}

mc_execute_command() {
    if is_running
    then
        echo "Executed $1"
        mc_command "$1"
    else
        echo "$SERVICE was not running. Not able to execute commmand."
    fi
}

mc_stop() {
    pidfile=${MCPATH}/${SCREEN}.pid
    #
    # Stops the server
    #
    echo "Saving worlds..."
    mc_command save-all
    echo "Stopping server..."
    mc_command stop
    sleep 0.5
    #
    # Waiting for the server to shut down
    #
    seconds=0
    isInStop=1
    while is_running
    do
        sleep 1 
        seconds=$seconds+1
        if [[ $seconds -eq 5 ]]
        then
            echo "Still not shut down, waiting a while longer..."
        fi
        if [[ $seconds -ge 120 ]]
        then
            logger -t minecraft-init "Failed to shut down server, aborting."
            echo "Failed to shut down, aborting."
            exit 1
        fi
    done
    as_user "rm $pidfile"
    unset isInStop
    is_running
    echo "$SERVICE is now shut down."
}

whitelist(){
    mc_command "whitelist list"
    sleep 1s
    whitelist=$(tac $MCPATH/server.log | grep -m 1 "White-listed players:")
    
    echo
    echo "Currently there are the following players on your whitelist:"
    echo
    echo ${whitelist:49} | sed 's/, /\n/g'
}

force_exit() {    # Kill the server running (messily) in an emergency
    echo ""
    echo "SIGINIT CALLED - FORCE EXITING!"
    pidfile=${MCPATH}/${SCREEN}.pid
    rm $pidfile
    echo "KILLING SERVER PROCESSES!!!"
        # Display which processes are being killed
        ps aux | grep -e 'SCREEN -dmS '${SCREEN}' java' | grep -v grep | awk '{print $2}' | xargs -i echo "Killing PID: " {}
        
        # Kill the processes
        ps aux | grep -e 'SCREEN -dmS '${SCREEN}' java' | grep -v grep | awk '{print $2}' | xargs -i kill {}
    exit 1
}

get_script_location() {
    echo $(dirname "$(readlink -e "$0")")
}

check_permissions() {
    as_user "touch $pidfile"
    if ! as_user "test -w '$pidfile'" ; then 
        echo "Check Permissions. Cannot write to $pidfile. Correct the permissions and then excute: $0 status"
    fi
}

trap force_exit SIGINT

case "$1" in
    start)
        # Starts the server
        if is_running; then
            echo "Server already running."
        else
            mc_start
        fi
        ;;
    stop)
        # Stops the server
        if is_running; then
            mc_say "SERVER SHUTTING DOWN!"
            mc_stop
        else
            echo "No running server."
        fi
        ;;
    restart)
        # Restarts the server
        if is_running; then
            mc_say "SERVER REBOOT IN 10 SECONDS!"
            sleep 10
            mc_stop
        else
            echo "No running server, starting it..."
        fi
        mc_start
        ;;
    whitelist)
        if is_running; then
            whitelist
        else
            echo "Server not running."
        fi
        ;;
    whitelist-reload)
        # Reloads the whitelist
        if is_running; then
            mc_command "whitelist reload"
        else
            echo "No running server."
        fi
        ;;
    whitelist-add)
        # Adds a player to the whitelist
        if is_running; then
            mc_command "whitelist add $2"
        else
            echo "No running server."
        fi
        ;;
    save-off)
        # Disables automatic saving.
        if is_running; then
            mc_saveoff
        else
            echo "No running server."
        fi
        ;;
    save-on)
        # Re-enables saving if it was disabled by save-off.
        if is_running; then
            mc_saveon
        else
            echo "No running server."
        fi
        ;;
    say)
        
        # Says something to the ingame chat
        if is_running; then
            mc_say "$2"
        else
            echo "No running server to say anything."
        fi
        ;;
    command)
        command=`echo "$@" | sed 's/command //'`
        # Executes a command on server
        if is_running; then
            mc_execute_command "$command"
        else
            echo "No running server to execute."
        fi
        ;;
    connected)
        # Lists connected users
        if is_running; then
            mc_command list
            sleep 3s
            tac $MCPATH/server.log | grep -m 1 "Connected"
        else
            echo "No running server."
        fi
        ;;
    status)
        # Shows server status
        if is_running
        then
            echo "$SERVICE is running."
        else
            echo "$SERVICE is not running."
        fi
        ;;
    version)
        if is_running; then
            mc_command version
            tac $MCPATH/server.log | grep -m 1 "This server is running"
        else
            echo "The server needs to be running to check version."
        fi
        ;;
    screen)
        if is_running; then
            screen -r $SCREEN
        else
        echo "Server is not running. Do you want to start it?"
        echo "Please put \"Yes\", or \"No\": "
        read START_SERVER
        case "$START_SERVER" in
            [Yy]|[Yy][Ee][Ss])
                check_links
                to_ram
                mc_start
                screen -r $SCREEN
                ;;
            [Nn]|[Nn][Oo])
                clear
                echo "Aborting startup!"
                sleep 1
                clear
                exit 1
                ;;
            *)
                clear
                echo "Invalid input"
                sleep 1
                clear
                exit 1
                ;;
        esac
        fi
        ;;
    kill)
        WIDTH=`stty size | cut -d ' ' -f 2`            # Get terminal's character width
        pstree | grep MDSImporte | cut -c 1-${WIDTH}   # Chop output after WIDTH chars
        
        echo "Killing the server is an EMERGENCY procedure, and should not be used to perform a normal shutdown! All changes younger than 15 minutes could be permanantly lost and WORLD CORRUPTION is possible! Are you ABSOLUTELY POSITIVE this is what you want to do?"
        echo "Please put \"Yes\", or \"No\": "
        read KILL_SERVER
        case "$KILL_SERVER" in    # Determine which option was specified
            [Yy]|[Yy][Ee][Ss])    # If yes, kill the server
                echo "KILLING SERVER PROCESSES!!!"
                force_exit
                exit 1
                ;;
            [Nn]|[Nn][Oo])    # If no, abort and exit 1
                echo "Aborting!"
                exit 1
                ;;
            *)    # If anything else, exit 1
                echo "Error: Invalid Input!"
                exit 1
                ;;
        esac
        ;;
    help|--help|-h)
        echo "Usage: $0 COMMAND"
        echo 
        echo "Available commands:"
        echo -e "   start \t\t Starts the server"
        echo -e "   stop \t\t Stops the server"
        echo -e "   restart \t\t Restarts the server"
        echo -e "   save-off \t\t Flushes the world to disk and then disables saving"
        echo -e "   save-on \t\t Re-enables saving if it was previously disabled by save-off"
        echo -e "   say \t\t\t Prints the given string to the ingame chat."
        echo -e "   connected \t\t Lists connected users"
        echo -e "   status \t\t Displays server status"
        echo -e "   whitelist \t\t Prints the current whitelist"
        echo -e "   whitelist-add NAME \t Adds the specified player to the server whitelist"
        echo -e "   whitelist-reload \t Reloads the whitelist"
        ;;
    *)
        echo "No such command, see $0 help"
        exit 1
        ;;
esac

exit 0
