#!/bin/bash
unset POSIXLY_CORRECT

# Function to retrieve a service by its name (without .service suffix) or full name (with .service suffix).
# Parameters:
#     -ServiceName (string): The name or full name of the service to retrieve.
# Returns:
# - echo the service short name if the service exists; "" otherwise
# - 0 (true) if the command succeeded, 1 (false) otherwise
function Retrieve_Service {
   local ServiceName=""
   local serviceShortName=""

    # Parse arguments
    local usage="Usage: Retrieve_Service -ServiceName <name>"
    while [ "$1" != "" ]; do
        case $1 in
            --ServiceName | -ServiceName)
                ServiceName="$2"
                shift 2
                ;;
            *)
                echo "$usage" >&2
                exit 1
                ;;
        esac
    done
    if [ -z "$ServiceName" ]; then
        echo "$usage" >&2
        exit 1
    fi

    if [[ "$ServiceName" == *.service ]]; then
        serviceShortName="${ServiceName%.service}"
    else
        serviceShortName="$ServiceName"
    fi    
 
    # Check if the service exists by using systemctl
    systemctl list-unit-files --type=service | grep -Eq "\b$serviceShortName\b.service"
    if [ $? -eq 0 ]; then
        echo "$serviceShortName"  # Service exists
        return 0
    else
        echo ""  # Service does not exist
        return 1
    fi    
}

# Function to check if a service exists
# Parameters:
# - ServiceName: The name of the service to check (with or without .service suffix)
# Returns:
# - echo the full service name (with .service suffix) if the service exists, "" otherwise
# - 0 (true) if the command succeeded, 1 (false) otherwise
function Test_Service_Exist {
    local ServiceName=""
    local serviceShortName=""

    # Parse arguments
    local usage="Usage: Test_Service_Exist -ServiceName <name>"
    while [ "$1" != "" ]; do
        case $1 in
            --ServiceName | -ServiceName)
                ServiceName="$2"
                shift 2
                ;;
            *)
                echo "$usage" >&2
                exit 1
                ;;
        esac
    done
    if [ -z "$ServiceName" ]; then
        echo "$usage" >&2
        exit 1
    fi

    serviceShortName=$(Retrieve_Service -ServiceName "$ServiceName")
    if [ -z "$serviceShortName" ] ; then
        echo ""
        return 1
    else 
        echo "$serviceShortName.service"
        return 0
    fi
}

# Function to set the service startup type
# Parameters:
# - ServiceName: The name of the service to set (with or without .service suffix)
# - StartupType: The startup type
# Returns:
# - 0 (true) if the command succeeded, 1 (false) otherwise
function Set_Service_Startup {
    local ServiceName=""
    local StartupType=""
    local serviceShortName=""

    # Parse arguments
    local usage="Usage: Set_Service_Startup -ServiceName <name> -StartupType <disable|enable>"
    while [ "$1" != "" ]; do
        case $1 in
            --ServiceName | -ServiceName)
                ServiceName="$2"
                shift 2
                ;;
            --StartupType | -StartupType)
                StartupType="$2"
                shift 2
                ;;                          
            *)
                echo "$usage" >&2
                exit 1
                ;;
        esac
    done
    if [ -z "$ServiceName" ] || [ -z "$StartupType" ]; then
        echo "$usage" >&2
        exit 1
    fi
    if [ "$StartupType" != "disable" ] && [ "$StartupType" != "enable" ] ; then
        echo "$usage" >&2
        exit 1
    fi

    serviceShortName=$(Retrieve_Service -ServiceName "$ServiceName")
    if [ -z "$serviceShortName" ] ; then
        return 1
    fi
    systemctl "$StartupType" "$serviceShortName"
    return $?
}

