-- populated on tool loading
local tools_conf = {
	{
		name = "reload",
		kind = "action",
		label = "Reload",
		description = "Reload tools/*.lua and widgets/*.lua",
		handler = function() suppl_scan_tools(); suppl_scan_widgets(); end
	}
};

local function run_group(group, ch, wnd)
	local ad = active_display();
	local as = ad.selected;

-- hack around the problem with many menu paths written using the dumb
-- active_display().selected
	if (wnd) then
		ad.selected = wnd;
	end

-- this doesn't check / account for reattachments/migrations etc.
	if (group and type(group) == "table") then
		for k,v in ipairs(group) do
			if (type(v) == "string" and string.sub(v, 1, 1) == ch) then
				dispatch_symbol(v);
			end
		end
	end

-- and restore if we didn't destroy something, but this method isn't safe
-- from modification, and that's mentioned in the documentation
	if (as and as.canvas) then
		ad.selected = as;
	end
end

local function run_domain(group, pal, set)
	run_group(group, "!", nil);
	if (set) then
-- need a copy to survive UAF- self modification
		local lst = {};
		for k,v in ipairs(set) do
			table.insert(lst, v);
		end
		for i,wnd in ipairs(lst) do
			if (wnd.canvas) then
				run_group(group, "#", wnd);
			end
			apply_scheme(pal, wnd);
		end
	end
end

function ui_scheme_menu(scope, tgt)
	local res = {};
	if (not schemes) then
		scan_schemes();
		if (not schemes) then
			return;
		end
	end

	for k,v in ipairs(schemes) do
		table.insert(res, {
			name = v.name,
			label = v.label,
			kind = "action",
			handler = function()
				if (scope == "global") then
					local lst = {};
					for wnd in all_windows(true) do
						table.insert(lst, wnd);
					end
					run_domain(v.actions, v.palette, lst);
				elseif (scope == "display") then
					local lst = {};
					for i, wnd in ipairs(tgt.windows) do
						table.insert(lst, wnd);
					end
					run_domain(v.actions, nil, lst);
					run_domain(v.display, v.palette, lst);
				elseif (scope == "workspace") then
					local lst = {};
					for i,v in ipairs(tgt.children) do
						table.insert(lst, v);
					end
					run_domain(v.actions, nil, lst);
					run_domain(v.workspace, v.palette, lst);
				elseif (scope == "window") then
					run_domain(v.actions, nil, {tgt});
					run_domain(v.window, v.palette, {tgt});
				end
			end
		});
	end

	return res;
end

local config_browser = {
	{
		name = "preview_mode",
		label = "Preview",
		description = "Control what type of resources will be previewed",
		kind = "value",
		initial = function(ctx, val) return gconfig_get("browser_preview"); end,
		set = {"none", "image", "full"},
		handler = function(ctx, val)
			gconfig_set("browser_preview", val);
		end
	},
	{
		name = "preview_delay",
		label = "Timer",
		description = "The amount of 'hover' ticks before preview is activated",
		kind = "value",
		hint = "1..100",
		validator = gen_valid_num(1, 100),
		initial = function() return tostring(gconfig_get("browser_timer")); end,
		handler = function(ctx, val)
			gconfig_set("browser_timer", tonumber(val));
		end
	},
	{
		name = "preview_position",
		label = "Position",
		kind = "value",
		hint = "(0..100)",
		description = "Relative preview starting position for media clips (%)",
		validator = gen_valid_num(0, 100),
		initial = function() return tostring(gconfig_get("browser_position")); end,
		handler = function(ctx, val)
			gconfig_set("browser_position", tonumber(val));
		end
	},
	{
		name = "preview_trigger",
		label = "Trigger",
		description = "The event that should trigger the preview to activate",
		kind = "value",
		set = {"selection", "visibility"},
		initial = function() return gconfig_get("browser_trigger"); end,
		handler = function(ctx, val)
			gconfig_set("browser_trigger", val);
		end
	}
};

