#!/bin/bash

export NETCONF_HOST=192.168.71.128
# export NETCONF_HOST=localhost



# A helper function to wait for a PID to exit
# The function waits for either the PID to exit or the timeout to expire
# The function returns 0 if the PID exited, 1 if the timeout expired and the PID is still running
# Usage: wait_for_pid <pid> <timeout>
wait_for_pid() {
  local pid=$1 timeout=$2
  local start_time=$(date +%s)
  while kill -0 $pid 2>/dev/null; do
    sleep 1
    (( $(date +%s) - start_time >= timeout )) && return 1
  done
  return 0
}

# Start a Netconf subscription that waits for a terminal notification in the background
# The function returns the subscription result (the netconf/subscription PID and the pipe that
# is used to read the result)
# Usage: subscribe_for <event_type> <mac_address>
subscribe_for() {
  local event_type=$1 mac_address=$2
  # Event type must be provided
  [[ -z "$event_type" ]] && { echo "$FUNCNAME() needs an event type"; return 1; }
  # Mac address must be provided
  [[ -z "$mac_address" ]] && { echo "$FUNCNAME() needs a mac address"; return 1; }

  # Create a named pipe for communication between child processes
  local pipedir
  pipedir=$(mktemp -d) || { echo "Failed to create a temporary directory"; return 1; }
  mkfifo "$pipedir/commpipe" "$pipedir/pidpipe" || { echo "Failed to create named pipes"; rmdir "$pipedir"; return 1; }

  # Start the netconf subscription in the background
  netconf sub sbc --keyvalue 2>&1 | (
    local pid local event_mac_address lines
    # Read the netconf output
    while IFS='=' read -r key value; do
      case "$key" in
        *PID)
          # Netconf PID - we need it to stop the subscription, write to the PID pipe
          pid=$value
          echo "$pid" > "$pipedir/pidpipe"
          ;;
        *notification/eventTime*)
          # A new notification was received, reset the event mac address
          event_mac_address=
          ;;
        *terminal/mac-address*)
          # Terminal mac address in the notification
          event_mac_address=$value
          ;;
        *terminal/$event_type-notify*)
          # Notification type, if mac address matches, write to the COMM pipe
          if [ "$event_mac_address" = "$mac_address" ]; then
            echo "success" > "$pipedir/commpipe"
            kill -SIGINT $pid
          fi
          ;;
        *)
          # Anything else - if subscription not started - remeber it, maybe it's an error
          [[ -z "$pid" ]] && lines="${lines}${key}${value:+=$value} "
          ;;
      esac
    done
    # If subscription not started, write the error to the PID pipe
    [ -z "$pid" ] && echo "error: $lines" > "$pipedir/pidpipe"
  ) >/dev/null &

  # Read data from the PID pipe and remove the pipe
  local netconf_pid=$(cat "$pipedir/pidpipe")
  rm -f "$pipedir/pidpipe"
  
  # if it's an error, then subscription failed
  if [[ "$netconf_pid" =~ ^error: ]]; then
    echo "${netconf_pid#error: }"
    return 1
  fi

  # return the subscription result (the PID and the pipe)
  echo "$netconf_pid:$pipedir"
  return 0
}


# Start a Netconf subscription that waits for a logon notification in the background
# The function returns the subscription result (the netconf/subscription PID and the pipe that
# is used to read the result)
# Usage: subscribe_for_logon <mac_address>
subscribe_for_logon() {
  subscribe_for logon "$1"
}

# Start a Netconf subscription that waits for a logoff notification in the background
# The function returns the subscription result (the netconf/subscription PID and the pipe that
# is used to read the result)
# Usage: subscribe_for_logoff <mac_address>
subscribe_for_logoff() {
  subscribe_for logoff "$1"
}

# Wait for a previously started subscription and return the result
# The function waits either for the netconf subscription to receive a requested notification or
# for the timeout to expire. If timeout is not provided, the function waits indefinitely.
# Usage: subscribe_wait <subscription_result> [<timeout>]
subscribe_wait() {
  local arg=$1 timeout=$2

  # The function needs a subscription result as an argument
  [[ -z "$arg" || ! "$arg" =~ ^[0-9]+(:.*)+$ ]] && { echo "$FUNCNAME() needs an argument"; return 1; }

  # Extract the PID and the pipe from the subscription result
  local netconf_pid=${arg%%:*}
  local pipedir=${arg#*:}
  
  # Handle timeout if provided
  local timeout_pid
  if [[ -n "$timeout" ]]; then
    (
      local pid
      sleep $timeout & pid=$!
      trap "kill -SIGINT $pid" SIGINT
      wait $pid
      if [ $? = 0 ]; then
        kill -SIGINT $netconf_pid
        echo "timeout" > "$pipedir/commpipe"
      fi
    ) >/dev/null &
    timeout_pid=$!
  fi

  # Read the result from the pipe
  local result=$(cat "$pipedir/commpipe")

  [[ -n "$timeout_pid" ]] && kill -SIGINT $timeout_pid 2>/dev/null
  wait_for_pid $netconf_pid 10 || kill -9 $netconf_pid
  [[ -n "$timeout_pid" ]] && wait $timeout_pid
  
  # Cleanup
  [ -p "$pipedir/commpipe" ] && rm -f "$pipedir/commpipe"
  [ -d "$pipedir" ] && rmdir "$pipedir"

  # Return the result
  echo "$result"
  if [[ "$result" = "success" ]]; then
    return 0
  else
    return 1
  fi
}


# Start a subscription for a logon notification
if ret=$(subscribe_for_logon 00:09:ce:c0:06:8a); then
  echo "Subscription started" >&2
  # Wait for the notification to be received with a timeout of 10 seconds
  if ret=$(subscribe_wait "$ret" 10); then
    echo "Notification received"
    exit 0
  else
    echo "Notification NOT received: $ret"
    exit 1
  fi

else
  echo "Failed to subscribe: $ret"
  exit 1
fi
