#!/bin/bash

function get_unit_file(){
    
     local UNIT=$1

     for DIR in ${UNIT_PATHS[@]} ; do
         if [ -f "${DIR}${UNIT}" ] ; then
             echo "${DIR}${UNIT}"
             break
         fi
     done

}

function read_option(){
     local OPTION="$1"
     local UNIT_FILE="$2"
     local UNIT_INSTANCE="$3"

     local UNIT=`basename $UNIT_FILE`
     local UNIT_FULL=`echo $UNIT | sed "s/@/@$UNIT_INSTANCE/"`

     VALUE="$(grep '^'$OPTION'[= ]' "$UNIT_FILE" | cut -d '=' -f2- | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')"

     VALUE="`
         echo $VALUE |
         sed -e "s/%[i]/$UNIT_INSTANCE/g" \
             -e "s/%[I]/\"$UNIT_INSTANCE\"/g" \
             -e "s/%[n]/$UNIT_FULL/g" \
             -e "s/%[N]/\"$UNIT_FULL\"/g"
     `"
     # TODO: Add more options from:
     # https://www.freedesktop.org/software/systemd/man/systemd.unit.html#Specifiers

     echo $VALUE
}

function get_unit_wants() {

     local UNIT_FILE=$1
     local UNIT=`basename $UNIT_FILE`

     sort -u <<< `(
         # Print wants from UNIT_PATHS
         for DIR in ${UNIT_PATHS[@]} ; do
             if [ -d "${DIR}${UNIT}.wants" ] ; then
                 ls -1 "${DIR}${UNIT}.wants/" | tr '\n' ' '
             fi
         done
    
         # Print wants from unit-file
         read_option Wants $UNIT_FILE
     )`
}

function action_start(){

    # Find depended services
    local UNIT_FILE=$1
    local UNIT_WANTS=(`get_unit_wants $1`)
    local UNIT_INSTANCE=$2

    # Start depended services
    for UNIT in ${UNIT_WANTS[@]}; do
        exec_action start $UNIT
    done

    # Load options 
    local User=`read_option User $UNIT_FILE $UNIT_INSTANCE`
    local Type=`read_option Type $UNIT_FILE $UNIT_INSTANCE`
    local EnvironmentFile=`read_option EnvironmentFile $UNIT_FILE $UNIT_INSTANCE`
    local ExecStartPre=(`read_option ExecStartPre $UNIT_FILE $UNIT_INSTANCE`)
    local ExecStart=`read_option ExecStart $UNIT_FILE $UNIT_INSTANCE`
    local ExecStartPost=(`read_option ExecStartPost $UNIT_FILE $UNIT_INSTANCE`)
    local Restart=(`read_option Restart $UNIT_FILE $UNIT_INSTANCE`)
    local RestartSec=(`read_option RestartSec $UNIT_FILE $UNIT_INSTANCE`)
	RestartSec=${RestartSec:=5}

    [ -f "$EnvironmentFile" ] && source "$EnvironmentFile"

    # Start service 
    if [ -z $Type ] || [[ "${Type,,}" == *"simple"* ]] ; then
		if [ "$Restart" == "always" ]; then
			COMMAND='nohup bash -c "while true ; do '"$ExecStart"'; sleep $RestartSec; done" &>/dev/null &'
		else
			COMMAND='nohup '"$ExecStart"' >>/dev/null 2>&1 &'
		fi
    elif [[ "${Type,,}" == *"forking"* ]] || [[ "${Type,,}" == *"oneshot"* ]] ; then
        COMMAND="$ExecStart"
    else
        >&2 echo "Unknown service type $Type"
    fi

    #[ -z $User ] || COMMAND="su $User -c \"$COMMAND\""

    while IFS=$'\n' read -a i; do
        eval $i
    done  <<< "${ExecStartPre[@]}"

    eval "$COMMAND"

    while IFS=$'\n' read -a i; do
        eval $i
    done  <<< "${ExecStartPost[@]}"
}

function action_stop(){

    # Find depended services
    local UNIT_FILE=$1
    local UNIT_WANTS=(`get_unit_wants $1`)
    local UNIT_INSTANCE=$2

    # Load options 
    local User=`read_option User $UNIT_FILE $UNIT_INSTANCE`
    local Type=`read_option Type $UNIT_FILE $UNIT_INSTANCE`
    local EnvironmentFile=`read_option EnvironmentFile $UNIT_FILE $UNIT_INSTANCE`
    local ExecStopPre=(`read_option ExecStartPre $UNIT_FILE $UNIT_INSTANCE`)
    local ExecStop=`read_option ExecStop $UNIT_FILE $UNIT_INSTANCE`
    local ExecStopPost=(`read_option ExecStartPost $UNIT_FILE $UNIT_INSTANCE`)
    local ExecStart=`read_option ExecStart $UNIT_FILE $UNIT_INSTANCE`

    [ -f "$EnvironmentFile" ] && source "$EnvironmentFile"

    # Stop service 
    if [ -z $ExecStop ] ; then
        COMMAND="kill -TERM \$(pgrep -f \"$ExecStart\")"
    else
        COMMAND="$ExecStop"
    fi

    #[ -z $User ] || COMMAND="su $User -c \"$COMMAND\""

    while IFS=$'\n' read -a i; do
        eval $i
    done  <<< "${ExecStopPre[@]}"

    eval "$COMMAND"

    while IFS=$'\n' read -a i; do
        eval $i
    done  <<< "${ExecStopPost[@]}"
}

function action_restart(){
    local UNIT_FILE=$1
    local UNIT_INSTANCE=$2

    action_stop $UNIT_FILE $UNIT_INSTANCE
    action_start $UNIT_FILE $UNIT_INSTANCE
}


function action_enable(){

    local UNIT_FILE=$1
    local UNIT=`basename $UNIT_FILE`
    local UNIT_INSTANCE=$2
    local UNIT_FULL=`echo $UNIT | sed "s/@/@$UNIT_INSTANCE/"`

    local WantedBy=`read_option WantedBy $UNIT_FILE`

    if [ -z $WantedBy ] ; then
        >&2 echo "Unit $UNIT have no WantedBy option."
        exit 1
    fi
    
    local WANTEDBY_DIR="/etc/systemd/system/$WantedBy.wants"

    if [ ! -f "$WANTEDBY_DIR/$UNIT_FULL" ] ; then
        mkdir -p $WANTEDBY_DIR
        echo Created symlink from $WANTEDBY_DIR/$UNIT_FULL to $UNIT_FILE.
        ln -s $WANTEDBY_DIR/$UNIT_FULL $UNIT_FILE
    fi
    
}
    
function action_disable(){

    local UNIT_FILE=$1
    local UNIT=`basename $UNIT_FILE`
    local UNIT_INSTANCE=$2
    local UNIT_FULL=`echo $UNIT | sed "s/@/@$UNIT_INSTANCE/"`

    local WantedBy=`read_option WantedBy $UNIT_FILE`

    if [ -z $WantedBy ] ; then
        >&2 echo "Unit $UNIT have no WantedBy option."
        exit 1
    fi

    local WANTEDBY_DIR="/etc/systemd/system/$WantedBy.wants"

    if [ -f "$WANTEDBY_DIR/$UNIT_FULL" ] ; then
        echo Removed $WANTEDBY_DIR/$UNIT_FULL.
        rm -f $WANTEDBY_DIR/$UNIT_FULL.
        rmdir --ignore-fail-on-non-empty $WANTEDBY_DIR
    fi
    
}

function action_status(){

    # Find depended services
    local UNIT_FILE=$1
    local UNIT_WANTS=(`get_unit_wants $1`)
    local UNIT_INSTANCE=$2

    local ExecStart=`read_option ExecStart $UNIT_FILE $UNIT_INSTANCE`


    COMMAND="pgrep -f \"$ExecStart\" &>/dev/null"


    if eval "$COMMAND"; then
     exit 0
    fi

    >&2 echo "Loaded: not-found"
    exit 1
}

function action_is_enabled(){
	exit 0
}

function action_is_active(){
	local UNIT=`basename $1`
	if systemctl status $UNIT ; then
		>&2 echo "active"
		exit 0
	fi

	exit 1

}

function exec_action(){

    local ACTION=$1
    local UNIT=$2
    
    [[ $UNIT =~ '.' ]] || UNIT="$UNIT.service"

    if [[ $UNIT =~ '@' ]] ; then
        local UNIT_INSTANCE=`echo $UNIT | cut -d'@' -f2- | cut -d. -f1`
        local UNIT=`echo $UNIT | sed "s/$UNIT_INSTANCE//"`
    fi

    UNIT_FILE=`get_unit_file $UNIT`

    if [ -z $UNIT_FILE ] ; then
        >&2 echo "Failed to $ACTION $UNIT: Unit $UNIT not found."
        exit 1
    else
        case "$ACTION" in
            start )      action_start $UNIT_FILE $UNIT_INSTANCE ;;
            stop )       action_stop $UNIT_FILE $UNIT_INSTANCE ;;
            restart )    action_restart $UNIT_FILE $UNIT_INSTANCE ;;
            enable )     action_enable $UNIT_FILE $UNIT_INSTANCE ;;
            disable )    action_disable $UNIT_FILE $UNIT_INSTANCE ;;
            status )     action_status $UNIT_FILE $UNIT_INSTANCE ;;
            is-enabled ) action_is_enabled $UNIT_FILE $UNIT_INSTANCE ;;
            is-active )  action_is_active $UNIT_FILE $UNIT_INSTANCE ;;
            * ) >&2 echo "Unknown operation $ACTION." ; exit 1 ;;
        esac
    fi
}

ACTION="$1"
UNITS="${@:2}"
UNIT_PATHS=(
    /etc/systemd/system/
    /usr/lib/systemd/system/
)


for UNIT in ${UNITS[@]}; do
    exec_action $ACTION $UNIT
done