local rate_menu = {
	{
		name = "rlimit",
		label = "Rate Limit",
		initial = function() return gconfig_get("extcon_rlimit"); end,
		kind = "value",
		hint = "(0: disabled .. 1000)",
		description = "Impose a minimum time between external connections (ticks @25Hz)",
		validator = gen_valid_num(0, 1000),
		handler = function(ctx, val)
			gconfig_set("extcon_rlimit", tonumber(val));
		end
	},
	{
		name = "startdelay",
		label = "Grace Period",
		kind = "value",
		hint = "(0: disabled .. 1000)",
		initial = function() return gconfig_get("extcon_startdelay"); end,
		validator = gen_valid_num(0, 1000),
		description = "Disable rate limit for the first n ticks (@25Hz)",
		handler = function(ctx, val)
			gconfig_set("extcon_startdelay", tonumber(val));
		end
	},
	{
		name = "extwndlim",
		label = "External Windows Limit",
		kind = "value",
		initial = function() return gconfig_get("extcon_wndlimit"); end,
		validator = gen_valid_num(0, 1000),
		hint = "(0: disabled .. 1000)",
		description = "Limit the number of windows with an external connection source",
		handler = function(ctx, val)
			gconfig_set("extcon_wndlimit", tonumber(val));
		end
	},
	{
		name = "subseglimit",
		label = "Window Subsegment Limit",
		kind = "value",
    hint = "(0: disabled, .. 100)",
		description = "Limit the number of subsegments a client may have active",
		initial = function() return gconfig_get("subwnd_limit"); end,
		validator = gen_valid_num(0, 100),
		handler = function(ctx, val)
			gconfig_set("subwnd_limit", tonumber(val));
		end
	}
};

local durden_system = {
	{
		name = "cpath",
		label = "Connection Path",
		kind = "value",
		hint = "(a..Z_)",
		validator = strict_fname_valid,
		initial = function() local path = gconfig_get("extcon_path");
			return path == ":disabled" and "[disabled]" or path;
		end,
		description = "Change the name of the socket used to connect external clients",
		handler = function(ctx, val)
			if #val == 0 then
				val = ":disabled"
			end

			gconfig_set("extcon_path", val, true);
		end
	},
	{
		name = "rate_limit",
		label = "Rate Limiting",
		kind = "action",
		submenu = true,
		description = "Settings for rate limiting external resource allocations",
		handler = rate_menu
	},
	{
		name = "control",
		label = "Control",
		kind = "value",
		hint = "(a..Z_)",
		validator = strict_fname_valid,
		description = "Set the control socket name (ipc/XXX) for external UI control",
		initial = function() local path = gconfig_get("control_path");
			return path == ":disabled" and "[disabled]" or path;
		end,
		handler = function(ctx, val)
			if (string.len(val) == 0) then
				val = ":disabled";
			end
			gconfig_set("control_path", val, true);
		end
	},
	{
		name = "source_color",
		label = "Color/Gamma Sync",
		kind = "value",
		description = "Control permissions for external color managers",
		initial = function() return gconfig_get("gamma_access"); end,
		set = {"none", "trusted", "all"},
		handler = function(ctx, val)
			gconfig_set("gamma_access", val);
		end
	},
	{
		name = "gpuauth",
		label = "GPU delegation",
		kind = "value",
		description = "Control permission for external privileged GPU access",
		initial = function() return gconfig_get("gpu_auth"); end,
		set = {"none", "full"},
		handler = function(ctx, val)
			gconfig_set("gpu_auth", val);
		end
	},
	{
		name = "bridgeclip",
		label = "Clipboard Bridge",
		kind = "value",
		description = "Control permissions for external clipboard managers",
		initial = function() return gconfig_get("clipboard_access"); end,
		set = {"none", "full", "passive", "active"},
		handler = function(ctx, val)
			gconfig_set("clipboard_access", val);
		end
	},
	{
		name = "debuglevel",
		label = "Debug Level",
		kind = "value",
		validator = gen_valid_num(0, 5),
		initial = function() return tostring(DEBUGLEVEL); end,
		hint = "(0=off, 5=max)",
		description = "(advanced/debug) Change the global debuglevel",
		handler = function(ctx, val)
			DEBUGLEVEL = tonumber(val);
		end
	}
};

