#!/bin/sh /etc/rc.common

# SIM slot switcher for HuastLink HC-G60 or ZBT-WE2806-A
# by Konstantine Shevlakov at <shevlakov@132lan.ru> 2025
# Audited & fixed 2025

START=99
STOP=10
USE_PROCD=1

CRON_FILE="/etc/crontabs/root"
CRON_TAG="# ssw-schedule"

load_config_gpio(){
	local gpio value
	for c in gpio value; do
		config_get $1_$c "$1" $c
	done
}

load_config_failover(){
	local enable mode interval times_rsrp times_ping revert rsrp host
	for c in enable mode interval times_rsrp times_ping revert rsrp host; do
		config_get $1_$c "$1" $c
	done
}

reload_iface(){
	[ "$iface" ] && {
		for i in $iface; do
			ifup "$i"
		done
	}
}

_apply_modem_state(){
	echo "$sim_value"   > /sys/class/gpio/"$sim_gpio"/value
	echo "$modem_value" > /sys/class/gpio/"$modem_gpio"/value
	if [ -x /etc/init.d/smstools3 ]; then
		/etc/init.d/smstools3 restart
	fi
	sleep 30 && reload_iface &
}

# Parse "HH:MM" -> cron fields "MM HH"
time_to_cron(){
	local t="$1" h m
	h="${t%%:*}"
	m="${t##*:}"
	h=$(echo "$h" | sed 's/^0*//')
	m=$(echo "$m" | sed 's/^0*//')
	[ -z "$h" ] && h=0
	[ -z "$m" ] && m=0
	printf "%s %s" "$m" "$h"
}

# Add duration minutes to "HH:MM", output as cron "MM HH"
time_add_min(){
	local t="$1" dur="$2" h m total_min
	h="${t%%:*}"
	m="${t##*:}"
	h=$(echo "$h" | sed 's/^0*//')
	m=$(echo "$m" | sed 's/^0*//')
	[ -z "$h" ] && h=0
	[ -z "$m" ] && m=0
	total_min=$(( h * 60 + m + dur ))
	h=$(( total_min / 60 % 24 ))
	m=$(( total_min % 60 ))
	printf "%s %s" "$m" "$h"
}

# Build cron day/month/weekday fields from period settings
# Outputs: "dom month dow"
cron_period_fields(){
	local period="$1"
	local period_days="$2"
	local weekday="$3"
	case "$period" in
		daily)    echo "* * *" ;;
		weekly)   echo "* * ${weekday:-1}" ;;
		monthly)  echo "1 * *" ;;
		interval) echo "*/${period_days:-1} * *" ;;
		*)        echo "* * *" ;;
	esac
}

update_cron(){
	local s_enable s_period s_time_on s_duration s_period_days s_weekday
	config_get s_enable      schedule enable      "0"
	config_get s_period      schedule period      "daily"
	config_get s_time_on     schedule time_on     "00:00"
	config_get s_duration    schedule duration    "0"
	config_get s_period_days schedule period_days "1"
	config_get s_weekday     schedule weekday     "1"

	# Remove old ssw entries
	sed -i "/$CRON_TAG/d" "$CRON_FILE" 2>/dev/null

	[ "$s_enable" != "1" ] && {
		/etc/init.d/cron reload 2>/dev/null
		return
	}

	local fields cron_on cron_off
	fields=$(cron_period_fields "$s_period" "$s_period_days" "$s_weekday")
	cron_on=$(time_to_cron "$s_time_on")
	cron_off=$(time_add_min "$s_time_on" "$s_duration")

	printf "%s %s /usr/share/ssw_schedule.sh %s\n" \
		"$cron_on" "$fields" "$CRON_TAG" >> "$CRON_FILE"

	if [ "$s_duration" -gt 0 ] 2>/dev/null; then
		printf "%s %s /usr/share/ssw_schedule.sh revert %s\n" \
			"$cron_off" "$fields" "$CRON_TAG" >> "$CRON_FILE"
	fi

	/etc/init.d/cron reload 2>/dev/null
	logger -t "SW SIM" "Schedule updated: on=${s_time_on} duration=${s_duration}min period=${s_period}"
}

start_service(){
	config_load ssw
	config_foreach load_config_gpio modem
	config_foreach load_config_gpio sim

	local modem_cur sim_cur
	modem_cur=$(cat /sys/class/gpio/"$modem_gpio"/value)
	sim_cur=$(cat /sys/class/gpio/"$sim_gpio"/value)

	iface=$(uci show network | awk -F'[.]' '/devices/{gsub("'\''",""); print $2}' | tail -1)

	if [ "$modem_value" = "$modem_cur" ] && [ "$sim_value" = "$sim_cur" ]; then
		logger -t "SIM SW" "Modem and SIM already in correct state. Nothing to do."
	elif [ "$modem_value" = "$modem_cur" ] && [ "$modem_value" = "1" ]; then
		logger -t "SIM SW" "Modem already enabled on gpio $modem_gpio. Restart it."
		echo "0" > /sys/class/gpio/"$modem_gpio"/value
		sleep 2
		_apply_modem_state
	else
		logger -t "SIM SW" "Modem power state changed."
		_apply_modem_state
	fi

	update_cron

	procd_open_instance
	procd_set_param command /usr/share/ssw_track.sh
	procd_close_instance
}

stop_service(){
	sed -i "/$CRON_TAG/d" "$CRON_FILE" 2>/dev/null
	/etc/init.d/cron reload 2>/dev/null
}

reload_service(){
	config_load ssw
	update_cron
	start_service
}

service_triggers(){
	procd_add_reload_trigger "ssw"
}
