#!/usr/bin/env bash
# Copyright (c) 2020 The Toltec Contributors
# SPDX-License-Identifier: MIT

#
# install-lib
#
# Common functions used by the install scripts
#

# Check whether a systemd unit exists and is in an enabled-like state
# ("enabled", "enabled-runtime", "alias", "static", "indirect", "generated"
# or "transient")
#
# Arguments:
#
# $1 - Name of the systemd unit, e.g. "xochitl.service" or "xochitl"
#
# Exit code:
#
# 0 if the unit exists and is enabled, 1 otherwise
is-enabled() {
    systemctl --quiet is-enabled "$1" 2> /dev/null
}

# Check whether a systemd unit exists and is masked
#
# Arguments:
#
# $1 - Name of the systemd unit, e.g. "xochitl.service" or "xochitl"
#
# Exit code:
#
# 0 if the unit exists and is masked, 1 otherwise
is-masked() {
    [[ "$(systemctl is-enabled "$1" 2> /dev/null)" == "masked" ]]
}

# Check whether a systemd unit is in an active state
# ("running")
#
# Arguments:
#
# $1 - Name of the systemd unit, e.g. "xochitl.service" or "xochitl"
#
# Exit code:
#
# 0 if the unit exists and is enabled, 1 otherwise
is-active() {
    systemctl --quiet is-active "$1" 2> /dev/null
}

# Get a list of systemd units with which the given unit conflicts
#
# Arguments:
#
# $1 - Full name of the systemd unit, e.g. "xochitl.service"
#
# Output:
#
# List of conflicting units
get-conflicts() {
    # Find enabled units that have a conflicting name
    for name in $(systemctl cat "$1" | awk -F'=' '/^Alias=/{print $2}'); do
        local realname
        if realname="$(basename "$(readlink "/etc/systemd/system/$name")")"; then
            echo "$realname"
        fi
    done

    # Find units that are declared as conflicting
    # (systemd automatically adds a conflict with "shutdown.target" to all
    # service units see systemd.service(5), section "Automatic Dependencies")
    systemctl show "$1" | awk -F'=' '/^Conflicts=/{print $2}' \
        | sed 's|\bshutdown.target\b||'
}

# Print instructions about how to enable a given systemd service and disable
# the services that conflict with it
#
# Arguments:
#
# $1 - Full name of the systemd unit, e.g. "draft.service"
#
# Output:
#
# Commands to run to achieve the desired result
how-to-enable() {
    for conflict in $(get-conflicts "$1"); do
        if is-enabled "$conflict"; then
            echo "$ systemctl disable --now ${conflict/.service/}"
        fi
    done

    echo "$ systemctl enable --now ${1/.service/}"
}

# Reload Oxide applications if tarnish is running
#
# Output:
#
# Status message
reload-oxide-apps() {
    if ! is-active tarnish.service; then
        return
    fi
    echo -n "Reloading Oxide applications: "
    local ret
    if type update-desktop-database &> /dev/null; then
        update-desktop-database --quiet
        ret=$?
    else
        /opt/bin/rot apps call reload 2> /dev/null
        ret=$?
    fi
    if [ $ret -eq 0 ]; then
        echo "Done!"
    else
        echo "Failed!"
    fi
}

# Create or update a bind mount systemd unit and enable it
#
# Arguments:
#
# $1 - Source directory
# $2 - Mount point
add-bind-mount() {
    local unit_name
    local unit_path
    unit_name="$(systemd-escape --path "$2").mount"
    unit_path="/lib/systemd/system/$unit_name"

    if [[ -e $unit_path ]]; then
        echo "Bind mount configuration for '$2' already exists, updating"
    else
        echo "Mounting '$1' over '$2'"
    fi

    cat > "$unit_path" << UNIT
[Unit]
Description=Bind mount $1 over $2
DefaultDependencies=no
Conflicts=umount.target
Before=local-fs.target umount.target

[Mount]
What=$1
Where=$2
Type=none
Options=bind

[Install]
WantedBy=local-fs.target
UNIT

    systemctl daemon-reload
    systemctl enable "$unit_name"
    systemctl restart "$unit_name"
}

# Disable and remove a bind mount systemd unit
#
# Arguments:
#
# $1 - Mount point
remove-bind-mount() {
    local unit_name
    local unit_path
    unit_name="$(systemd-escape --path "$1").mount"
    unit_path="/lib/systemd/system/$unit_name"

    if [[ ! -e $unit_path ]]; then
        echo "No existing bind mount for '$1'"
        return 1
    fi

    echo "Removing mount over '$1'"
    systemctl disable "$unit_name"
    systemctl stop "$unit_name"
    rm "$unit_path"
    systemctl daemon-reload
}

# Check to see if a systemd unit exists
#
# Arguments:
#
# $1 - Full name of the systemd unit, e.g. "draft.service"
unit-exists() {
    [ "$(systemctl --quiet list-unit-files "${1}" | /bin/grep -c "${1}" 2> /dev/null)" -eq 1 ]
}

# Stops and disabled a unit
#
# Arguments:
#
# $1 - Full name of the systemd unit, e.g. "draft.service"
disable-unit() {
    if ! unit-exists "${1}"; then
        return
    fi
    if is-active "$1"; then
        echo "Stopping ${1}"
        systemctl stop "${1}"
    fi
    if is-enabled "${1}"; then
        echo "Disabling ${1}"
        systemctl disable "${1}"
    fi
}
