local t=LibStub("\067\097\108\108\098\097\099\107\072\097\110\100\108\101\114-\049\046\048")local M,u="\065\099\101\067\111\110\102\105\103\082\101\103\105\115\116\114\121-\051\046\048",21 local r=LibStub:NewLibrary(M,u)if not r then return end r.tables=r.tables or{}if not r.callbacks then r.callbacks=t:New(r)end local W,d=table.insert,table.concat local g,V=string.find,string.match local a,L,e,X=type,tostring,select,pairs local S,Q=error,assert r.validated={cmd={},dropdown={};dialog={}}local function A(t,u,...)local r={}for t=e("\035",...),1,-1 do W(r,e(t,...))end S(M..("\058\086\097\108\105\100\097\116\101\079\112\116\105\111\110\115\084\097\098\108\101\040\041\058 "..(d(r,"\046")..t)),u+2)end local C={string=true,_="\115\116\114\105\110\103"}local b={string=true,["\102\117\110\099\116\105\111\110"]=true,_="\115\116\114\105\110\103 \111\114 \102\117\110\099\114\101\102"}local p={table=true,_="\116\097\098\108\101"}local R={table=true;string=true;["\102\117\110\099\116\105\111\110"]=true,_="\109\101\116\104\111\100\110\097\109\101\044 \102\117\110\099\114\101\102 \111\114 \116\097\098\108\101"}local l={["\110\105\108"]=true,string=true,_="\115\116\114\105\110\103"}local v={["\110\105\108"]=true,string=true,["\102\117\110\099\116\105\111\110"]=true,_="\115\116\114\105\110\103 \111\114 \102\117\110\099\114\101\102"}local o={["\110\105\108"]=true;string=true,number=true,["\102\117\110\099\116\105\111\110"]=true,_="\115\116\114\105\110\103\044 \110\117\109\098\101\114 \111\114 \102\117\110\099\114\101\102"}local y={["\110\105\108"]=true,number=true,_="\110\117\109\098\101\114"}local k={["\110\105\108"]=true;string=true;["\102\117\110\099\116\105\111\110"]=true;boolean={[false]=true},_="\109\101\116\104\111\100\110\097\109\101\044 \102\117\110\099\114\101\102 \111\114 \102\097\108\115\101"}local f={["\110\105\108"]=true;string=true,["\102\117\110\099\116\105\111\110"]=true,number=true;_="\109\101\116\104\111\100\110\097\109\101\044 \102\117\110\099\114\101\102 \111\114 \110\117\109\098\101\114"}local z={["\110\105\108"]=true,string=true,["\102\117\110\099\116\105\111\110"]=true;table=true;_="\109\101\116\104\111\100\110\097\109\101\044 \102\117\110\099\114\101\102 \111\114 \116\097\098\108\101"}local I={["\110\105\108"]=true;string=true,["\102\117\110\099\116\105\111\110"]=true,boolean=true;_="\109\101\116\104\111\100\110\097\109\101\044 \102\117\110\099\114\101\102 \111\114 \098\111\111\108\101\097\110"}local P={["\110\105\108"]=true;table=true;_="\116\097\098\108\101"}local Z={["\110\105\108"]=true;boolean=true,_="\098\111\111\108\101\097\110"}local G={["\110\105\108"]=true;boolean=true;number=true;_="\098\111\111\108\101\097\110 \111\114 \110\117\109\098\101\114"}local F={["\110\105\108"]=true,string=true;number=true,_="\115\116\114\105\110\103 \111\114 \110\117\109\098\101\114"}local B={type=C;name=b,desc=v,descStyle=l;order=f,validate=k;confirm=I,confirmText=l;disabled=I;hidden=I,guiHidden=I;dialogHidden=I,dropdownHidden=I;cmdHidden=I;tooltipHyperlink=v;icon=o;iconCoords=z,handler=P;get=k,set=k,func=k;arg={["\042"]=true};width=F}local J={header={control=l;dialogControl=l;dropdownControl=l},description={image=o;imageCoords=z;imageHeight=y;imageWidth=y,fontSize=v,control=l;dialogControl=l;dropdownControl=l};group={args=p,plugins=P;inline=Z,cmdInline=Z;guiInline=Z,dropdownInline=Z;dialogInline=Z;childGroups=l},execute={image=o;imageCoords=z;imageHeight=y;imageWidth=y;control=l,dialogControl=l,dropdownControl=l};input={pattern=l,usage=l,control=l,dialogControl=l;dropdownControl=l,multiline=G},toggle={tristate=Z,image=o,imageCoords=z;control=l,dialogControl=l;dropdownControl=l},tristate={};range={min=y,softMin=y,max=y;softMax=y,step=y,bigStep=y,isPercent=Z,control=l;dialogControl=l,dropdownControl=l};select={values=R,sorting=z,style={["\110\105\108"]=true;string={dropdown=true,radio=true},_="\115\116\114\105\110\103\058 \'\100\114\111\112\100\111\119\110\' \111\114 \'\114\097\100\105\111\'"};control=l,dialogControl=l;dropdownControl=l;itemControl=l},multiselect={values=R;style=l,tristate=Z;control=l,dialogControl=l;dropdownControl=l},color={hasAlpha=I;control=l;dialogControl=l,dropdownControl=l},keybinding={control=l;dialogControl=l;dropdownControl=l}}local function H(t,M,...)M=(M or 0)+1 if a(t)~="\115\116\114\105\110\103"then A("\091"..(L(t).."\093 - \107\101\121 \105\115 \110\111\116 \097 \115\116\114\105\110\103"),M,...)end if g(t,"\091\037\099\127\093")then A("\091"..(L(t).."\093 - \107\101\121 \110\097\109\101 \099\111\110\116\097\105\110\101\100 \099\111\110\116\114\111\108 \099\104\097\114\097\099\116\101\114\115"),M,...)end end local function E(t,M,u,...)u=(u or 0)+1 local r=M[a(t)]or M["\042"]if not r then A("\058 \101\120\112\101\099\116\101\100 \097 "..(M._..("\044 \103\111\116 \'"..(L(t).."\'"))),u,...)end if a(r)=="\116\097\098\108\101"then if not r[t]then A("\058 \100\105\100 \110\111\116 \101\120\112\101\099\116 "..(a(t)..(" \118\097\108\117\101 \'"..(L(t).."\'"))),u,...)end end end local function m(t,M,...)M=(M or 0)+1 if a(t)~="\116\097\098\108\101"then A("\058 \101\120\112\101\099\116\101\100 \097 \116\097\098\108\101\044 \103\111\116 \097 "..a(t),M,...)end if a(t.type)~="\115\116\114\105\110\103"then A("\046\116\121\112\101\058 \101\120\112\101\099\116\101\100 \097 \115\116\114\105\110\103\044 \103\111\116 \097 "..a(t.type),M,...)end local u=J[t.type]if not u then A("\046\116\121\112\101\058 \117\110\107\110\111\119\110 \116\121\112\101 \'"..(t.type.."\'"),M,...)end for t,r in X(t)do if not(u[t]or B[t])then A("\058 \117\110\107\110\111\119\110 \112\097\114\097\109\101\116\101\114",M,L(t),...)end end for u,r in X(B)do E(t[u],r,M,u,...)end for u,r in X(u)do E(t[u],r,M,u,...)end if t.type=="\103\114\111\117\112"then for t,u in X(t.args)do H(t,M,"\097\114\103\115",...)m(u,M,t,"\097\114\103\115",...)end if t.plugins then for t,u in X(t.plugins)do if a(u)~="\116\097\098\108\101"then A("\058 \101\120\112\101\099\116\101\100 \097 \116\097\098\108\101\044 \103\111\116 \'"..(L(u).."\'"),M,L(t),"\112\108\117\103\105\110\115",...)end for u,r in X(u)do H(u,M,L(t),"\112\108\117\103\105\110\115",...)m(r,M,u,L(t),"\112\108\117\103\105\110\115",...)end end end end end function r.ValidateOptionsTable(r,t,M,u)u=(u or 0)+1 M=M or"\079\112\116\105\111\110\115\116\097\098\108\101"if not t.name then t.name=M end m(t,u,M)end function r.NotifyChange(M,t)if not r.tables[t]then return end r.callbacks:Fire("\067\111\110\102\105\103\084\097\098\108\101\067\104\097\110\103\101",t)end local function U(t,u,r)r=(r or 0)+2 if t~="\099\109\100"and(t~="\100\114\111\112\100\111\119\110"and t~="\100\105\097\108\111\103")then S(M.."\058 \082\101\113\117\101\115\116\105\110\103 \111\112\116\105\111\110\115 \116\097\098\108\101\058 \'\117\105\084\121\112\101\' - \105\110\118\097\108\105\100 \099\111\110\102\105\103\117\114\097\116\105\111\110 \085\073 \116\121\112\101\044 \101\120\112\101\099\116\101\100 \'\099\109\100\'\044 \'\100\114\111\112\100\111\119\110\' \111\114 \'\100\105\097\108\111\103\'",r)end if not V(u,"\091\065-\090\097-\122\093\037-\091\048-\057\093")then S(M.."\058 \082\101\113\117\101\115\116\105\110\103 \111\112\116\105\111\110\115 \116\097\098\108\101\058 \'\117\105\078\097\109\101\' - \098\097\100\108\121 \102\111\114\109\097\116\116\101\100 \111\114 \109\105\115\115\105\110\103 \118\101\114\115\105\111\110 \110\117\109\098\101\114\046 \069\120\112\101\099\116\101\100 \101\046\103\046 \'\077\121\076\105\098-\049\046\050\'",r)end end function r.RegisterOptionsTable(d,t,u,W)if a(u)=="\116\097\098\108\101"then if u.type~="\103\114\111\117\112"then S(M.."\058 \082\101\103\105\115\116\101\114\079\112\116\105\111\110\115\084\097\098\108\101\040\097\112\112\078\097\109\101\044 \111\112\116\105\111\110\115\041\058 \'\111\112\116\105\111\110\115\' - \109\105\115\115\105\110\103 \116\121\112\101\061\'\103\114\111\117\112\' \109\101\109\098\101\114 \105\110 \114\111\111\116 \103\114\111\117\112",2)end r.tables[t]=function(M,d,g)g=(g or 0)+1 U(M,d,g)if not r.validated[M][t]and not W then r:ValidateOptionsTable(u,t,g)r.validated[M][t]=true end return u end elseif a(u)=="\102\117\110\099\116\105\111\110"then r.tables[t]=function(M,d,g)g=(g or 0)+1 U(M,d,g)local V=Q(u(M,d,t))if not r.validated[M][t]and not W then r:ValidateOptionsTable(V,t,g)r.validated[M][t]=true end return V end else S(M.."\058 \082\101\103\105\115\116\101\114\079\112\116\105\111\110\115\084\097\098\108\101\040\097\112\112\078\097\109\101\044 \111\112\116\105\111\110\115\041\058 \'\111\112\116\105\111\110\115\' - \101\120\112\101\099\116\101\100 \116\097\098\108\101 \111\114 \102\117\110\099\116\105\111\110 \114\101\102\101\114\101\110\099\101",2)end end function r.IterateOptionsTables(t)return X(r.tables)end function r.GetOptionsTable(W,t,M,u)local d=r.tables[t]if not d then return nil end if M then return d(M,u,1)else return d end end
--- AceConfigRegistry-3.0 handles central registration of options tables in use by addons and modules.\\
-- Options tables can be registered as raw tables, OR as function refs that return a table.\\
-- Such functions receive three arguments: "uiType", "uiName", "appName". \\
-- * Valid **uiTypes**: "cmd", "dropdown", "dialog". This is verified by the library at call time. \\
-- * The **uiName** field is expected to contain the full name of the calling addon, including version, e.g. "FooBar-1.0". This is verified by the library at call time.\\
-- * The **appName** field is the options table name as given at registration time \\
--
-- :IterateOptionsTables() (and :GetOptionsTable() if only given one argument) return a function reference that the requesting config handling addon must call with valid "uiType", "uiName".
-- @class file
-- @name AceConfigRegistry-3.0
-- @release $Id: AceConfigRegistry-3.0.lua 1296 2022-11-04 18:50:10Z nevcairiel $
local CallbackHandler = LibStub("CallbackHandler-1.0")