# Function to start or stop a service
# Parameters:
# - ServiceName: The name of the service to manage (with or without .service suffix)
# - Action: The action to perform ('start' or 'stop')
# Returns:
# - 0 (true) if the command succeeded, 1 (false) otherwise
Manage_Service() {
    local ServiceName=""
    local Action=""
    local serviceShortName=""

    # Parse arguments
    local usage="Usage: Manage_Service -ServiceName <name> -Action <start|stop>"
    while [ "$1" != "" ]; do
        case $1 in
            --ServiceName | -ServiceName)
                ServiceName="$2"
                shift 2
                ;;
            --Action | -Action)
                Action="$2"
                shift 2
                ;;                
            *)
                echo "$usage" >&2
                exit 1
                ;;
        esac
    done
    if [ -z "$ServiceName" ] || [ -z "$Action" ]; then
        echo "$usage" >&2
        exit 1
    fi
    if [ "$Action" != "start" ] && [ "$Action" != "stop" ] ; then
        echo "$usage" >&2
        exit 1
    fi

    serviceShortName=$(Retrieve_Service -ServiceName "$ServiceName")
    if [ -n "$serviceShortName" ]; then
        echo "> $Action '$serviceShortName.service'"
        # Get the current status of the service
        local serviceStatus=$(systemctl is-active "$serviceShortName")
        case "$Action" in
            "start")
                if [ "$serviceStatus" != "active" ]; then
                    systemctl start "$serviceShortName"
                    if [ $? -eq 0 ]; then
                        echo "  $serviceShortName start succeeded"
                        return 0  # Success
                    else
                        echo "  $serviceShortName start failed."
                        return 1  # Failure
                    fi
                else
                    echo "  $serviceShortName is already running"
                    return 0  # Already running
                fi
                ;;
            "stop")
                if [ "$serviceStatus" != "inactive" ]; then
                    systemctl stop "$serviceShortName"
                    if [ $? -eq 0 ]; then
                        echo "  $serviceShortName stop succeeded"
                        return 0  # Success
                    else
                        echo "  $serviceShortName stop failed."
                        return 1  # Failure
                    fi
                else
                    echo "  $serviceShortName is already stopped"
                    return 0  # Already stopped
                fi
                ;;
        esac
    else
        echo "> $Action $ServiceName"
        echo "  $ServiceName does not exist"
        return 1  # Service does not exist
    fi
}

# Function to check the service status
# Parameters:
# - ServiceName: The service name of the service to check (with or without .service suffix)
# - Status: The status to check (active, inactive, etc.)
# - Timeout: The maximum time to wait for the service to reach the desired status (in seconds)
# Returns:
# - The status of the service if found (active, inactive, failed, activating, deactivating,reloading)
#   or "" if the service does not exist
Check_Service() {
    local ServiceName=""
    local Status=""
    local Timeout=0 # Default timeout of 0 seconds
    local serviceShortName=""

    # Parse arguments
    local usage="Usage: Check_Service -ServiceName <name> -Status <active|inactive|activating|deactivating> [-Timeout <value in seconds>]"
    while [ "$1" != "" ]; do
        case $1 in
            --ServiceName | -ServiceName)
                ServiceName="$2"
                shift 2
                ;;
            --Status | -Status)
                Status="$2"
                shift 2
                ;;   
            --Timeout | -Timeout)
                Timeout=$2
                shift 2
                ;;                                
            *)
                echo "$usage" >&2
                exit 1
                ;;
        esac
    done 

    if [ -z "$ServiceName" ] || [ -z "$Status" ]; then
        echo "$usage" >&2
        exit 1
    fi
    if [ "$Status" != "active" ] && [ "$Status" != "inactive" ] && [ "$Status" != "activating" ] && [ "$Status" != "deactivating" ]; then
        echo "$usage" >&2
        exit 1
    fi
    if [[ ! "$Timeout" =~ ^[0-9]+$ ]]; then
        echo "$usage" >&2
        exit 1
    fi

    serviceShortName=$(Retrieve_Service -ServiceName "$ServiceName")
    if [ -n "$serviceShortName" ]; then
        local elapsed_time=0
        local interval=1  # Check every second
        echo "> check '$serviceShortName.service'"  >&2
        while [ $elapsed_time -lt $Timeout ] || { [ $Timeout -eq 0 ] && [ $elapsed_time -eq 0 ]; }; do
            local serviceStatus=$(systemctl is-active "$serviceShortName")
            echo "  $serviceShortName status is $serviceStatus" >&2
            if [ "$serviceStatus" == "$Status" ]; then
                echo "$serviceStatus"
                return
            else
                case $Status in
                    "active")
                        if [ "$serviceStatus" != "activating" ]; then
                            echo "$serviceStatus"
                            return
                        fi
                        ;;
                    "inactive")
                        if [ "$serviceStatus" != "deactivating" ]; then
                            echo "$serviceStatus"
                            return
                        fi
                        ;;
                esac
            fi
            sleep $interval
            elapsed_time=$((elapsed_time + interval))
        done

        if [ $Timeout -ne 0 ]; then
            echo "  check timeout reached: $serviceShortName status is $serviceStatus" >&2
        fi
        echo "$serviceStatus"
    else
        echo "> check $ServiceName" >&2
        echo "  $ServiceName does not exist" >&2
        echo ""
    fi
}

