local Kindred, maj, rev, execQueue, _, T = {}, 1, 0, {}, ...

local core = CreateFrame("FRAME", nil, nil, "SecureHandlerAttributeTemplate")
core:SetFrameRef("sandbox", CreateFrame("FRAME", nil, nil, "SecureFrameTemplate"))
core:Execute([==[-- Kindred.Init
	pcache, nextDriverKey, sandbox = newtable(), 4200, self:GetFrameRef("sandbox")
	cndType, cndState, cndDrivers, stateDrivers = newtable(), newtable(), newtable(), newtable()

	OptionParse = [=[-- Kindred_OptionParse
		local ret, conditional = newtable(), ...
		local no, ns, lp = conditional:gmatch("()%["), conditional:gmatch("();"), #conditional + 1
		local po, lc, cur, pc, ps = no() or lp, 0
		repeat
			ps, cur = ns() or lp, newtable()
			while po < ps do
				pc = conditional:match("()%]", po)
				if pc then
					local clause, ct = conditional:sub(po+1, pc-1), newtable()
					for m in clause:gmatch("[^,%s][^,]*") do
						m = m:match("^%s*(.-)%s*$")
						if m:sub(1,1) == "@" or m:sub(1,7) == "target=" then
							ct.target = m:match("[=@](.*)")
						else
							local cvalparsed, mark, wname, inv, name, col, cval = nil, m:match("^([+%-#]?)((n?o?)([^:=]*))([:=]?)(.-)%s*$")
							if inv ~= "no" then inv, name = "", wname end
							cval, name = col == ":" and cval and ("/" .. cval .. "/"):gsub("%s*/%s*", "/"):match("/(.+)/") or nil, col == ":" and name or (name .. col .. cval)
							if cval and cval ~= "" then
								cvalparsed = newtable()
								for s in cval:gmatch("[^/]+") do cvalparsed[#cvalparsed+1] = s end
							end
							cct = newtable(name, cvalparsed, inv ~= "no", mark, cval)
							ct[#ct+1], cct[0] = cct, m
						end
					end
					cur[#cur+1], lc, po = ct, pc, no() or lp
				else
					break
				end
			end
			cur[1], cur.v = cur[1] or newtable(), conditional:sub(lc+1, ps-1):match("^%s*(.-)%s*$")
			ret[#ret + 1], lc = cur, ps
		until ps == lp		
		pcache[conditional] = ret
	]=]
	OptionConstruct = [=[-- Kindred_OptionConstruct
		local cond, out = pcache[...] or owner:Run(OptionParse, ...) or pcache[...]
		for i=1,#cond do
			local clause, cparse = cond[i], ""
			for i=1,#clause do
				local target = clause[i].target
				local conditional, cnext = target and ("@" .. target) or "", ""
				for j=1,#clause[i] do
					local c = clause[i][j]
					local name, argp, goal, flag = c[1], c[2], c[3], c[4]
					if goal == false and (cndType[name] == nil and cndType["no" .. name]) then goal, name = true, "no" .. name end
					if cndType[name] == nil then
						conditional, cnext = conditional .. cnext .. c[0], ","
					else
						local cres, ctype = false, cndType[name]
						if ctype == "state" then
							local cval, cs = nil, cndState[name]
							if argp == nil then
								cval = cs and cs["*"] or false
							elseif cs then
								for k=1,#argp do
									if cs[argp[k]] then
										cval = true
										break
									end
								end
							end
							cres = (not not cval) == goal
						elseif ctype == "srun" then
							cres = (not not sandbox:Run(cndState[name], c[5], target, c[4])) == goal
						end
						if not cres then
							conditional = nil
							break
						end
					end
				end
				if conditional then
					cparse = cparse .. "[" .. conditional .. "]"
				end
			end
			if cparse ~= "" then
				out = (out and (out .. ";") or "") .. cparse .. clause.v
			end
		end
		out = out or "[form:42,noform:42]"
		return out
	]=]
	RefreshDrivers = [=[-- Kindred_RefreshDrivers
		local name = ...
		if cndDrivers[name] then
			for key, info in pairs(cndDrivers[name]) do
				local nv = owner:Run(OptionConstruct, info[3])
				if info[5] ~= nv then
					info[5] = nv
					RegisterStateDriver(info[1], info[2], nv)
				end
			end
		end
	]=]
]==])
core:SetAttribute("RegisterStateDriver", [=[-- Kindred_RegisterStateDriver
	if self == owner then return owner:RunMethod("Throw", "NO! NO! NO! NO! NO!") end
	local drivers, frame, state, values = stateDrivers[self], self, ...
	local old = drivers and drivers[state]
	if old then
		drivers[state] = nil
		RegisterStateDriver(frame, state, "")
		for _, t in pairs(cndDrivers) do
			t[old[4]] = nil
		end
	end
	if values and type(state) == "string" and values ~= "" then
		local info, key
		drivers, info, key = drivers or newtable(), newtable(frame, state, values, nextDriverKey), nextDriverKey
		stateDrivers[frame], drivers[state], nextDriverKey = drivers, info, nextDriverKey + 1
		local parse, cv = pcache[values] or owner:Run(OptionParse, values) or pcache[values], owner:Run(OptionConstruct, values)
		info[5] = cv
		RegisterStateDriver(frame, state, cv)
		for i=1,#parse do
			for j=1,#parse[i] do
				for k=1,#parse[i][j] do
					local n = parse[i][j][k][1]
					cndDrivers[n] = cndDrivers[n] or newtable()
					cndDrivers[n][key] = info
				end
			end
		end
	end
]=])
core:SetAttribute("EvaluateCmdOptions", [=[-- Kindred:EvaluateCmdOptions("options")
	return SecureCmdOptionParse(owner:Run(OptionConstruct, ...))
]=])
core:SetAttribute("UpdateStateConditional", [=[-- Kindred:UpdateStateConditional("name", "addSet", "remSet")
	local name, new, kill = ...
	local cs = cndState[name] or newtable()
	cndType[name], cndState[name] = "state", cs
	if kill == "*" then
		wipe(cs)
	else
		for s in (type(kill) == "string" and kill or ""):gmatch("[^/]+") do
			cs[s] = nil
		end
	end
	cs["*"] = cs["*"] or (new and new ~= "" and 2 or nil)
	for s in (type(new) == "string" and new or ""):gmatch("[^/]+") do
		cs[s] = 1
	end
	if cndDrivers[name] then
		owner:Run(RefreshDrivers, name)
	end
]=])
core:RegisterEvent("PLAYER_REGEN_ENABLED")
core:SetScript("OnEvent", function(self, e)
	for k,v in pairs(execQueue) do
		execQueue[k] = nil
		Kindred:SetStateConditionalValue(k,v)
	end
end)
function core:Throw(text)
	error(text)
end
function core:DeferExecute(snippet, key)
	if InCombatLockdown() then
		execQueue[key] = snippet
	else
		self:Execute(snippet)
	end
end

local EvaluateCmdOptions do
	local ShadowEnvironment do
		local fcache, _R, _ENV = {}, {next=rtable.next, pairs=rtable.pairs, newtable=function(...) return {...} end}, {}
		local _shadow = {__index=function(t,k)
			local v = _ENV[t] and _ENV[t][k]
			if v == nil then
				v = _R[k] or _G[k]
			elseif type(v) == "userdata" then
				v = IsFrameHandle(v) and ShadowEnvironment(GetFrameHandleFrame(v)) or setmetatable({}, {__index=v})
			end
			t[k] = v
			return v
		end}
		local function ShadowRun(self, f, ...)
			local v = fcache[f] or loadstring(("-- %s\nreturn function(self, ...)\n%s\nend"):format(tostring(f):match("^[%s%-]*([^\n]*)"), f))()
			fcache[f] = setfenv(v, _ENV[self])
			return securecall(v, self, ...)
		end
		function ShadowEnvironment(h)
			local e = _ENV[h] or setmetatable({owner={Run=ShadowRun}}, _shadow)
			_ENV[h], _ENV[e], _ENV[e.owner] = e, GetManagedEnvironment(h), e
			return e.owner, e
		end
	end
	local _core, _env = ShadowEnvironment(core)
	function EvaluateCmdOptions(options)
		return SecureCmdOptionParse((securecall(_core.Run, _core, _env.OptionConstruct, options)))
	end
end

function Kindred:SetStateConditionalValue(name, value)
	if type(value) == "boolean" then value = value and "*" or "" end
	assert(type(value) == 'string', 'Syntax: Kindred:SetStateConditionalValue("name", "value")')
	core:DeferExecute(([[owner:RunAttribute("UpdateStateConditional", %q, %q, "*")]]):format(name, value or ""), name)
end
function Kindred:SetSecureExecConditional(name, snippet)
	assert(type(name) == "string" and type(snippet) == "string", 'Syntax: Kindred:SetSecureExecConditional("name", "snippet")')
	core:DeferExecute(([[ local name = %q
		cndType[name], cndState[name] = "srun", %q
		owner:Run(RefreshDrivers, name)
	]]):format(name, snippet), name)
end
function Kindred:PokeConditional(name)
	assert(type(name) == "string", 'Syntax: Kindred:PokeConditional("name")')
	core:DeferExecute(("owner:Run(RefreshDrivers, %q)"):format(name), "_poke-" .. name)
end
function Kindred:RegisterStateDriver(frame, state, values)
	assert(type(frame) == "table" and type(state) == "string" and (values == nil or type(values) == "string"), 'Syntax: Kindred:RegisterStateDriver(frame, "state"[, "values"])')
	core:SetFrameRef("regframe", frame)
	core:Execute(([[self:RunFor(self:GetFrameRef("regframe"), self:GetAttribute("RegisterStateDriver"), %q, %q)]]):format(state, values or ""))
end
function Kindred:EvaluateCmdOptions(options)
	return EvaluateCmdOptions(options)
end
function Kindred:seclib()
	return core
end
function Kindred:compatible(cmaj, crev)
	return (cmaj == maj and crev <= rev) and Kindred or nil
end

T.Kindred = Kindred