local MAJOR, MINOR = "AceConfigRegistry-3.0", 21
local AceConfigRegistry = LibStub:NewLibrary(MAJOR, MINOR)

if not AceConfigRegistry then return end

AceConfigRegistry.tables = AceConfigRegistry.tables or {}

if not AceConfigRegistry.callbacks then
	AceConfigRegistry.callbacks = CallbackHandler:New(AceConfigRegistry)
end

-- Lua APIs
local tinsert, tconcat = table.insert, table.concat
local strfind, strmatch = string.find, string.match
local type, tostring, select, pairs = type, tostring, select, pairs
local error, assert = error, assert

-----------------------------------------------------------------------
-- Validating options table consistency:


AceConfigRegistry.validated = {
	-- list of options table names ran through :ValidateOptionsTable automatically.
	-- CLEARED ON PURPOSE, since newer versions may have newer validators
	cmd = {},
	dropdown = {},
	dialog = {},
}



local function err(msg, errlvl, ...)
	local t = {}
	for i=select("#",...),1,-1 do
		tinsert(t, (select(i, ...)))
	end
	error(MAJOR..":ValidateOptionsTable(): "..tconcat(t,".")..msg, errlvl+2)
end


local isstring={["string"]=true, _="string"}
local isstringfunc={["string"]=true,["function"]=true, _="string or funcref"}
local istable={["table"]=true,   _="table"}
local ismethodtable={["table"]=true,["string"]=true,["function"]=true,   _="methodname, funcref or table"}
local optstring={["nil"]=true,["string"]=true, _="string"}
local optstringfunc={["nil"]=true,["string"]=true,["function"]=true, _="string or funcref"}
local optstringnumberfunc={["nil"]=true,["string"]=true,["number"]=true,["function"]=true, _="string, number or funcref"}
local optnumber={["nil"]=true,["number"]=true, _="number"}
local optmethodfalse={["nil"]=true,["string"]=true,["function"]=true,["boolean"]={[false]=true},  _="methodname, funcref or false"}
local optmethodnumber={["nil"]=true,["string"]=true,["function"]=true,["number"]=true,  _="methodname, funcref or number"}
local optmethodtable={["nil"]=true,["string"]=true,["function"]=true,["table"]=true,  _="methodname, funcref or table"}
local optmethodbool={["nil"]=true,["string"]=true,["function"]=true,["boolean"]=true,  _="methodname, funcref or boolean"}
local opttable={["nil"]=true,["table"]=true,  _="table"}
local optbool={["nil"]=true,["boolean"]=true,  _="boolean"}
local optboolnumber={["nil"]=true,["boolean"]=true,["number"]=true,  _="boolean or number"}
local optstringnumber={["nil"]=true,["string"]=true,["number"]=true, _="string or number"}

