#!/bin/sh
# Copyright (C) 2023 iopsys Software Solutions AB
# Author: Suvendhu Hansa <suvendhu.hansa@iopsys.eu>

. /usr/share/libubox/jshn.sh

ROOT="$(dirname "${0}")"
. "${ROOT}"/bbf_api

clear_iplayercapacity_output() {
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.DiagnosticState="${1}"
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.SoftwareVersion=""
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.BOMTime=""
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.EOMTime=""
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.TmaxUsed=""
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.TestInterval=""
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.TmaxRTTUsed=""
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.TimestampResolutionUsed=""
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.MaxIPLayerCapacity=""
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.TimeOfMax=""
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.MaxETHCapacityNoFCS=""
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.MaxETHCapacityWithFCS=""
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.MaxETHCapacityWithFCSVLAN=""
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.LossRatioAtMax=""
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.RTTRangeAtMax=""
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.PDVRangeAtMax=""
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.MinOnewayDelayAtMax=""
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.ReorderedRatioAtMax=""
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.ReplicatedRatioAtMax=""
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.InterfaceEthMbpsAtMax=""
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.IPLayerCapacitySummary=""
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.LossRatioSummary=""
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.RTTRangeSummary=""
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.PDVRangeSummary=""
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.MinOnewayDelaySummary=""
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.MinRTTSummary=""
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.ReorderedRatioSummary=""
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.ReplicatedRatioSummary=""
	$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.InterfaceEthMbpsSummary=""
}

iplayercap_error() {
	json_init
	json_add_string "Status" "$1"
	json_dump

	# Store data in dmmap
	[ "$2" = "both_proto" ] && {
		clear_iplayercapacity_output "$1"

		# Clear all incremental & modal result instances
		res=$($UCI_SHOW_BBF_DMMAP dmmap_diagnostics | grep -E "=modalresult$" | cut -d= -f 1)
		for i in $res; do
			$UCI_DELETE_BBF_DMMAP "${i}"
		done

		res=$($UCI_SHOW_BBF_DMMAP dmmap_diagnostics | grep -E "=incrementalresult$" | cut -d= -f 1)
		for i in $res; do
			$UCI_DELETE_BBF_DMMAP "${i}"
		done

		$UCI_COMMIT_BBF_DMMAP
	}
}

