-- Copyright (C) 2019 github.com/peter-tank
-- Licensed to the public under the GNU General Public License v3.

local m, s, o, _, v, created
local fs = require "nixio.fs"
local sys = require "luci.sys"
local ds = require "luci.tools.dnscrypt".init()
local cfg, sid = arg[1], arg[2]

local protocol = {
	"DNSCrypt",
	"DoH",
}

function typicalmsg(self)
	if not ds:typicalcfg(cfg) then
		local c, init, exec = luci.model.uci.cursor()
		c:load("ucitrack")
		init = c:get_first("ucitrack", self.config, "init", "null")
		exec = c:get_first("ucitrack", self.config, "exec", "null")
		c:unload("ucitrack")
		local error = {}
		table.insert(error,  translate("Not a typical dnscrypt-proxy resolvers configure!") .. " Original for: [%s]" % init)
		table.insert(error,  translate("Additional changes on apply:"))
		table.insert(error,  "init script: %s --> %s" % {init, "null"})
		table.insert(error,  "exec script: %s --> %s %s" % {exec, "/etc/init.d/dnscrypt-proxy_resolvers", self.config})
		self.error = self.error and self.error or {}
		self.error["global"] = self.error["global"] and table(self.error["global"], error) or error
	end
end

function list_dns(m, cfg)
-- [[ Source Setting ]]--
s = m:section(NamedSection, "global", "source",  translate("Configuration -: ") .. cfg)
s.description = translate("Update the resolvers here by a new apply. Permently cover your modifications on specific resolve, if the source resolved successfully.")
s.anonymous = false
s.addremove = true
typicalmsg(s)
-- section might not exist
function s.cfgvalue(self, section)
	if not self.map:get(section) then
 	 self.map:set(section, nil, self.sectiontype)
	end
	return self.map:get(section)
end
function s.remove(self, section)
 	self.map:del(section)
 	self.map.proceed = true
 	return self.map.uci:delete_all(self.config, "dnscrypt", function(section) return true end)
end

o = s:option(Value, "urls", translate("Source URL"), translate("Split MultiValues by a comma"))
o.rmempty = true
o.default = "https://download.dnscrypt.info/dnscrypt-resolvers/v3/public-resolvers.md"
o.placeholder = "https://xxx.xxx.xxx/public-resolvers.md"

--o = s:option(Value, "cache_file", translate("Cache File"), translate("Change this only on duplicating this resolver to another source when retrieving: ") .. "/usr/share/dnscrypt-proxy/{*}.md")
--o.default = "public-resolvers.md"
--o.placeholder = "eg: custom.md"
--o.rmempty = false

o = s:option(Value, "details_json", translate("Details File URL"), translate("Detailed resolvers JSON file `dnscrypt-proxy -json --list-all` or: ") .. "https://download.dnscrypt.info/dnscrypt-resolvers/json/{*}.json")
o.default = "https://download.dnscrypt.info/dnscrypt-resolvers/json/public-resolvers.json"
o.placeholder = "eg: custom.json"
o.rmempty = true

o = s:option(Flag, "cache_mode", translate("No resolvers update."), translate("Force cached resolvers only: ").. "/usr/share/dnscrypt-proxy/{.*}[.md|.minisig|.json]")
o.default = true
o.optional = false
o.rmempty = false

o = s:option(Flag, "selfsign", translate("Selfsign Resolvers"), translate("Mostly useful for build your own resolvers list on net probe fails. minisign binary needed: ") .. "https://github.com/peter-tank/openwrt-minisign")
o.default = false
o.optional = false
o.rmempty = true
o:depends("cache_mode", true)

o = s:option(Value, "minisign_key", translate("MiniSign Key"), translate("Resolvers singed by: ") .. "https://download.dnscrypt.info/dnscrypt-resolvers/v3/minisign.pub")
o.default = "RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3"
o.optional = false
o.placeholder = o.default
o.rmempty = false
o:depends("selfsign", false)

o = s:option(Value, "prefix", translate("Prefix"), translate("Change this only on filtering the resolvers: "))
o.optional = true
o.placeholder = "eg: quad9-"
o.rmempty = true

o = s:option(Value, "format", translate("Version"), translate("Configure file version."))
o.optional = true
o.default = "v3"
o.rmempty = true

s = m:section(TypedSection, 'dnscrypt', translate("DNSCrypt Resolver Info"))
s.anonymous = false
s.addremove = true
s.sortable = false
s.template = "cbi/tblsection"
s.extedit = luci.dispatcher.build_url("admin/services/dnscrypt-proxy/dnscrypt-resolvers", cfg, "%s")
function s.create(self, name)
		AbstractSection.create(self, name)
		luci.http.redirect( self.extedit:format(name) )
end