local basekeys={
	type=isstring,
	name=isstringfunc,
	desc=optstringfunc,
	descStyle=optstring,
	order=optmethodnumber,
	validate=optmethodfalse,
	confirm=optmethodbool,
	confirmText=optstring,
	disabled=optmethodbool,
	hidden=optmethodbool,
		guiHidden=optmethodbool,
		dialogHidden=optmethodbool,
		dropdownHidden=optmethodbool,
	cmdHidden=optmethodbool,
	tooltipHyperlink=optstringfunc,
	icon=optstringnumberfunc,
	iconCoords=optmethodtable,
	handler=opttable,
	get=optmethodfalse,
	set=optmethodfalse,
	func=optmethodfalse,
	arg={["*"]=true},
	width=optstringnumber,
}

local typedkeys={
	header={
		control=optstring,
		dialogControl=optstring,
		dropdownControl=optstring,
	},
	description={
		image=optstringnumberfunc,
		imageCoords=optmethodtable,
		imageHeight=optnumber,
		imageWidth=optnumber,
		fontSize=optstringfunc,
		control=optstring,
		dialogControl=optstring,
		dropdownControl=optstring,
	},
	group={
		args=istable,
		plugins=opttable,
		inline=optbool,
			cmdInline=optbool,
			guiInline=optbool,
			dropdownInline=optbool,
			dialogInline=optbool,
		childGroups=optstring,
	},
	execute={
		image=optstringnumberfunc,
		imageCoords=optmethodtable,
		imageHeight=optnumber,
		imageWidth=optnumber,
		control=optstring,
		dialogControl=optstring,
		dropdownControl=optstring,
	},
	input={
		pattern=optstring,
		usage=optstring,
		control=optstring,
		dialogControl=optstring,
		dropdownControl=optstring,
		multiline=optboolnumber,
	},
	toggle={
		tristate=optbool,
		image=optstringnumberfunc,
		imageCoords=optmethodtable,
		control=optstring,
		dialogControl=optstring,
		dropdownControl=optstring,
	},
	tristate={
	},
	range={
		min=optnumber,
		softMin=optnumber,
		max=optnumber,
		softMax=optnumber,
		step=optnumber,
		bigStep=optnumber,
		isPercent=optbool,
		control=optstring,
		dialogControl=optstring,
		dropdownControl=optstring,
	},
	select={
		values=ismethodtable,
		sorting=optmethodtable,
		style={
			["nil"]=true,
			["string"]={dropdown=true,radio=true},
			_="string: 'dropdown' or 'radio'"
		},
		control=optstring,
		dialogControl=optstring,
		dropdownControl=optstring,
		itemControl=optstring,
	},
	multiselect={
		values=ismethodtable,
		style=optstring,
		tristate=optbool,
		control=optstring,
		dialogControl=optstring,
		dropdownControl=optstring,
	},
	color={
		hasAlpha=optmethodbool,
		control=optstring,
		dialogControl=optstring,
		dropdownControl=optstring,
	},
	keybinding={
		control=optstring,
		dialogControl=optstring,
		dropdownControl=optstring,
	},
}

