#!/bin/sh
# Copyright (C) 2022 iopsys Software Solutions AB
# Author: IMEN Bhiri <imen.bhiri@pivasoftware.com>
# Author: AMIN Ben Romdhane <amin.benromdhane@iopsys.eu>

. /usr/share/libubox/jshn.sh

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

DOWNLOAD_TIMEOUT=1800

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

	# Store data in dmmap_diagnostics for both protocols (cwmp/usp)
	[ "$2" = "both_proto" ] && {
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.download.DiagnosticState="$1"
	}

	$UCI_SET_BBF_DMMAP dmmap_diagnostics.download.Status="complete"
	$UCI_COMMIT_BBF_DMMAP
}

download_launch() {
	input="$1"

	json_load "${input}"
	
	json_get_var url url
	json_get_var iface iface
	json_get_var dscp dscp
	json_get_var eth_prio eth_prio
	json_get_var ip_proto ip_proto
	json_get_var num_of_con num_of_con
	json_get_var enable_per_con enable_per_con
	json_get_var proto proto

	# Check if a download process is already running
	download_s=$(uci_get_bbf_dmmap dmmap_diagnostics.download)
	if [ -z "${download_s}" ]; then
		[ ! -f /etc/bbfdm/dmmap/dmmap_diagnostics ] && touch /etc/bbfdm/dmmap/dmmap_diagnostics
		$UCI_ADD_BBF_DMMAP dmmap_diagnostics download
		$UCI_RENAME_BBF_DMMAP dmmap_diagnostics.@download[0]='download'
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.download.Status="running"
		$UCI_COMMIT_BBF_DMMAP
	else
		Status=$(uci_get_bbf_dmmap dmmap_diagnostics.download.Status)
		[ "${Status}" = "running" ] && {
			return
		}

		$UCI_SET_BBF_DMMAP dmmap_diagnostics.download.Status="running"
		$UCI_COMMIT_BBF_DMMAP
	fi

	# Fail if url is empty
	[ -z "${url}" ] && {
		download_error "Error_InitConnectionFailed" "${proto}"
		return
	}

	[ "${url:0:7}" != "http://" ] && [ "${url:0:6}" != "ftp://" ] && [ "${url:0:8}" != "https://" ] && {
		download_error "Error_Other" "${proto}"
		return
	}

	if [ -n "${iface}" ]; then
		device=$(ifstatus "${iface}" | jsonfilter -e '@.l3_device')

		# If no device was found, return error
		[ -z "${device}" ] && {
			download_error "Error_NoRouteToHost" "${proto}"
			return
		}
	else
		device=$(route -n | grep 'UG[ \t]' | awk '{print $8}')
	fi

	ip_addr_used=$(get_ip_addr_used "${url}" "${ip_proto}" "${iface}")

	# Assign default value
	if [ "$ip_proto" = "IPv4" ]; then ip_proto="--ipv4"; elif [ "$ip_proto" = "IPv6" ]; then ip_proto="--ipv6"; else ip_proto=""; fi

	format='{ "size_download": "%{size_download}",
			  "size_header": "%{size_header}",
			  "time_appconnect": "%{time_appconnect}",
			  "time_connect": "%{time_connect}",
			  "time_pretransfer": "%{time_pretransfer}",
			  "time_starttransfer": "%{time_starttransfer}",
			  "time_total": "%{time_total}",
			  "exitcode": "%{exitcode}" }'

	tx_bytes_start=$(ubus call network.device status "{'name':'$device'}" | jsonfilter -e @.statistics.tx_bytes)
	rx_bytes_start=$(ubus call network.device status "{'name':'$device'}" | jsonfilter -e @.statistics.rx_bytes)

	time_start=$(date +"%s.282646") # It should be like that time_start=$(date +"%s.%6N") but since OpenWrt busybox has limitations and doesn't support nonoseconds so keep it hardcoded
	if [ -z "${ip_proto}" ]; then
		res=$(curl --fail --silent --max-time "${DOWNLOAD_TIMEOUT}" -w "${format}" "${url}" --output /dev/null)
	else
		res=$(curl "${ip_proto}" --fail --silent --max-time "${DOWNLOAD_TIMEOUT}" -w "${format}" "${url}" --output /dev/null)
	fi
	time_end=$(date +"%s.282646") # It should be like that time_end=$(date +"%s.%6N") but since OpenWrt busybox has limitations and doesn't support nonoseconds so keep it hardcoded

	tx_bytes_end=$(ubus call network.device status "{'name':'$device'}" | jsonfilter -e @.statistics.tx_bytes)
	rx_bytes_end=$(ubus call network.device status "{'name':'$device'}" | jsonfilter -e @.statistics.rx_bytes)
	
	logger -t "bbf_download" "########### ${url} ==> ${res} ###########"
	json_load "${res}"
	json_get_var size_download size_download
	json_get_var size_header size_header
	json_get_var time_appconnect time_appconnect
	json_get_var time_connect time_connect
	json_get_var time_pretransfer time_pretransfer
	json_get_var time_starttransfer time_starttransfer
	json_get_var time_total time_total
	json_get_var exitcode exitcode

	[ "$exitcode" = "6" ] && {
		download_error "Error_CannotResolveHostName" "${proto}"
		return
	}

	[ "$exitcode" = "7" ] && {
		download_error "Error_InitConnectionFailed" "${proto}"
		return
	}

	[ "$exitcode" = "22" ] && {
		download_error "Error_NoResponse" "${proto}"
		return
	}

	[ "$exitcode" = "27" ] && {
		download_error "Error_IncorrectSize" "${proto}"
		return
	}

	[ "$exitcode" = "28" ] && {
		download_error "Error_Timeout" "${proto}"
		return
	}

	[ "$exitcode" != "0" ] && {
		download_error "Error_Other" "${proto}"
		return
	}
	
	tcp_open_request_time=$(echo "${time_start}" "${time_appconnect}" | awk '{printf "%.6f", $1 + $2}')
	tcp_open_response_time=$(echo "${time_start}" "${time_connect}" | awk '{printf "%.6f", $1 + $2}')
	rom_time=$(echo "${time_start}" "${time_pretransfer}" | awk '{printf "%.6f", $1 + $2}')
	bom_time=$(echo "${time_start}" "${time_starttransfer}" | awk '{printf "%.6f", $1 + $2}')
	eom_time=$(echo "${time_start}" "${time_total}" | awk '{printf "%.6f", $1 + $2}')

	x=${tcp_open_request_time%%[.]*}
	separator_idx=$((${#x}+1))
	TCPOpenRequestTime_MicroSec=${tcp_open_request_time:$separator_idx}
	TCPOpenRequestTime_Sec=${tcp_open_request_time:0:$((separator_idx-1))}

	x=${tcp_open_response_time%%[.]*}
	separator_idx=$((${#x}+1))
	TCPOpenResponseTime_MicroSec=${tcp_open_response_time:$separator_idx}
	TCPOpenResponseTime_Sec=${tcp_open_response_time:0:$((separator_idx-1))}

	x=${rom_time%%[.]*}
	separator_idx=$((${#x}+1))
	ROMTime_MicroSec=${rom_time:$separator_idx}
	ROMTime_Sec=${rom_time:0:$((separator_idx-1))}

	x=${bom_time%%[.]*}
	separator_idx=$((${#x}+1))
	BOMTime_MicroSec=${bom_time:$separator_idx}
	BOMTime_Sec=${bom_time:0:$((separator_idx-1))}

	x=${eom_time%%[.]*}
	separator_idx=$((${#x}+1))
	EOMTime_MicroSec=${eom_time:$separator_idx}
	EOMTime_Sec=${eom_time:0:$((separator_idx-1))}

	TCPOpenRequestTime=$(date -u +"%Y-%m-%dT%H:%M:%S.${TCPOpenRequestTime_MicroSec}Z" -d @"${TCPOpenRequestTime_Sec}")
	TCPOpenResponseTime=$(date -u +"%Y-%m-%dT%H:%M:%S.${TCPOpenResponseTime_MicroSec}Z" -d @"${TCPOpenResponseTime_Sec}")
	ROMTime=$(date -u +"%Y-%m-%dT%H:%M:%S.${ROMTime_MicroSec}Z" -d @"${ROMTime_Sec}")
	BOMTime=$(date -u +"%Y-%m-%dT%H:%M:%S.${BOMTime_MicroSec}Z" -d @"${BOMTime_Sec}")
	EOMTime=$(date -u +"%Y-%m-%dT%H:%M:%S.${EOMTime_MicroSec}Z" -d @"${EOMTime_Sec}")

	tx_bytes=$((tx_bytes_end-tx_bytes_start))
	rx_bytes=$((rx_bytes_end-rx_bytes_start))
	test_rx_bytes=$((size_download+size_header))
	period_time=$(echo "${time_end}" "${time_start}" | awk '{printf ($1 - $2) * 1000000}')

	json_init
	json_add_string "Status" "Complete"
	json_add_string "IPAddressUsed" "${ip_addr_used}"
	json_add_string "ROMTime" "${ROMTime}"
	json_add_string "BOMTime" "${BOMTime}"
	json_add_string "EOMTime" "${EOMTime}"
	json_add_int "TestBytesReceived" "${test_rx_bytes}"
	json_add_int "TotalBytesReceived" "${rx_bytes}"
	json_add_int "TotalBytesSent" "${tx_bytes}"
	json_add_int "PeriodOfFullLoading" "${period_time}"
	json_add_string "TCPOpenRequestTime" "${TCPOpenRequestTime}"
	json_add_string "TCPOpenResponseTime" "${TCPOpenResponseTime}"
	if [ "$enable_per_con" = "true" ] || [ "$enable_per_con" = "1" ]; then
		json_add_array "DownloadPerConnection"
		json_add_object ""
		json_add_string "ROMTime" "${ROMTime}"
		json_add_string "BOMTime" "${BOMTime}"
		json_add_string "EOMTime" "${EOMTime}"
		json_add_int "TestBytesReceived" "${test_rx_bytes}"
		json_add_int "TotalBytesReceived" "${rx_bytes}"
		json_add_int "TotalBytesSent" "${tx_bytes}"
		json_add_string "TCPOpenRequestTime" "${TCPOpenRequestTime}"
		json_add_string "TCPOpenResponseTime" "${TCPOpenResponseTime}"
		json_close_object
	fi
	json_dump

	# Store data in dmmap_diagnostics for both protocols (cwmp/usp)
	[ "${proto}" = "both_proto" ] && {
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.download.DiagnosticState="Complete"
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.download.IPAddressUsed="${ip_addr_used}"
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.download.ROMTime="${ROMTime}"
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.download.BOMTime="${BOMTime}"
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.download.EOMTime="${EOMTime}"
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.download.TestBytesReceived="${test_rx_bytes}"
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.download.TotalBytesReceived="${rx_bytes}"
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.download.TotalBytesSent="${tx_bytes}"
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.download.PeriodOfFullLoading="${period_time}"
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.download.TCPOpenRequestTime="${TCPOpenRequestTime}"
		$UCI_SET_BBF_DMMAP dmmap_diagnostics.download.TCPOpenResponseTime="${TCPOpenResponseTime}"
		if [ "$enable_per_con" = "true" ] || [ "$enable_per_con" = "1" ]; then
			$UCI_ADD_BBF_DMMAP dmmap_diagnostics DownloadPerConnection
			$UCI_SET_BBF_DMMAP dmmap_diagnostics.@DownloadPerConnection[0].ROMTime="${ROMTime}"
			$UCI_SET_BBF_DMMAP dmmap_diagnostics.@DownloadPerConnection[0].BOMTime="${BOMTime}"
			$UCI_SET_BBF_DMMAP dmmap_diagnostics.@DownloadPerConnection[0].EOMTime="${EOMTime}"
			$UCI_SET_BBF_DMMAP dmmap_diagnostics.@DownloadPerConnection[0].TestBytesReceived="${test_rx_bytes}"
			$UCI_SET_BBF_DMMAP dmmap_diagnostics.@DownloadPerConnection[0].TotalBytesReceived="${rx_bytes}"
			$UCI_SET_BBF_DMMAP dmmap_diagnostics.@DownloadPerConnection[0].TotalBytesSent="${tx_bytes}"
			$UCI_SET_BBF_DMMAP dmmap_diagnostics.@DownloadPerConnection[0].TCPOpenRequestTime="${TCPOpenRequestTime}"
			$UCI_SET_BBF_DMMAP dmmap_diagnostics.@DownloadPerConnection[0].TCPOpenResponseTime="${TCPOpenResponseTime}"
		else
			$UCI_DELETE_BBF_DMMAP dmmap_diagnostics.@DownloadPerConnection[0]
		fi
	}

	$UCI_SET_BBF_DMMAP dmmap_diagnostics.download.Status="complete"
	$UCI_COMMIT_BBF_DMMAP
}

if [ -n "$1" ]; then
	download_launch "$1"
else
	download_error "Error_Internal"
fi
