UPGRADE_FW_MAJOR="2020-09-07-0-e50f2a1b-20.09"
UPGRADE_FW_VERSION="2020-09-14-1-e77d229f-20.09.1-plus"
UPGRADE_FW_REQUIRE="2020-09-07-0-e50f2a1b-20.09"

UPGRADE_FW_VERSION_SUFFIX=${UPGRADE_FW_VERSION#*-*-*-*-*-}
UPGRADE_FW_VERSION_PLUS=""

case $UPGRADE_FW_VERSION_SUFFIX in *plus*) UPGRADE_FW_VERSION_PLUS="+";; esac

CONF_DIR_PATH="/tmp/sysupgrade_cfg"
CONF_TGZ_PATH="/tmp/sysupgrade.tgz"

BOSMINER_CONF="/etc/bosminer.toml"

BOSMINER_CONF_DST="/tmp/bosminer.toml"
CONFIG_GENERATOR="sysupgrade_script"

current_fw_version() {
	if ! cat /etc/bos_version 2>/dev/null; then
		awk '/Package: /{p=$2} /Version: /{v=$2} /Status: /{if (p == "firmware" && $NF == "installed") print v}' \
			'/usr/lib/opkg/status'
	fi
}

current_fw_major() {
	cat /etc/bos_major 2>/dev/null || echo unknown
}

check_fw_version() {
	echo "Gathering current firmware information..."

	local board_name=$1
	local fw_major=$(current_fw_major)
	local fw_version=$(current_fw_version)

	echo "board  : $board_name"
	echo "version: $fw_version"
	echo "major  : $fw_major"

	echo "Checking compatibility..."

	if [ "$UPGRADE_FW_VERSION" ">" "$fw_version" ]; then
		# firmware upgrade
		if [ "$UPGRADE_FW_REQUIRE" ">" "$fw_version" ]; then
			echo "Firmware upgrade to '$UPGRADE_FW_VERSION' is not possible!"
			echo "Firmware version '$UPGRADE_FW_REQUIRE' is required before upgrading to this version."
			return 1
		fi
	elif [ "$UPGRADE_FW_VERSION" "<" "$fw_version" ]; then
		# firmware downgrade
		if [ "$UPGRADE_FW_MAJOR" != "$fw_major" ]; then
			echo "Firmware downgrade to '$UPGRADE_FW_VERSION' is not possible!"
			echo "Downgrade is only possible among firmwares with major version '$UPGRADE_FW_MAJOR'."
			echo "Do the factory reset and try to upgrade to this version."
			return 1
		fi
	fi

	return 0
}

modify_configs() {
	# extract configuration files from tarball
	mkdir -p "$CONF_DIR_PATH"
	tar -xzf "$CONF_TGZ_PATH" -C "$CONF_DIR_PATH"
	echo "$CONF_DIR_PATH"

	return 0
}

finish_configs_modification() {
	if [ "$1" == "store" ]; then
		tar -czf "$CONF_TGZ_PATH" -C "$CONF_DIR_PATH" $(ls -A "$CONF_DIR_PATH")
	fi

	# cleanup system
	rm -rf "$CONF_DIR_PATH"

	return 0
}

get_bosminer_toml_version() {
	awk -f - "$BOSMINER_CONF" <<-EOF
		/^\[format\]\$/ {
			f = "y"; next
		}
		/^\[.*\]\$/ {
			f = "n"; next
		}
		\$1 == "version" {
			print substr(\$3, 2, length(\$3)-2)
		}
	EOF
	return 0
}

migrate_bosminer_toml_to_open() {
	local version="$1"

	echo "Migrating BOSminer+ configuration file to open version..."

	local timestamp=$(date +%s)
	awk -f - "$BOSMINER_CONF" > "$BOSMINER_CONF_DST" <<-EOF
		function reset() {
			f = "n"; c = "n"
			g = "n"; t = "n"
		}

		function print_generator(nl) {
			if (f == "y") {
				if (g == "n") print "generator = '${CONFIG_GENERATOR}'"
				if (t == "n") print "timestamp = ${timestamp}"
				if (nl && (g == "n" || t == "n")) print ""
			}
		}

		BEGIN {
			reset()
		}
		/^\[format\]\$/ {
			reset(); f = "y"
			print; next
		}
		/^\[autotuning\]\$/ || /^\[power_scaling\]\$/ {
			reset(); c = "y"
			print "# " \$0; next
		}
		/^\[.*\]\$/ {
			print_generator(1)
			reset()
		}
		f == "y" && \$1 == "version" {
			print "# " \$0; print "version = '${version}'"; next
		}
		f == "y" && \$1 == "generator" {
			g = "y"; print "generator = '${CONFIG_GENERATOR}'"; next
		}
		f == "y" && \$1 == "timestamp" {
			t = "y"; print "timestamp = ${timestamp}"; next
		}
		c == "y" {
			print "# " \$0; next
		}
		{print}
		END {
			print_generator(0)
		}
	EOF
	return 0
}