local function validateKey(k,errlvl,...)
	errlvl=(errlvl or 0)+1
	if type(k)~="string" then
		err("["..tostring(k).."] - key is not a string", errlvl,...)
	end
	if strfind(k, "[%c\127]") then
		err("["..tostring(k).."] - key name contained control characters", errlvl,...)
	end
end

local function validateVal(v, oktypes, errlvl,...)
	errlvl=(errlvl or 0)+1
	local isok=oktypes[type(v)] or oktypes["*"]

	if not isok then
		err(": expected a "..oktypes._..", got '"..tostring(v).."'", errlvl,...)
	end
	if type(isok)=="table" then		-- isok was a table containing specific values to be tested for!
		if not isok[v] then
			err(": did not expect "..type(v).." value '"..tostring(v).."'", errlvl,...)
		end
	end
end

local function validate(options,errlvl,...)
	errlvl=(errlvl or 0)+1
	-- basic consistency
	if type(options)~="table" then
		err(": expected a table, got a "..type(options), errlvl,...)
	end
	if type(options.type)~="string" then
		err(".type: expected a string, got a "..type(options.type), errlvl,...)
	end

	-- get type and 'typedkeys' member
	local tk = typedkeys[options.type]
	if not tk then
		err(".type: unknown type '"..options.type.."'", errlvl,...)
	end

	-- make sure that all options[] are known parameters
	for k,v in pairs(options) do
		if not (tk[k] or basekeys[k]) then
			err(": unknown parameter", errlvl,tostring(k),...)
		end
	end

	-- verify that required params are there, and that everything is the right type
	for k,oktypes in pairs(basekeys) do
		validateVal(options[k], oktypes, errlvl,k,...)
	end
	for k,oktypes in pairs(tk) do
		validateVal(options[k], oktypes, errlvl,k,...)
	end

	-- extra logic for groups
	if options.type=="group" then
		for k,v in pairs(options.args) do
			validateKey(k,errlvl,"args",...)
			validate(v, errlvl,k,"args",...)
		end
		if options.plugins then
			for plugname,plugin in pairs(options.plugins) do
				if type(plugin)~="table" then
					err(": expected a table, got '"..tostring(plugin).."'", errlvl,tostring(plugname),"plugins",...)
				end
				for k,v in pairs(plugin) do
					validateKey(k,errlvl,tostring(plugname),"plugins",...)
					validate(v, errlvl,k,tostring(plugname),"plugins",...)
				end
			end
		end
	end
