#!/bin/bash

## This script shall be used to enable and disable services for systemd. It is executed from its own systemd-service in
## the embedded OS (defined in yocto / meta-evtec).
## All service ("units") files on which the installed package ("ECP") is depending on are enabled/disabled in here
## on basis of the config and the hereby executed algorithm.

# services in this list should be known to the embedded os! for readability insert here file-name (w/o ".service" tail)
# in alphabetical-order
# todo: to include (1024x768Display)
allECPServices="DCMSControl AndchargeDisplay CMDisplay ECP MobileBroadband GPS HmiControl MeterControl MSIControl PowerSinkControl
                StorageControl VehicleControl PPTP LAN WatchdogServer ModemManager TimeSync"

# unit file names of services assigned here are always enabled & started
enableServicesMain=""
enableServicesDisplay=""
enableServicesInterface="LAN TimeSync"

# check which of all listed services are enabled and the corresponding unit files available
for service in $allECPServices; do
  if sudo systemctl is-enabled "$service" --quiet &>/dev/null 2>&1; then
    isEnabledServices+="$service "
  else
    sudo systemctl status "$service" &>/dev/null 2>&1
    if [[ $? == 4 ]]; then  # unit file not known
      echo "!! unit file for $service unknown to systemd, check listed services or add unit file to platform !!"
      exit 1
    else
      isDisabledServices+="$service "
    fi
  fi
done

# todo: delete echos for productive environment
echo "ENABLED ON START: $isEnabledServices"
echo "DISABLED ON START: $isDisabledServices"

# configuration json-key paths (format".key1.key2") to get values from
JSON_KEY_ROLE='.Device.Role'
JSON_KEY_TYPE='.Device.Type'
JSON_KEY_METER='.Device.MeterControl'
JSON_KEY_DCMS='.Device.BaristaMaster'
JSON_KEY_VIEW='.UserInterface.DeviceView'
JSON_KEY_VPN='.Interfaces.VPN.Enable'
JSON_KEY_MOBILE='.Interfaces.MobileBroadband.Enable'
JSON_KEY_GPS='.Device.Location.EnableGPS'

CONFIG_PATH=$ECP_WORK_FILES_DIR/config/config.json
# read out configuration (with trimmed "")
role=$(jq $JSON_KEY_ROLE $CONFIG_PATH | tr -d \")
deviceType=$(jq $JSON_KEY_TYPE $CONFIG_PATH | tr -d \")
deviceView=$(jq $JSON_KEY_VIEW $CONFIG_PATH | tr -d \")
meterControl=$(jq $JSON_KEY_METER $CONFIG_PATH | tr -d \")
dcmsControl=$(jq $JSON_KEY_DCMS $CONFIG_PATH | tr -d \")
vpn=$(jq $JSON_KEY_VPN $CONFIG_PATH | tr -d \")
mobileBroadband=$(jq $JSON_KEY_MOBILE $CONFIG_PATH | tr -d \")
gps=$(jq $JSON_KEY_GPS $CONFIG_PATH | tr -d \")

################# Choose "Role-service" and "Display-service" to run" #################
case "$role" in
  'ControllerRemoteDisplay'|'ControllerLocalHMI')
    enableServicesMain+="ECP "
    enableServicesDisplay=""
    if [[ "$role" == 'ControllerLocalHMI' ]]; then
      enableServicesDisplay="AndchargeDisplay "
    fi
    ;;
  'VehicleControl')
    enableServicesMain+="VehicleControl "
    enableServicesDisplay=""
    ;;
  'StorageControl')
    enableServicesMain+="StorageControl "
    enableServicesDisplay=""
    ;;
  'PowerSinkControl')
    enableServicesMain+="PowerSinkControl "
    enableServicesDisplay=""
    ;;
  'MSIControl')
    enableServicesMain+="MSIControl "
    enableServicesDisplay=""
    ;;
  'ContainerControl')
    enableServicesMain+="ContainerControl "
    enableServicesDisplay=""
    ;;
  'RemoteHMI1'|'RemoteHMI2')
    enableServicesMain+="HmiControl"
    if [[ "$deviceType" == 'CM' ]] || [[ "$deviceType" == 'PRE300' ]] || [[ "$deviceType" == 'PRE360AIO' ]]; then
      enableServicesDisplay="CMDisplay "
    elif [[ "$deviceView" == 'ufc300' ]]; then
      enableServicesDisplay="1024x768Display "
    else
      enableServicesDisplay="AndchargeDisplay "
    fi
    ;;
  'RemoteDisplay1')
    enableServicesMain+="WatchdogServer "
    if [[ "$deviceType" == 'CM' ]] || [[ "$deviceType" == 'PRE300' ]] || [[ "$deviceType" == 'PRE360AIO' ]]; then
      enableServicesDisplay="CMDisplay "
    elif [[ "$deviceView" == 'ufc300' ]]; then
      enableServicesDisplay="1024x768Display "
    else
      enableServicesDisplay="AndchargeDisplay "
    fi
    ;;
  *)
    echo "Role \"$role\" DOES NOT EXIST => !! CHECK CONFIG INTEGRITY !!"