migrate_bosminer_toml_to_plus() {
	local version="$1"

	echo "Migrating BOSminer configuration file to plus version..."

	local miner_psu_power_limit=$(fw_printenv -n miner_psu_power_limit 2>/dev/null)
	local autotuning_enabled="yes"

	case $miner_psu_power_limit in
		default)
			miner_psu_power_limit=
		;;
		"")
			autotuning_enabled="no"
			miner_psu_power_limit=
		;;
	esac

	local timestamp=$(date +%s)
	awk -f - "$BOSMINER_CONF" > "$BOSMINER_CONF_DST" <<-EOF
		function reset() {
			f = "n"
			g = "n"; t = "n"
		}

		function print_generator(nl) {
			if (f == "y") {
				if (g == "n") print "generator = '${CONFIG_GENERATOR}'"
				if (t == "n") print "timestamp = ${timestamp}"
				if (nl && (g == "n" || t == "n")) print ""
			}
		}

		BEGIN {
			reset()
		}
		/^\[format\]\$/ {
			reset(); f = "y"
			print; next
		}
		/.*^\[.*\]\$/ {
			print_generator(1)
			reset()
		}
		f == "y" && \$1 == "version" {
			print "# " \$0; print "version = '${version}'"; next
		}
		f == "y" && \$1 == "generator" {
			g = "y"; print "generator = '${CONFIG_GENERATOR}'"; next
		}
		f == "y" && \$1 == "timestamp" {
			t = "y"; print "timestamp = ${timestamp}"; next
		}
		{print}
		END {
			print_generator(0)
			if ("${autotuning_enabled}" == "yes") {
				print ""
				print "[autotuning]"
				print "enabled = true"
				if ("${miner_psu_power_limit}") {
					print "psu_power_limit = ${miner_psu_power_limit}"
				}
			}
		}
	EOF
	return 0
}

fix_bosminer_toml_version() {
	local curr_ver="$1"
	local next_ver="$2"

	local fw_version=$(current_fw_version)

	# Do the fix only during firmware upgrade
	[ "$UPGRADE_FW_VERSION" ">" "$fw_version" ] || return 0
	# Skip the fix when the format version is the same
	[ "$curr_ver" != "$next_ver" ] || return 0

	echo "Fixing BOSminer configuration file version..."

	local timestamp=$(date +%s)
	awk -f - "$BOSMINER_CONF" > "$BOSMINER_CONF_DST" <<-EOF
		function reset() {
			f = "n"
			g = "n"; t = "n"
		}

		function print_generator(nl) {
			if (f == "y") {
				if (g == "n") print "generator = '${CONFIG_GENERATOR}'"
				if (t == "n") print "timestamp = ${timestamp}"
				if (nl && (g == "n" || t == "n")) print ""
			}
		}

		BEGIN {
			reset()
		}
		/^\[format\]\$/ {
			reset(); f = "y"
			print; next
		}
		/.*^\[.*\]\$/ {
			print_generator(1)
			reset()
		}
		f == "y" && \$1 == "version" {
			print "# " \$0; print "version = '${next_ver}'"; next
		}
		f == "y" && \$1 == "generator" {
			g = "y"; print "generator = '${CONFIG_GENERATOR}'"; next
		}
		f == "y" && \$1 == "timestamp" {
			t = "y"; print "timestamp = ${timestamp}"; next
		}
		{print}
		END {
			print_generator(0)
		}
	EOF
	return 0
}

migrate_bosminer_toml() {
	# Do not migrate BOSminer config when BOSminer config is not present
	[ ! -f "$BOSMINER_CONF" ] && return 0

	local current_toml_version=$(get_bosminer_toml_version)
	# Exit when format version cannot be determined
	[ -z "$current_toml_version" ] && return 0

	local current_toml_version_plus=""
	case $current_toml_version in *+) current_toml_version_plus="+";; esac

	if [ -n "$UPGRADE_FW_VERSION_PLUS" ]; then
		# Do the migration when upgrading from open to plus version
		[ -z "$current_toml_version_plus" ] \
			&& migrate_bosminer_toml_to_plus "$BOSMINER_CONF_VERSION_PLUS" \
			|| fix_bosminer_toml_version "$current_toml_version" "$BOSMINER_CONF_VERSION_PLUS"
	else
		# Do the migration when downgrading from plus to open version
		[ -n "$current_toml_version_plus" ] \
			&& migrate_bosminer_toml_to_open "$BOSMINER_CONF_VERSION_OPEN" \
			|| fix_bosminer_toml_version "$current_toml_version" "$BOSMINER_CONF_VERSION_OPEN"
	fi

	return 0
}

replace_bosminer_conf() {
	local conf_dir_path=$(modify_configs)
	local conf_action="discard"

	cp "${BOSMINER_CONF_DST}" "${conf_dir_path}/etc/" 2>/dev/null && \
		conf_action="store"

	finish_configs_modification $conf_action
	return 0
}

BOSMINER_CONF_VERSION_OPEN="1.0"
BOSMINER_CONF_VERSION_PLUS="1.0+"

check_image() {
	check_fw_version $1 && {
		migrate_bosminer_toml
	}
}

pre_upgrade() {
	local board_name=$1
	local tar_file=$2

	replace_bosminer_conf
	return
}
