local y,w=...local O=w.DevTool function O.round(y,w)if not y then return nil end local O=10^(w or 0)return math.floor(y*O+.5)/O end function O.CalculatePosition(y,w,O)if y<w then y=w end if y>O then y=O end return y end function O.split(y,w)local O,H O,H=w or"\046",{}local C=string.format("\040\091\094\037\115\093\043\041",O)string.gsub(y,C,function(y)H[#H+1]=y end)return H end function O.starts(y,w)return string.sub(y,1,string.len(w))==w end function O.ends(y,w)return w==""or string.sub(y,-string.len(w))==w end function O.ArgsToString(y)local w=""local O=false local H=""for C=10,1,-1 do if y[C]~=nil then O=true end if O then w=tostring(y[C])..(H..w)H="\044 "end end return w end function O.FindIn(y,w,O)local H={}for y,C in pairs(y or{})do if O(y,w)then H[y]=C end end return H end function O.FindIndex(y,w)for y,O in pairs(y)do if O==w then return y end end return nil end function O.CountElements(y)local w=0 for y,O in pairs(y)do w=w+1 end return w end function O.FromStrToObject(y)if y=="\095\071"then return _G end local w=O.split(y,"\046")or{}local H=_G for y,w in pairs(w)do if H then H=H[w]end end return H end function O.SelectSortFunction(y)local w if y>20000 then w=function(y,w)return y.name<w.name end elseif y<300 then w=function(y,w)if y.name=="\095\095\105\110\100\101\120"then return true elseif w.name=="\095\095\105\110\100\101\120"then return false else if tonumber(y.name)~=nil and tonumber(w.name)~=nil then return tonumber(y.name)<tonumber(w.name)else return y.name<w.name end end end else w=function(y,w)if y.name=="\095\095\105\110\100\101\120"then return true elseif w.name=="\095\095\105\110\100\101\120"then return false else return y.name<w.name end end end return w end function O.ToUIString(y,w,H)local C local M=type(y)if M=="\116\097\098\108\101"then C=O.GetObjectInfoFromWoWAPI(w,y)or tostring(y)C="\040"..(O.CountElements(y)..("\041 "..C))else C=tostring(y)end if H then C=string.gsub(string.gsub(tostring(C),"\124\110",""),"\n","")end return C end function O.GetObjectInfoFromWoWAPI(y,w)local H local C,M=O.TryCallAPIFn("\071\101\116\079\098\106\101\099\116\084\121\112\101",w)if C then local C=function(y,w,O)w=w or""O=O or""if y then return H..(" "..(w..(y..O)))end return H end local T,I=O.TryCallAPIFn("\071\101\116\078\097\109\101",w)local b,t=O.TryCallAPIFn("\071\101\116\084\101\120\116\117\114\101",w)local z,x=O.TryCallAPIFn("\071\101\116\084\101\120\116",w)local e,W,X,R,D=O.TryCallAPIFn("\071\101\116\066\111\117\110\100\115\082\101\099\116",w)H=M or""if e then H=C("\091"..(tostring(O.round(W))..("\044 "..(tostring(O.round(X))..("\044 "..(tostring(O.round(R))..("\044 "..(tostring(O.round(D)).."\093"))))))))end if y~=I then H=C(I,O.colors.gray:WrapTextInColorCode("\060"),O.colors.gray:WrapTextInColorCode("\062"))end H=C(t)H=C(x,"\'","\'")H=C(tostring(w))end return H end function O.TryCallAPIFn(y,w)if type(w)~="\116\097\098\108\101"then return end local O=getmetatable(w)if O and(type(O)=="\116\097\098\108\101"and type(O.__index)=="\102\117\110\099\116\105\111\110")then return end if w.IsForbidden then local y,O=pcall(w.IsForbidden,w)if not y or y and O then return end end local H=w[y]if not H or type(H)~="\102\117\110\099\116\105\111\110"then return end return pcall(H,w)end function O.TryCallFunctionWithArgs(y,w)local O={pcall(y,unpack(w,1,10))}local H=O[1]table.remove(O,1)return H,O end function O.IsMetaTableNode(y)return y.name=="\036\109\101\116\097\116\097\098\108\101"or y.name=="\036\109\101\116\097\116\097\098\108\101\046\095\095\105\110\100\101\120"or y.name=="\095\095\105\110\100\101\120"and(y.parent and y.parent.name=="\036\109\101\116\097\116\097\098\108\101")end function O.GetParentTable(y)local w=y.parent if w and(w.value==_G or w==O.list)then w=nil end if w then while O.IsMetaTableNode(w)do w=w.parent end end return w end
-- DevTool is a World of Warcraft® addon development tool.
-- Copyright (c) 2021-2024 Britt W. Yazel
-- Copyright (c) 2016-2021 Peter aka "Varren"
-- This code is licensed under the MIT license (see LICENSE for details)

local _, addonTable = ... --make use of the default addon namespace
local DevTool = addonTable.DevTool

-----------------------------------------------------------------------------------------------
--- UTILS
-----------------------------------------------------------------------------------------------

--- Math

function DevTool.round(num, idp)
	if not num then
		return nil
	end
	local mult = 10 ^ (idp or 0)
	return math.floor(num * mult + 0.5) / mult
end

function DevTool.CalculatePosition(pos, min, max)
	if pos < min then
		pos = min
	end
	if pos > max then
		pos = max
	end
	return pos
end


--- String

function DevTool.split(str, sep)
	local separator, fields
	separator, fields = sep or ".", {}
	local pattern = string.format("([^%s]+)", separator)
	string.gsub(str, pattern, function(c)
		fields[#fields + 1] = c
	end)
	return fields
end

function DevTool.starts(String, Start)
	return string.sub(String, 1, string.len(Start)) == Start
end

function DevTool.ends(String, End)
	return End == '' or string.sub(String, -string.len(End)) == End
end

function DevTool.ArgsToString(args)
	local strArgs = ""
	local found = false
	local delimiter = ""
	for i = 10, 1, -1 do
		if args[i] ~= nil then
			found = true
		end

		if found then
			strArgs = tostring(args[i]) .. delimiter .. strArgs
			delimiter = ", "
		end
	end
	return strArgs
end

function DevTool.FindIn(parent, strName, fn)
	local resultTable = {}

	for k, v in pairs(parent or {}) do
		if fn(k, strName) then
			resultTable[k] = v
		end
	end

	return resultTable
end


--- Table

function DevTool.FindIndex(table, item)
	for k, v in pairs(table) do
		if v == item then
			return k
		end
	end
	return nil;
end

function DevTool.CountElements(t)
	local count = 0
	for _, _ in pairs(t) do
		count = count + 1
	end
	return count
end

function DevTool.FromStrToObject(str)
	if str == "_G" then
		return _G
	end

	local vars = DevTool.split(str, ".") or {}

	local var = _G
	for _, name in pairs(vars) do
		if var then
			var = var[name]
		end
	end

	return var
end


--- Miscellaneous

function DevTool.SelectSortFunction(tableLength)
	local compareFn

	--fast filter
	if tableLength > 20000 then
		--optimizing for _G
		compareFn = function(a, b)
			return a.name < b.name
		end
	elseif tableLength < 300 then

		--thorough filter
		--lets try some better sorting if we have small number of records
		--numbers will be sorted not like 1,10,2 but like 1,2,10
		compareFn = function(a, b)
			if a.name == "__index" then
				return true
			elseif b.name == "__index" then
				return false
			else
				if tonumber(a.name) ~= nil and tonumber(b.name) ~= nil then
					return tonumber(a.name) < tonumber(b.name)
				else
					return a.name < b.name
				end
			end
		end
	else
		--default filter
		compareFn = function(a, b)
			if a.name == "__index" then
				return true
			elseif b.name == "__index" then
				return false
			else
				return a.name < b.name
			end
		end
	end

	return compareFn
end

function DevTool.ToUIString(value, name, withoutLineBrakes)
	local result
	local valueType = type(value)

	if valueType == "table" then
		result = DevTool.GetObjectInfoFromWoWAPI(name, value) or tostring(value)
		result = "(" .. DevTool.CountElements(value) .. ") " .. result
	else
		result = tostring(value)
	end

	if withoutLineBrakes then
		result = string.gsub(string.gsub(tostring(result), "|n", ""), "\n", "")
	end

	return result
end

function DevTool.GetObjectInfoFromWoWAPI(helperText, value)
	local resultStr
	local ok, objectType = DevTool.TryCallAPIFn("GetObjectType", value)

	-- try to get frame name
	if ok then
		local concat = function(str, before, after)
			before = before or ""
			after = after or ""
			if str then
				return resultStr .. " " .. before .. str .. after
			end
			return resultStr
		end

		local _, name = DevTool.TryCallAPIFn("GetName", value)
		local _, texture = DevTool.TryCallAPIFn("GetTexture", value)
		local _, text = DevTool.TryCallAPIFn("GetText", value)

		local hasSize, left, bottom, width, height = DevTool.TryCallAPIFn("GetBoundsRect", value)

		resultStr = objectType or ""
		if hasSize then
			resultStr = concat("[" ..
					tostring(DevTool.round(left)) .. ", " ..
					tostring(DevTool.round(bottom)) .. ", " ..
					tostring(DevTool.round(width)) .. ", " ..
					tostring(DevTool.round(height)) .. "]")
		end

		if helperText ~= name then
			resultStr = concat(name, DevTool.colors.gray:WrapTextInColorCode("<"), DevTool.colors.gray:WrapTextInColorCode(">"))
		end

		resultStr = concat(texture)
		resultStr = concat(text, "'", "'")
		resultStr = concat(tostring(value))
	end

	return resultStr
end

function DevTool.TryCallAPIFn(fnName, value)
	-- this function is helper fn to get table type from wow api.
	-- if there is GetObjectType then we will return it.
	-- returns Button, Frame or something like this

	-- VALIDATION
	if type(value) ~= "table" then
		return
	end

	-- VALIDATION FIX if __index is function we don't want to execute it
	-- Example in ACP.L
	local metatable = getmetatable(value)
	if metatable and type(metatable) == "table" and type(metatable.__index) == "function" then
		return
	end

	-- VALIDATION is forbidden from wow api
	if value.IsForbidden then
		local ok, forbidden = pcall(value.IsForbidden, value)
		if not ok or (ok and forbidden) then
			return
		end
	end

	local fn = value[fnName]
	-- VALIDATION has WoW API
	if not fn or type(fn) ~= "function" then
		return
	end

	-- MAIN PART:
	return pcall(fn, value)
end

function DevTool.TryCallFunctionWithArgs(fn, args)
	local results = { pcall(fn, unpack(args, 1, 10)) }
	local ok = results[1]
	table.remove(results, 1)
	return ok, results
end

function DevTool.IsMetaTableNode(info)
	return info.name == "$metatable" or info.name == "$metatable.__index" or (info.name == "__index" and info.parent and info.parent.name == "$metatable")
end

function DevTool.GetParentTable(info)
	local parent = info.parent
	if parent and (parent.value == _G or parent == DevTool.list) then
		-- this fn is in global namespace, or has no parent
		parent = nil
	end

	if parent then
		while DevTool.IsMetaTableNode(parent) do
			-- metatable has real object 1 level higher
			parent = parent.parent
		end
	end

	return parent
end