esac

# Choose additional energy management service(s)
if [[ $meterControl == 'true' ]]; then
  enableServicesMain+="MeterControl "
fi

if [[ $dcmsControl == 'MasterLocal' ]] || [[ $dcmsControl == 'Master3' ]] || [[ $dcmsControl == 'Master10' ]] || [[ $dcmsControl == 'MasterFull' ]]; then
  enableServicesMain+="DCMSControl "
elif [[ $dcmsControl != "MasterDisabled" ]]; then
  echo "check $JSON_KEY_DCMS in config: \"$dcmsControl\""
fi

################# Choose "Interface-service" to run" #################
if [[ "$vpn" == 'true' ]]; then
  enableServicesInterface+="PPTP "
fi

if [[ "$mobileBroadband" == 'true' ]]; then
  enableServicesInterface+="MobileBroadband "
  enableServicesInterface+="ModemManager "
elif [[ "$gps" == 'true' ]]; then
  enableServicesInterface+="GPS "
else
  # power down modem since it is not used
  echo 0 > /sys/class/gpio/gpio139/value
fi


allEnablingServices="$enableServicesInterface $enableServicesMain $enableServicesDisplay"
toDisable=()
toEnable=()
 # every known service is checked if it should be en- or disabled
# todo delete unnecessary (if any) echos before going live
for service in $allECPServices; do
  info=""
  if [[ "$allEnablingServices" != *"$service"* ]]; then
    info="DISABLE: $service -> "
    if [[ "$isDisabledServices" != *"$service"* ]]; then
      info+="SET UP TO (disable+stop) "
      echo "$info"
      toDisable=("$service" "${toDisable[@]}")
      continue
    else
      info+="IS NOW, DO NOTHING"
      echo "$info"
      continue
    fi
  else
    info="ENABLE : $service -> "
    if [[ "$isEnabledServices" != *"$service"* ]]; then
      info+="SET UP TO (enable+start)"
      echo "$info"
      toEnable=("$service" "${toEnable[@]}")
      continue
    else
      info+="IS NOW, DO NOTHING"
      echo "$info"
      continue
    fi
  fi
  echo "!! STATUS OF SERVICE: ($service) UNKNOWN; THIS SHOULD DEFINITELY NOT HAPPEN !!"
done

# here disabling and enabling is actually executed (to minimize the "remount" calls)
if [[ ${#toEnable[*]} -gt 0 ]] || [[ ${#toDisable[*]} -gt 0 ]]; then
  sudo mount -o remount,rw /
  for disable in "${toDisable[@]}"; do
    sudo systemctl disable "$disable" --now
    if [[ ! $? ]]; then
      echo "FAILED to disable $disable, exit and let service restart"
      exit 1
    fi
  done

  for enable in "${toEnable[@]}"; do
    sudo systemctl enable "$enable" --now
    if [[ ! $? ]]; then
      echo "FAILED to enable $enable, exit and let service restart"
      exit 1
    fi
  done
  # as the remount,ro sometimes results in a "mount: /: mount point is busy." which can lead to a "rw" mounted root
  # during run time of main application.
  # So a first quick proposal was to "free" the device from write access with "sync" which forces any buffer to be flushed.
  # But as long as you can read this comment the "sync" solution is not proven to prevent the described issue.
  # todo: verify sync solution or find better one (e.g just reboot after changes)
  sync
  sudo mount -o remount,ro /
else
  echo "$0: NO CHANGES necessary in services"
fi

exit 0