end


--- Validates basic structure and integrity of an options table \\
-- Does NOT verify that get/set etc actually exist, since they can be defined at any depth
-- @param options The table to be validated
-- @param name The name of the table to be validated (shown in any error message)
-- @param errlvl (optional number) error level offset, default 0 (=errors point to the function calling :ValidateOptionsTable)
function AceConfigRegistry:ValidateOptionsTable(options,name,errlvl)
	errlvl=(errlvl or 0)+1
	name = name or "Optionstable"
	if not options.name then
		options.name=name	-- bit of a hack, the root level doesn't really need a .name :-/
	end
	validate(options,errlvl,name)
end

--- Fires a "ConfigTableChange" callback for those listening in on it, allowing config GUIs to refresh.
-- You should call this function if your options table changed from any outside event, like a game event
-- or a timer.
-- @param appName The application name as given to `:RegisterOptionsTable()`
function AceConfigRegistry:NotifyChange(appName)
	if not AceConfigRegistry.tables[appName] then return end
	AceConfigRegistry.callbacks:Fire("ConfigTableChange", appName)
end

-- -------------------------------------------------------------------
-- Registering and retreiving options tables:


-- validateGetterArgs: helper function for :GetOptionsTable (or, rather, the getter functions returned by it)

local function validateGetterArgs(uiType, uiName, errlvl)
	errlvl=(errlvl or 0)+2
	if uiType~="cmd" and uiType~="dropdown" and uiType~="dialog" then
		error(MAJOR..": Requesting options table: 'uiType' - invalid configuration UI type, expected 'cmd', 'dropdown' or 'dialog'", errlvl)
	end
	if not strmatch(uiName, "[A-Za-z]%-[0-9]") then	-- Expecting e.g. "MyLib-1.2"
		error(MAJOR..": Requesting options table: 'uiName' - badly formatted or missing version number. Expected e.g. 'MyLib-1.2'", errlvl)
	end