iplayercap_launch() {
	input="$1"
	options=""

	json_load "${input}"

	json_get_var interface interface
	json_get_var role role
	json_get_var host host
	json_get_var port port
	json_get_var jumbo_frames jumbo_frames
	json_get_var DSCP DSCP
	json_get_var proto_ver proto_ver
	json_get_var udp_content udp_content
	json_get_var test_type test_type
	json_get_var ipdv_enable ipdv_enable
	json_get_var rate_index rate_index
	json_get_var num_interval num_interval
	json_get_var mode_subintervals mode_subintervals
	json_get_var test_subinterval test_subinterval
	json_get_var feedback_interval feedback_interval
	json_get_var seq_err_thresh seq_err_thresh
	json_get_var dup_ignore dup_ignore
	json_get_var lower_thresh lower_thresh
	json_get_var upper_thresh upper_thresh
	json_get_var high_speed_delta high_speed_delta
	json_get_var algorithm algorithm
	json_get_var slow_adj_thresh slow_adj_thresh
	json_get_var proto proto

	[ "${proto}" = "both_proto" ] && {
		old_pid=$(cat /tmp/iplayercap_pid)

		[ -n "${old_pid}" ] && {
			cmd=$(cat /proc/$old_pid/cmdline)
		}

		if [[ "${cmd}" = *iplayercap* ]]; then
			kill -9 $old_pid
		fi

		# Clear all incremental & modal result instances
		res=$($UCI_SHOW_BBF_DMMAP dmmap_diagnostics | grep -E "=modalresult$" | cut -d= -f 1)
		for i in $res; do
			$UCI_DELETE_BBF_DMMAP "${i}"
		done

		res=$($UCI_SHOW_BBF_DMMAP dmmap_diagnostics | grep -E "=incrementalresult$" | cut -d= -f 1)
		for i in $res; do
			$UCI_DELETE_BBF_DMMAP "${i}"
		done

		if [ "${cancel}" -eq "1" ]; then
			clear_iplayercapacity_output "None"
			$UCI_COMMIT_BBF_DMMAP

			return
		else
			echo $$ > /tmp/iplayercap_pid
			$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.DiagnosticState="Requested_running"
			$UCI_COMMIT_BBF_DMMAP
		fi
	}

	# Fail if host is empty
	[ -z "${host}" ] && {
		iplayercap_error "Error_Internal" "${proto}"
		return
	}

	# Assign default value
	[ -z "${test_type}" ] && test_type="Search"
	[ -z "${test_subinterval}" ] && test_subinterval=1000
	[ -z "${feedback_interval}" ] && feedback_interval=50
	[ -z "${seq_err_thresh}" ] && seq_err_thresh=10
	[ -z "${dup_ignore}" ] && dup_ignore=1
	[ -z "${lower_thresh}" ] && lower_thresh=30
	[ -z "${upper_thresh}" ] && upper_thresh=90
	[ -z "${high_speed_delta}" ] && high_speed_delta=10
	[ -z "${slow_adj_thresh}" ] && slow_adj_thresh=3
	[ -z "${num_interval}" ] && num_interval=10

	if [ -z "${role}" ] || [ "${role}" = "Sender" ]; then
		options="$options -u"
	else
		options="$options -d"
	fi

	if [ -n "${jumbo_frames}" ] && [ "${jumbo_frames}" -eq 0 ]; then
		options="$options -j"
	fi

	if [ -n "${DSCP}" ] && [ "${DSCP}" -gt 0 ]; then
		options="$options -m $DSCP"
	fi

	if [ "${proto_ver}" = "IPv4" ]; then
		options="$options -4"
	elif [ "${proto_ver}" = "IPv6" ]; then
		options="$options -6"
	fi

	if [ "${udp_content}" = "random" ]; then
		options="$options -X"
	fi

	if [ -n "${ipdv_enable}" ] && [ "${ipdv_enable}" -eq 1 ]; then
		options="$options -o"
	fi

	if [ -n "${rate_index}" ]; then
		options="$options -I @${rate_index}"
	fi

	if [ -n "${algorithm}" ]; then
		options="$options -A ${algorithm}"
	fi

	if [ -n "${interface}" ]; then
		options="$options -E ${interface}"
	fi

	if [ -n "${port}" ]; then
		options="$options -p ${port}"
	fi

	test_subinterval=$(( test_subinterval/1000 ))
	t_val=$(( test_subinterval*num_interval ))
	if [ "${t_val}" -lt 5 ] || [ "${t_val}" -gt 60 ]; then
		iplayercap_error "Error_Internal" "${proto}"
		return
	fi

	if [ -n "${mode_subintervals}" ] && [ "${mode_subintervals}" -gt 0 ]; then
		if [ "${mode_subintervals}" -lt ${num_interval} ]; then
			options="$options -i ${mode_subintervals}"
		else
			iplayercap_error "Error_Internal" "${proto}"
			return
		fi
	fi

	options="$options -P ${test_subinterval} -t ${t_val} -F ${feedback_interval}"

	if [ "${test_type}" = "Search" ]; then
		options="$options -q ${seq_err_thresh} -L ${lower_thresh} -U ${upper_thresh} -h ${high_speed_delta} -c ${slow_adj_thresh}"
		if [ "${dup_ignore}" -eq 0 ]; then
			options="$options -R"
		fi
	fi

	cmd="udpst ${options} -f jsonf ${host}"
	output=$(${cmd} 2>&1)
	if [ "$?" -eq 127 ] || [ "$?" -eq 255 ]; then
		iplayercap_error "Error_Internal" "${proto}"
		return
	fi

	json_init
	json_load "$output"

	[ "${proto}" = "both_proto" ] && {
		json_get_var err ErrorStatus
		if [ "${err}" -ne 0 ]; then
			iplayercap_error "Error_Internal" "${proto}"
			return
		fi

		json_select IPLayerCapSupported
		if [ "$?" -ne 0 ]; then
			iplayercap_error "Error_Internal" "${proto}"
			return
		fi

		json_get_var version SoftwareVersion
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.SoftwareVersion="${version}"
		json_select ..

		json_select Output
		if [ "$?" -ne 0 ]; then
			iplayercap_error "Error_Internal" "${proto}"
			return
		fi

		json_get_var Status Status
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.DiagnosticState="${Status}"

		json_get_var BOMTime BOMTime
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.BOMTime="${BOMTime}"

		json_get_var EOMTime EOMTime
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.EOMTime="${EOMTime}"

		json_get_var TmaxUsed TmaxUsed
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.TmaxUsed="${TmaxUsed}"

		json_get_var TestInterval TestInterval
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.TestInterval="${TestInterval}"

		json_get_var TmaxRTTUsed TmaxRTTUsed
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.TmaxRTTUsed="${TmaxRTTUsed}"

		json_get_var TimestampResolutionUsed TimestampResolutionUsed
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.TimestampResolutionUsed="${TimestampResolutionUsed}"

		json_select AtMax
		if [ "$?" -ne 0 ]; then
			iplayercap_error "Error_Internal" "${proto}"
			return
		fi

		json_get_var MaxIPLayerCapacity MaxIPLayerCapacity
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.MaxIPLayerCapacity="${MaxIPLayerCapacity}"

		json_get_var TimeOfMax TimeOfMax
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.TimeOfMax="${TimeOfMax}"

		json_get_var MaxETHCapacityNoFCS MaxETHCapacityNoFCS
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.MaxETHCapacityNoFCS="${MaxETHCapacityNoFCS}"

		json_get_var MaxETHCapacityWithFCS MaxETHCapacityWithFCS
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.MaxETHCapacityWithFCS="${MaxETHCapacityWithFCS}"

		json_get_var MaxETHCapacityWithFCSVLAN MaxETHCapacityWithFCSVLAN
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.MaxETHCapacityWithFCSVLAN="${MaxETHCapacityWithFCSVLAN}"

		json_get_var LossRatioAtMax LossRatioAtMax
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.LossRatioAtMax="${LossRatioAtMax}"

		json_get_var RTTRangeAtMax RTTRangeAtMax
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.RTTRangeAtMax="${RTTRangeAtMax}"

		json_get_var PDVRangeAtMax PDVRangeAtMax
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.PDVRangeAtMax="${PDVRangeAtMax}"

		json_get_var MinOnewayDelayAtMax MinOnewayDelayAtMax
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.MinOnewayDelayAtMax="${MinOnewayDelayAtMax}"

		json_get_var ReorderedRatioAtMax ReorderedRatioAtMax
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.ReorderedRatioAtMax="${ReorderedRatioAtMax}"

		json_get_var ReplicatedRatioAtMax ReplicatedRatioAtMax
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.ReplicatedRatioAtMax="${ReplicatedRatioAtMax}"

		json_get_var InterfaceEthMbps InterfaceEthMbps
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.InterfaceEthMbpsAtMax="${InterfaceEthMbps}"
		json_select ..

		json_select Summary
		if [ "$?" -ne 0 ]; then
			iplayercap_error "Error_Internal" "${proto}"
			return
		fi

		json_get_var IPLayerCapacitySummary IPLayerCapacitySummary
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.IPLayerCapacitySummary="${IPLayerCapacitySummary}"

		json_get_var LossRatioSummary LossRatioSummary
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.LossRatioSummary="${LossRatioSummary}"

		json_get_var RTTRangeSummary RTTRangeSummary
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.RTTRangeSummary="${RTTRangeSummary}"

		json_get_var PDVRangeSummary PDVRangeSummary
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.PDVRangeSummary="${PDVRangeSummary}"

		json_get_var MinOnewayDelaySummary MinOnewayDelaySummary
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.MinOnewayDelaySummary="${MinOnewayDelaySummary}"

		json_get_var MinRTTSummary MinRTTSummary
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.MinRTTSummary="${MinRTTSummary}"

		json_get_var ReorderedRatioSummary ReorderedRatioSummary
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.ReorderedRatioSummary="${ReorderedRatioSummary}"

		json_get_var ReplicatedRatioSummary ReplicatedRatioSummary
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.ReplicatedRatioSummary="${ReplicatedRatioSummary}"

		json_get_var InterfaceEthMbps InterfaceEthMbps
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.iplayercapacity.InterfaceEthMbpsSummary="${InterfaceEthMbps}"
		json_select ..

		failed=0
		if json_is_a ModalResult array; then
			json_select ModalResult
			if [ "$?" -eq 0 ]; then
				idx=1
				inst=0
				while json_is_a ${idx} object
				do
					json_select ${idx}
					if [ "$?" -ne 0 ]; then
						iplayercap_error "Error_Internal" "${proto}"
						failed=1
						break
					fi

					json_get_var TimeOfMax TimeOfMax
					json_get_var MaxIPLayerCapacity MaxIPLayerCapacity
					json_get_var MaxETHCapacityNoFCS MaxETHCapacityNoFCS
					json_get_var MaxETHCapacityWithFCS MaxETHCapacityWithFCS
					json_get_var MaxETHCapacityWithFCSVLAN MaxETHCapacityWithFCSVLAN
					json_get_var LossRatioAtMax LossRatioAtMax
					json_get_var RTTRangeAtMax RTTRangeAtMax
					json_get_var PDVRangeAtMax PDVRangeAtMax
					json_get_var MinOnewayDelayAtMax MinOnewayDelayAtMax
					json_get_var ReorderedRatioAtMax ReorderedRatioAtMax
					json_get_var ReplicatedRatioAtMax ReplicatedRatioAtMax
					json_get_var InterfaceEthMbps InterfaceEthMbps

					sec=$($UCI_ADD_BBF_DMMAP dmmap_diagnostics modalresult)
					$UCI_RENAME_BBF_DMMAP dmmap_diagnostics.@modalresult[${inst}]="modalresult_${inst}"
					$UCI_SET_BBF_DMMAP dmmap_diagnostics.modalresult_${inst}.MaxIPLayerCapacity="${MaxIPLayerCapacity}"
					$UCI_SET_BBF_DMMAP dmmap_diagnostics.modalresult_${inst}.TimeOfMax="${TimeOfMax}"
					$UCI_SET_BBF_DMMAP dmmap_diagnostics.modalresult_${inst}.MaxETHCapacityNoFCS="${MaxETHCapacityNoFCS}"
					$UCI_SET_BBF_DMMAP dmmap_diagnostics.modalresult_${inst}.MaxETHCapacityWithFCS="${MaxETHCapacityWithFCS}"
					$UCI_SET_BBF_DMMAP dmmap_diagnostics.modalresult_${inst}.MaxETHCapacityWithFCSVLAN="${MaxETHCapacityWithFCSVLAN}"
					$UCI_SET_BBF_DMMAP dmmap_diagnostics.modalresult_${inst}.LossRatioAtMax="${LossRatioAtMax}"
					$UCI_SET_BBF_DMMAP dmmap_diagnostics.modalresult_${inst}.RTTRangeAtMax="${RTTRangeAtMax}"
					$UCI_SET_BBF_DMMAP dmmap_diagnostics.modalresult_${inst}.PDVRangeAtMax="${PDVRangeAtMax}"
					$UCI_SET_BBF_DMMAP dmmap_diagnostics.modalresult_${inst}.MinOnewayDelayAtMax="${MinOnewayDelayAtMax}"
					$UCI_SET_BBF_DMMAP dmmap_diagnostics.modalresult_${inst}.ReorderedRatioAtMax="${ReorderedRatioAtMax}"
					$UCI_SET_BBF_DMMAP dmmap_diagnostics.modalresult_${inst}.ReplicatedRatioAtMax="${ReplicatedRatioAtMax}"
					$UCI_SET_BBF_DMMAP dmmap_diagnostics.modalresult_${inst}.InterfaceEthMbpsAtMax="${InterfaceEthMbps}"

					idx=$(( idx + 1 ))
					inst=$(( inst + 1))
					json_select ..
				done
				json_select ..
			fi
		fi

		if [ "${failed}" -eq 1 ]; then
			return
		fi

		if json_is_a IncrementalResult array; then
			json_select IncrementalResult
			if [ "$?" -eq 0 ]; then
				idx=1
				inst=0
				while json_is_a ${idx} object
				do
					json_select ${idx}
					if [ "$?" -ne 0 ]; then
						iplayercap_error "Error_Internal" "${proto}"
						failed=1
						break
					fi

					json_get_var TimeOfSubInterval TimeOfSubInterval
					json_get_var IPLayerCapacity IPLayerCapacity
					json_get_var LossRatio LossRatio
					json_get_var RTTRange RTTRange
					json_get_var PDVRange PDVRange
					json_get_var MinOnewayDelay MinOnewayDelay
					json_get_var ReorderedRatio ReorderedRatio
					json_get_var ReplicatedRatio ReplicatedRatio
					json_get_var InterfaceEthMbps InterfaceEthMbps

					sec=$($UCI_ADD_BBF_DMMAP dmmap_diagnostics incrementalresult)
					$UCI_RENAME_BBF_DMMAP dmmap_diagnostics.@incrementalresult[${inst}]="incrementalresult_${inst}"
					$UCI_SET_BBF_DMMAP dmmap_diagnostics.incrementalresult_${inst}.IPLayerCapacity="${IPLayerCapacity}"
					$UCI_SET_BBF_DMMAP dmmap_diagnostics.incrementalresult_${inst}.TimeOfSubInterval="${TimeOfSubInterval}"
					$UCI_SET_BBF_DMMAP dmmap_diagnostics.incrementalresult_${inst}.LossRatio="${LossRatio}"
					$UCI_SET_BBF_DMMAP dmmap_diagnostics.incrementalresult_${inst}.RTTRange="${RTTRange}"
					$UCI_SET_BBF_DMMAP dmmap_diagnostics.incrementalresult_${inst}.PDVRange="${PDVRange}"
					$UCI_SET_BBF_DMMAP dmmap_diagnostics.incrementalresult_${inst}.MinOnewayDelay="${MinOnewayDelay}"
					$UCI_SET_BBF_DMMAP dmmap_diagnostics.incrementalresult_${inst}.ReorderedRatio="${ReorderedRatio}"
					$UCI_SET_BBF_DMMAP dmmap_diagnostics.incrementalresult_${inst}.ReplicatedRatio="${ReplicatedRatio}"
					$UCI_SET_BBF_DMMAP dmmap_diagnostics.incrementalresult_${inst}.InterfaceEthMbps="${InterfaceEthMbps}"

					idx=$(( idx + 1 ))
					inst=$(( inst + 1))
					json_select ..
				done
				json_select ..
			fi
		fi

		if [ "${failed}" -eq 1 ]; then
			return
		fi

		$UCI_COMMIT_BBF_DMMAP
	}

	json_dump
}


[ ! -f /etc/bbfdm/dmmap/dmmap_diagnostics ] && touch /etc/bbfdm/dmmap/dmmap_diagnostics
if [ -n "$1" ]; then
	iplayercap_launch "$1"
else
	iplayercap_error "Error_Internal" "${proto}"
fi