local recmenu = {
	{
	name = "fps",
	label = "Framerate",
	kind = "value",
	hint = "(10..60)",
	description = "Change the nominal video encoding samplerate",
	validator = gen_valid_num(10, 60),
	initial = function() return tostring(gconfig_get("enc_fps")); end,
	handler = function(ctx, val)
		gconfig_set("enc_fps", tonumber(val));
	end
	},
	{
	name = "preset",
	label = "Video Quality Preset",
	kind = "value",
	hint = "(0:disable..10:max, overrides bitrate)",
	description = "Change the targeted video quality approximation level",
	validator = gen_valid_num(0, 10),
	initial = function() return tostring(gconfig_get("enc_vpreset")); end,
	handler = function(ctx, val)
		gconfig_set("enc_vpreset", tonumber(val));
		gconfig_set("enc_vbr", tonumber(val) == 0 and 800 or 0);
	end
	},
	{
	name = "vbr",
	label = "Video Bitrate",
	kind = "value",
	hint = "(kbit/s, overrides preset)",
	description = "Change the ideal video bitrate",
	validator = gen_valid_num(100, 10000),
	initial = function() return tostring(gconfig_get("enc_vbr")); end,
	handler = function(ctx, val)
		gconfig_set("enc_vpreset", 0);
		gconfig_set("enc_vbr", tonumber(val));
	end
	},
	{
	name = "presilence",
	label = "Audio Presilence",
	kind = "value",
	hint = "(samples)",
	description = "Prefill audio buffers with n samples of silence",
	validator = gen_valid_num(0, 16384),
	initial = function() return tostring(gconfig_get("enc_presilence")); end,
	handler = function(ctx, val) gconfig_set("enc_presilence", tonumber(val)); end
	}
};

return {
	{
		name = "visual",
		label = "Visual",
		kind = "action",
		submenu = true,
		description = "UI elements, colors and effects",
		handler = system_load("menus/global/visual.lua")()
	},
	{
		name = "wspaces",
		label = "Workspaces",
		kind = "action",
		submenu = true,
		description = "Workspace layout mode settings",
		handler = system_load("menus/global/workspaces.lua")()
	},
	{
		name = "timers",
		label = "Timers",
		kind = "action",
		submenu = true,
		description = "View / Manage active timers",
		handler = system_load("menus/global/timer.lua")()
	},
	{
		name = "notifications",
		label = "Notifications",
		kind = "action",
		submenu = true,
		description = "Controls for the notification subsytem",
		handler = system_load("menus/global/notification.lua")()
	},
	{
		name = "led",
		label = "LEDs",
		kind = "action",
		submenu = true,
		description = "LED device controls",
		eval = function()
			return #ledm_devices("passive") > 0;
		end,
		handler = system_load("menus/global/led.lua")()
	},
	{
		name = "system",
		label = "System",
		kind = "action",
		submenu = true,
		description = "System and Security specific controls",
		handler = durden_system
	},
	{
		name = "recording",
		label = "Recording",
		kind = "action",
		description = "Media recording parameters (framerate, bitrate, ...)",
		submenu = true,
		handler = recmenu
	},
	{
		name = "terminal",
		label = "Terminal",
		kind = "action",
		submenu = true,
		description = "Command-Line Interface (CLI) options",
		eval = function()
			return string.match(FRAMESERVER_MODES, "terminal") ~= nil;
		end,
		handler = system_load("menus/global/terminal.lua")()
	},
	{
		name = "browser",
		label = "Browser",
		kind = "action",
		submenu = true,
		description = "Resource browser options",
		handler = config_browser
	},
	{
		name = "scheme",
		label = "Scheme",
		kind = "action",
		submenu = true,
		description = "Select a color/UI scheme",
		eval = function()	return #(ui_scheme_menu()) > 0; end,
		handler = function() return ui_scheme_menu("global"); end
	},
	{
		name = "tools",
		label = "Tools",
		kind = "action",
		description = "Custom tool specific settings",
		submenu = true,
		handler = tools_conf
	},
	{
		name = "statusbar",
		label = "Statusbar",
		kind = "action",
		submenu = true,
		description = "Change Task/Statusbar look and feel",
		handler = system_load("menus/global/statusbar.lua")(),
	},
	{
		name = "titlebar",
		label = "Titlebar",
		kind = "action",
		submenu = true,
		description = "Change Window titlebar defaults",
		handler = system_load("menus/global/titlebar.lua")()
	},
	{
		name = "hud",
		label = "HUD",
		kind = "action",
		submenu = true,
		description = "Change HUD look and feel",
		handler = system_load("menus/global/hud.lua")(),
	},
	{
		name = "x11",
		label = "X11",
		kind = "action",
		submenu = true,
		description = "Change how X11 clients over Xarcan behaves",
		handler = system_load("menus/global/x11.lua")()
	},
	{
		name = "commit",
		label = "Commit",
		kind = "action",
		description = "Store all pending configuration changes",
		handler = function()
			SYMTABLE:store_translation();
			gconfig_shutdown();
		end
	}
};