end

--- Register an options table with the config registry.
-- @param appName The application name as given to `:RegisterOptionsTable()`
-- @param options The options table, OR a function reference that generates it on demand. \\
-- See the top of the page for info on arguments passed to such functions.
-- @param skipValidation Skip options table validation (primarily useful for extremely huge options, with a noticeable slowdown)
function AceConfigRegistry:RegisterOptionsTable(appName, options, skipValidation)
	if type(options)=="table" then
		if options.type~="group" then	-- quick sanity checker
			error(MAJOR..": RegisterOptionsTable(appName, options): 'options' - missing type='group' member in root group", 2)
		end
		AceConfigRegistry.tables[appName] = function(uiType, uiName, errlvl)
			errlvl=(errlvl or 0)+1
			validateGetterArgs(uiType, uiName, errlvl)
			if not AceConfigRegistry.validated[uiType][appName] and not skipValidation then
				AceConfigRegistry:ValidateOptionsTable(options, appName, errlvl)	-- upgradable
				AceConfigRegistry.validated[uiType][appName] = true
			end
			return options
		end
	elseif type(options)=="function" then
		AceConfigRegistry.tables[appName] = function(uiType, uiName, errlvl)
			errlvl=(errlvl or 0)+1
			validateGetterArgs(uiType, uiName, errlvl)
			local tab = assert(options(uiType, uiName, appName))
			if not AceConfigRegistry.validated[uiType][appName] and not skipValidation then
				AceConfigRegistry:ValidateOptionsTable(tab, appName, errlvl)	-- upgradable
				AceConfigRegistry.validated[uiType][appName] = true
			end
			return tab
		end
	else
		error(MAJOR..": RegisterOptionsTable(appName, options): 'options' - expected table or function reference", 2)
	end
end

--- Returns an iterator of ["appName"]=funcref pairs
function AceConfigRegistry:IterateOptionsTables()
	return pairs(AceConfigRegistry.tables)
end




--- Query the registry for a specific options table.
-- If only appName is given, a function is returned which you
-- can call with (uiType,uiName) to get the table.\\
-- If uiType&uiName are given, the table is returned.
-- @param appName The application name as given to `:RegisterOptionsTable()`
-- @param uiType The type of UI to get the table for, one of "cmd", "dropdown", "dialog"
-- @param uiName The name of the library/addon querying for the table, e.g. "MyLib-1.0"
function AceConfigRegistry:GetOptionsTable(appName, uiType, uiName)
	local f = AceConfigRegistry.tables[appName]
	if not f then
		return nil
	end

	if uiType then
		return f(uiType,uiName,1)	-- get the table for us
	else
		return f	-- return the function
	end
end