# Function to stop the SafeKit module and exit with an error code.
# Called by module scripts (prestart, start_prim, stop_prim, start_both, stop_both, ...) on fatal error
# Parameters:
#   - ScriptName: The name of the script that requires the stop (mandatory).
Stop_Module_And_Exit() {
    local ScriptName=""

    # Parse arguments
    local usage="Usage: Stop_Module_And_Exit -ScriptName <name>"
    while [ "$1" != "" ]; do
        case $1 in
            --ScriptName | -ScriptName)
                ScriptName="$2"
                shift 2
                ;;
            *)
                echo "$usage" >&2
                exit 1
                ;;
        esac
    done
    if [ -z "$ScriptName" ]; then
        echo "$usage" >&2
        exit 1
    fi

    echo "  Stopping the module $SAFEMODULE"
    "$SAFE/safekit" stop -i "$ScriptName"
    exit 1
}

# Function that returns the list of service names from 
# (1) script argument -Services (can be a list of services with , as separator)
# (2) the SERVICES environment variable
# (3) the SERVICES user var defined into safeconf.xml
# Parameters: 
#   - ScriptArgs: script arguments that optionally contains -Services value
#   - ReverseOrder: reverse list order if true; default is false
# Returns: 
#   - list of service names or "" if no services are defined.
Get_ServicesArray() {
    local ScriptArgs=""
    local ReverseOrder=false
    local ServicesList=""
    local servicesArray=()

    # Parse arguments
    local usage="Usage: Get_ServicesArray -ScriptArgs <arguments> [-ReverseOrder true|false]"
    while [ $# -ne 0 ] ; do
        case "$1" in
            -ScriptArgs | --ScriptArgs) 
                ScriptArgs=$2 
                shift; shift
                ;;
            -ReverseOrder | --ReverseOrder) 
                if [ "$2" == "true" ] ; then
                    ReverseOrder=true
                fi
                if [ "$2" == "false" ] ; then
                    ReverseOrder=false
                fi     
                shift; shift               
                ;;
            *) 
                echo "$usage" >&2
                exit 1
        esac
    done 
    if [ $ReverseOrder != "true" ] && [ $ReverseOrder != "false" ] ; then
        echo "$usage" >&2
        exit 1
    fi

   # (1) Loop through the arguments to find -Services
   local values=""
   if [[ "$ScriptArgs" == *"-Services "* ]]; then
        # Extract the part after '-Services '
        values="${ScriptArgs#*-Services }"
    fi
    # Trim leading and trailing spaces from the extracted values
    ServicesList=$(echo "$values" | sed 's/^ *//;s/ *$//')
    if [[ -z "$ServicesList" ]]; then
        # (2) the SERVICES environment variable
        ServicesList="${SERVICES}"
        if [[ -z "$ServicesList" ]]; then
            # (3) the SERVICES user var defined into safeconf.xml
            local moduleConfig="$SAFEUSERCONF/safeconf.xml"
            ServicesList=$("$SAFEBIN/xpathGet" "//user/var[@name='SERVICES']/@value" "$moduleConfig")
            if [[ -n "$ServicesList" ]]; then
	            echo "   $ServicesList from SERVICES in safeconf.xml" >&2
            fi
        else
            echo "   $ServicesList from SERVICES environment variable" >&2
        fi
    else
        ServicesList="${values}"
        echo "   $ServicesList from -Services argument in $ScriptArgs" >&2
    fi
  
    if [[ -z "$ServicesList" ]]; then
        echo ""
        echo "   Warning: SERVICES not found" >&2
        return 1
    else
        #echo "ServicesList=$ServicesList" >&2
        # Split the list by commas, trim spaces and filter empty items
        IFS=',' read -r -a servicesArray <<< "$ServicesList"
        tempArray=()
        for i in "${!servicesArray[@]}"; do
            trimmed=$(echo "${servicesArray[$i]}" | xargs)  # trim spaces
            if [[ -n "$trimmed" ]]; then
                tempArray+=("$trimmed")
            fi
        done
        servicesArray=("${tempArray[@]}")
        # Reverse the array if ReverseOrder is true
        if [ "$ReverseOrder" = true ]; then
            for (( i=${#servicesArray[@]}-1; i>=0; i-- )); do
                reversedArray+=("${servicesArray[i]}")
            done
            IFS=',' 
            echo "${reversedArray[*]}"
        else
            IFS=',' 
            echo "${servicesArray[*]}"
        fi
    fi
    return 0
}
