#!/bin/sh

CHKCONFIG=chkconfig
SERVICE=service
SD_BOOTED=sd_booted
SYSTEMCTL=systemctl
INITDIR="${INITDIR:-/etc/init.d}"
UNITDIR="${UNITDIR:-/lib/systemd/system}"

# SysVinit functions

sysv_service_exists() {
	[ -f "${INITDIR%/}/$1" ]
}

sysv_service_control()
{
    local srv="$1"; shift
    local cmd="$1"; shift
    local out='2>/dev/null'

    [ -z "${ALTERATOR_DEBUG:-}" ] || out=

    case "$cmd" in
        on|enable)
            eval "$CHKCONFIG --add \"$srv\" $out 1>&2" </dev/null
            eval "$CHKCONFIG \"$srv\" on $out 1>&2" </dev/null
            ;;
        off|disable)
            eval "$CHKCONFIG \"$srv\" off $out 1>&2" </dev/null
            ;;
        is-enabled)
	    local runlevel="$(/sbin/runlevel | cut -c3)"
	    # Check runlevel
	    case "$runlevel" in
		[1-6])
		    ;;
		*)
		    # Use inittab if runlevel is unknown
		    runlevel="$(sed -nr '/:initdefault:$/ {s,^id:([^:]+):.*,\1,;p}' /etc/inittab)"
		    ;;
	    esac
	    eval "$CHKCONFIG --level \"$runlevel\" \"$srv\" $out 1>&2" </dev/null
            ;;
        is-active|status)
            eval "$SERVICE \"$srv\" status $out 1>&2" </dev/null
	    ;;
        *)
            eval "$SERVICE \"$srv\" \"$cmd\" $out 1>&2" </dev/null
            ;;
    esac
}

# Systemd functions

sd_service_exists() {
	[ -f "${UNITDIR%/}/$1" ]
}

sd_service_name()
{
    local name="$1"; shift

    if [ "${name%.service}" = "$name" -a "${name%.socket}" = "$name" ]; then
        if sd_service_exists "$name.service"; then
            name="$name.service"
        elif sd_service_exists "$name.socket"; then
            name="$name.socket"
        fi
    fi

    echo "$name"
}

sd_service_control()
{
    local srv="$(sd_service_name "$1")"; shift
    local cmd="$1"; shift
    local out='2>/dev/null'

    [ -z "${ALTERATOR_DEBUG:-}" ] || out=

    case "$cmd" in
        on|enable)
            eval "$SYSTEMCTL enable \"$srv\" $out 1>&2" </dev/null
            ;;
        off|disable)
            eval "$SYSTEMCTL disable \"$srv\" $out 1>&2" </dev/null
            ;;
        is-active|status)
            eval "$SYSTEMCTL is-active \"$srv\" $out 1>&2" </dev/null
	    ;;
        condrestart)
            eval "$SYSTEMCTL try-restart \"$srv\" $out 1>&2" </dev/null
	    ;;
        condreload)
            ! $SYSTEMCTL --quiet is-active "$srv" ||
            eval "$SYSTEMCTL reload-or-try-restart \"$srv\" $out 1>&2" </dev/null
	    ;;
        condstop)
	    ! $SYSTEMCTL --quiet is-active "$srv" ||
	    eval "$SYSTEMCTL stop \"$srv\" $out 1>&2" </dev/null
	    ;;
        *)
            eval "$SYSTEMCTL \"$cmd\" \"$srv\" $out 1>&2" </dev/null
            ;;
    esac
}

####

# Checks if a service is present in the system
# args: service
service_exists() {
    $SD_BOOTED &&
        sd_service_exists "$(sd_service_name "$1")" ||
        sysv_service_exists "$1"
}

# Manages the service status (elementary status options).
# args: service command
_service_control()
{
    $SD_BOOTED &&
        sd_service_control "$(sd_service_name "$1")" "$2" ||
        sysv_service_control "$1" "$2"
}

# Manages the service status (complex and elementary status options).
# args: service command
service_control()
{
    case "$2" in
	    charge|energize|energise|on/start|enable-start)
		    _service_control "$1" enable && _service_control "$1" start
		    ;;
	    discharge|gronk|stop/off|stop-disable|disable-stop)
		    _service_control "$1" stop && _service_control "$1" disable
		    ;;
	    *)
		    _service_control "$1" "$2"
		    ;;
    esac
}

# Checks if a service is in transition.
# args: service
service_test_locked()
{
    $SD_BOOTED && return 1
    sysv_service_exists "$1" || return 1
    sysv_service_control "$1" status
    [ $? -eq 2 ] && return 0 || return 1
}

# Waits for the service to change status
# args: service [ timeout ]
service_wait()
{
    local retries="${2:-5}"

    $SD_BOOTED && return 0
    sysv_service_exists "$1" || return 0
    x=0;
    while [ $x -lt "$retries" ] && service_test_locked "$1"; do
        x=$(( x + 1 ))
        sleep 1
    done
}

# Start or restart a service with timeout
# args: service command [ timeout ]
service_start_wait()
{
    # Allow only start/restart/reload commands
    case "$2" in
        start|restart|reload) ;;
        *) return 1 ;;
    esac
    service_control "$1" "$2" || return
    service_wait "$1" "${3-}"
    service_control "$1" is-active
}