s:option(DummyValue, "country", translate("Country"))
s:option(DummyValue, "proto", translate("Protocol"))
s:option(DummyValue, "name", translate("Resolver"))
s:option(DummyValue, "description", translate("Description"))
s:option(Flag, "ipv6", translate("IPv6"))
s:option(Flag, "dnssec", translate("DNSSec Validation"))
s:option(Flag, "nolog", translate("NoLog"))
s:option(Flag, "nofilter", translate("NoFilter"))
s:option(DummyValue, "addrs", translate("Address"))
s:option(DummyValue, "ports", translate("Port"))
-- s:option(DummyValue, "stamp", translate("Stamp"))
end 


-- [[ Servers Setting ]]--
function edit_list(m)
s = m:section(NamedSection, sid, "dnscrypt", translate("DNSCrypt Resolver Editing - ") .. sid)
s.anonymous = true
s.addremove   = true

o = s:option(Value, "name", translate("Resolver"))
o.default = sid
o.rmempty = false

o = s:option(Value, "country", translate("Country"))
o.default = "China"

o = s:option(Value, "proto", translate("Protocol"))
for _, v in ipairs(protocol) do o:value(v) end
o.default = "DNSCrypt"
o.rmempty = false

o = s:option(Value, "description", translate("Description"))
o.default = "Dns-over-HTTPS protocol . Non-logging, supports DNSSEC. By https://www.google.com"

o = s:option(Flag, "dnssec", translate("DNSSec Validation"))
o.rmempty = false

o = s:option(Flag, "ipv6", translate("IPv6"))
o.rmempty = false

o = s:option(Flag, "nolog", translate("NoLog"))
o.rmempty = false

o = s:option(Flag, "nofilter", translate("NoFilter"))
o.rmempty = false

o = s:option(Value, "addrs", translate("Resolver Address"), translate("Split MultiValues by a comma"))
o.placeholder = "eg: 8.8.8.8,8.8.4.4"
o.rmempty = false

o = s:option(Value, "ports", translate("Port"), translate("Split MultiValues by a comma"))
o.placeholder = "eg: 443,5353"
o.rmempty = false

o = s:option(Value, "location", translate("Geography Coordinates"))
o.placeholder = "eg: 33.032501, 83.895699"

o = s:option(Value, "stamp", translate("Stamp"))
o.placeholder = "eg: sdns://AgcAAAAAAAAADjExNi4yMDMuNzAuMTU2ID4aGg9sU_PpekktVwhLW5gHBZ7gV6sVBYdv2D_aPbg4EWRvaC5kbnN3YXJkZW4uY29tCy91bmNlbnNvcmVk"
o.rmempty = false
end

m = Map(cfg, translate("DNSCrypt Resolvers Manage"))
m.on_before_commit = function (self)
	local exec = "/etc/init.d/dnscrypt-proxy_resolvers"
	local section, stype, on_remove = "global", "source", false
	local sec = "DNSCrypt_resolvers_" .. self.config:gsub("[^%w_]", "_")
	local c = luci.model.uci.cursor()
	local changes = c:changes()
	self.redirect = luci.dispatcher.build_url("admin/services/dnscrypt-proxy/dnscrypt-resolvers", self.config)
	for r, tbl in pairs(changes or next(changes)) do
	 	for s, os in pairs(tbl) do
	 		if os['.type'] and os['.type'] == "" and r == self.config and s == section then on_remove = true end
	 	end
	end
	c:load("ucitrack")
	if self:get(section, "urls") and not on_remove then
	 	if not c:get_first("ucitrack", self.config, "exec", nil) then
	 		c:delete_all("ucitrack", self.config, function(section) return true end)
	 		sec = c:section("ucitrack", self.config, sec)
	 		c:set("ucitrack", sec, "init", "null")
	 		c:set("ucitrack", sec, "test", "0")
	 		c:set("ucitrack", sec, "exec", "%s %s" % {exec, self.config})
	 		c:save("ucitrack"); c:commit("ucitrack");
	 	end
	else
	 	if c:get_first("ucitrack", self.config, "exec", nil) == ("%s %s" %{exec, self.config}) then
	  	c:delete_all("ucitrack", self.config, function(section) return true end)
	  	c:save("ucitrack"); c:commit("ucitrack");
	 	end
	 	self.redirect = luci.dispatcher.build_url("admin/services/dnscrypt-proxy/dnscrypt-resolvers")
	end
	c:unload("ucitrack")
	luci.util.exec("/etc/init.d/ucitrack reload")
end

if cfg then
	if sid == nil then list_dns(m, cfg) else edit_list(m, cfg) end
else
	luci.http.redirect(luci.dispatcher.build_url("admin/services/dnscrypt-proxy/dnscrypt-resolvers"))
	return
end

return m
