#!/opt/lnxall_app/bin/lua

local uci = require "uci"
local invoker = require "invoker"

local gfmt = string.format
local g_config = "/etc/config/ntpdrtc"
local g_service = "/opt/lnxall_app/platspec/ntpdrtc.service"
local g_ntpsvr = { [1] = "ntp.aliyun.com", [2] = "ntp.lnxall.com" }
local g_ptpdev = nil -- network device for PTP clock synchronization
local g_noptp  = nil -- disable PTP settings

local function is_netdev(ndev)
	if type(ndev) ~= "string" or #ndev == 0 then return false end
	return invoker.invoke(invoker.NOSTDIO, "ip", "link", "show", "dev", ndev) == 0
end

local function current_dns_load()
	local ucintp = uci.cursor('/etc/config')
	if not ucintp then
		io.stderr:write("Error, uci system has corrupted.\n")
		io.stderr:flush()
		return false
	end
	local ntp1 = ucintp:get("ntpdrtc", "ntpd", "ntp_server1")
	local ntp2 = ucintp:get("ntpdrtc", "ntpd", "ntp_server2")
	local ntp3 = ucintp:get("ntpdrtc", "ntpd", "ntp_server3")
	local ntp4 = ucintp:get("ntpdrtc", "ntpd", "ntp_server4")
	local ptpdev = ucintp:get("ntpdrtc", "ntpd", "ptp_device")
	if is_netdev(ptpdev) then
		g_ptpdev = ptpdev
	end

	if type(ntp1) == "string" and string.len(ntp1) > 0 then g_ntpsvr[1] = ntp1 end
	if type(ntp2) == "string" and string.len(ntp2) > 0 then g_ntpsvr[2] = ntp2 end
	if type(ntp3) == "string" and string.len(ntp3) > 0 then g_ntpsvr[3] = ntp3 end
	if type(ntp4) == "string" and string.len(ntp4) > 0 then g_ntpsvr[4] = ntp4 end

	ucintp:close(); ucintp = nil
	return true
end

local function check_ntp_server(ntpsvr, idx)
	if not ntpsvr then return false end
	if string.len(ntpsvr) == 0 then return false end

	if ntpsvr == "NOPTP" then
		g_noptp = true
		return g_ptpdev
	end
	-- if ntpsvr is a network device
	if is_netdev(ntpsvr) then
		local ret = false
		if g_ptpdev ~= ntpsvr then
			ret = true
			g_ptpdev = ntpsvr
		end
		return ret
	end

	if g_ntpsvr[idx] == ntpsvr then return false end

	local oldntp = g_ntpsvr[idx] or ""
	io.stdout:write(gfmt("Updating NTP Server from '%s' to %s\n", oldntp, ntpsvr))
	io.stdout:flush()
	g_ntpsvr[idx] = ntpsvr
	return true
end

local function write_ntpdrtc_service(file)
	local fp = io.open(file, "wb")
	if not fp then return false end
	fp:write("[Unit]\nDescription=NTPD Service for Lnxall Device\nAfter=network.target\n\n[Service]\nType=simple\nRestart=always\nRestartSec=5s\n")

	for idx = 1, 4 do
		if g_ntpsvr[idx] then
			fp:write(gfmt('Environment="NTP_SERVER%d=%s"\n', idx, g_ntpsvr[idx]))
		end
	end
	if g_ptpdev then
		fp:write(gfmt('Environment="PTP_DEVICE=%s"\n', g_ptpdev))
		fp:write("ExecStart=/opt/lnxall_app/bin/lua /opt/lnxall_app/bin/ptprtc.lua\n")
	else
		fp:write("ExecStart=/bin/bash /usr/bin/ntpdrtc.sh\n")
	end

	fp:write("\n[Install]\nWantedBy=multi-user.target\n")
	fp:close(); fp = nil
	return true
end

local function mainfunc(arg1, arg2, arg3, arg4)
	local dowrite = false
	current_dns_load()
	if check_ntp_server(arg1, 1) then dowrite = true end
	if check_ntp_server(arg2, 2) then dowrite = true end
	if check_ntp_server(arg3, 3) then dowrite = true end
	if check_ntp_server(arg4, 4) then dowrite = true end
	if g_noptp then g_ptpdev = nil end

	if dowrite then
		local ddat = gfmt("config interface ntpd\n\toption ntp_server1 '%s'\n\toption ntp_server2 '%s'\n",
			g_ntpsvr[1], g_ntpsvr[2])
		if g_ntpsvr[3] then ddat = ddat .. gfmt("\toption ntp_server3 '%s'\n", g_ntpsvr[3]) end
		if g_ntpsvr[4] then ddat = ddat .. gfmt("\toption ntp_server4 '%s'\n", g_ntpsvr[4]) end
		if g_ptpdev then ddat = ddat .. gfmt("\toption ptp_device '%s'\n", g_ptpdev) end

		local fh = io.open(g_config, "wb")
		if not fh then
			io.stderr:write(gfmt("Error, failed to open file for writing: %s\n", g_config))
			io.stderr:flush()
			os.exit(1)
		end
		fh:write(ddat); fh:close(); fh = nil
		io.stdout:write("Restarting NTPD-RTC service...\n")
		io.stdout:flush()
	end

	local tmpfile = "/tmp/ntpdrtc.service"
	if write_ntpdrtc_service(tmpfile) and invoker.invoke(0, "diff", "-q", tmpfile, g_service) ~= 0 then
		invoker.invoke(0, "mv", "-vf", tmpfile, g_service)
		invoker.invoke(0, "cp", "-vf", g_service, "/usr/lib/systemd/system/")
		invoker.invoke(0, "systemctl", "daemon-reload")
		invoker.invoke(0, "systemctl", "enable", "ntpdrtc.service")
		invoker.invoke(0, "systemctl", "restart", "ntpdrtc.service")
	end
	invoker.unlink(tmpfile)

	io.stdout:write(gfmt("Current NTP Server settings:\n\tntp_server1: %s\n\tntp_server2: %s\n\tntp_server3: %s\n\tntp_server4: %s\n\tptp_device: %s\n",
		g_ntpsvr[1], g_ntpsvr[2], g_ntpsvr[3] or "", g_ntpsvr[4] or "", g_ptpdev or ""))
	io.stdout:flush()
end

mainfunc(arg[1], arg[2], arg[3], arg[4])
os.exit(0)
