-- LUALOCALS < ---------------------------------------------------------
local core, pairs, table, tostring, type
    = core, pairs, table, tostring, type
local table_concat
    = table.concat
-- LUALOCALS > ---------------------------------------------------------

------------------------------------------------------------------------
-- High-level UI/UX helpers for presenting standard interfaces and
-- interactions to a user
------------------------------------------------------------------------

local env = ...
local include = env.include

------------------------------------------------------------------------

local modname = core.get_current_modname()
local util = include("util")

local ux = {}

------------------------------------------------------------------------
-- Connection Config UI

-- ux.configure(options) - access stored configuration
-- modstore - load/save options from this mod storage
-- prefix - override default mod storage key prefix
-- manager - arclib manager to configure
-- player - show formspec to this player (nil to only load)
do
	-- Fields that are allowed to be edited in config
	local okfields = {
		url_target = true,
		url_proxy = true,
		login_slotname = true,
		login_password = true,
		enabled = true
	}

	-- Apply config immediately to both manager and storage
	-- (with changes for edits, without just to rehydrate)
	local function applyconfig(options, changes)
		local conf, save = options.store("config")
		if changes then
			for k, v in pairs(changes) do conf[k] = v end
			save()
		end
		local manager = options.manager
		local dirty
		for k, v in pairs(conf) do
			if okfields[k] then
				dirty = dirty or manager[k] ~= v
				manager[k] = v
			end
		end
		if dirty then manager:close() end
		if conf.enabled then manager:open() end
		return conf
	end

	-- UI form management
	local hooked
	local sendform
	local function form_received(_, formname, fields)
		if not fields.enable and not fields.disable then return end
		local found = hooked[formname]
		if not found then return end
		hooked[formname] = nil
		fields.enabled = fields.enable and true or false
		return sendform(found, applyconfig(found, fields))
	end
	local fsesc = core.formspec_escape
	sendform = function(options, conf)
		if not options.player then return end

		local formname = table_concat({
				modname,
				core.get_us_time(),
				util.generate_uuid()
			}, "_")
		local formspec = table_concat({
				"formspec_version[3]"
				.. "size[8,8.5]"
				.. "real_coordinates[true]",
				conf.enabled and "button[1.5,7.5;3,0.8;disable;Disconnect]"
				or ("label[0.5,0.5;Archipelago Server URL:]"
					.. "field[0.5,1;7,0.8;url_target;;"
					.. fsesc(conf.url_target or "wss://archipelago.gg:54321") .. "]"
					.. "label[0.5,2;Player Name:]"
					.. "field[0.5,2.5;7,0.8;login_slotname;;"
					.. fsesc(conf.login_slotname or "Player") .. "]"
					.. "label[0.5,3.5;Password:]"
					.. "pwdfield[0.5,4;7,0.8;login_password;"
					.. fsesc(conf.login_password or "") .. "]"
					.. "label[0.5,5;Websock Proxy URL:]"
					.. "field[0.5,5.5;7,0.8;url_proxy;;"
					.. fsesc(conf.url_proxy or "http://localhost:9839") .. "]"
					.. fsesc(tostring(not conf.enabled or false)) .. "]"
					.. "button[1.5,7.5;3,0.8;enable;Save & Connect]"),
				"button_exit[4.5,7.5;3,0.8;cancel;Cancel]"
			}, "")
		core.show_formspec(options.player, formname, formspec)
		if not hooked then
			hooked = {}
			core.register_on_player_receive_fields(form_received)
		end
		hooked[formname] = options
	end

	-- Exported API
	function ux.configure(options)
		local manager = options.manager
		options = util.deepcopy(options)
		options.manager = manager

		options.store = util.structstore(options.modstore, options.prefix)

		options.player = options.player and type(options.player) ~= "string"
		and options.player:get_player_name() or options.player

		return sendform(options, applyconfig(options))
	end
end

------------------------------------------------------------------------

return ux
