
local E = select(2, ...) -- Engine

local pairs 	= pairs
local match 	= string.match
local gsub 		= string.gsub
local sub 		= string.sub
local len 		= string.len
local gmatch 	= string.gmatch
local rep 		= string.rep
local lower		= string.lower
local upper		= string.upper
local floor 	= math.floor
local fmod 		= math.fmod

function E:tableContainsKey(tbl, item)
    for key, value in pairs(tbl) do
        if key == item then return value end
    end
    return false
end

function E:tableContainsValue(tbl, item)
    for key, value in pairs(tbl) do
        if value == item then return key end
    end
    return false
end

function E:tableContainsValueAtN(tbl, item, position)
    for key, value in pairs(tbl) do
        if value[position] == item then return key end
    end
    return false
end

function E:IsStringPartInTableValues(tbl, str)
    for key, value in pairs(tbl) do
        if match(str, value) then return match(str, value) end
    end
    return false
end

function E:IsStringPartInTableKeys(tbl, str)
    for key, value in pairs(tbl) do
        if match(str, key) then return match(str, key) end
    end
    return false
end

function E:DoesStringPartExist(str, find)
	return match(str, find)
end

function E:RemoveFromString(str, find)
	return gsub(str, find, "")
end

function E:GetFullFrameName(object)
	return object:GetName()
end

function E:GetPlainFrameName(str)
	local Suffix = E:IsStringPartInTableValues(E:GetModule("Unitframes").UFSuffix, str)
	local TargetFrame = str
	
	if Suffix then
		TargetFrame = E:RemoveFromString(str, Suffix)
	end
	
	TargetFrame = E:removeDigits(TargetFrame) -- Also clean Numbers
	
	return TargetFrame
end

function E:rgbToHex(rgb, SmallValue)
	
	local hexadecimal = 'FF'

	for key, value in pairs(rgb) do
		if SmallValue then value = value * 255 end
		local hex = ''

		while(value > 0)do
			local index = fmod(value, 16) + 1
			value = floor(value / 16)
			hex = sub('0123456789ABCDEF', index, index) .. hex			
		end

		if(len(hex) == 0)then
			hex = '00'

		elseif(len(hex) == 1)then
			hex = '0' .. hex
		end

		hexadecimal = hexadecimal .. hex
	end

	return hexadecimal
end

-- Split str after every space
function E:Split(str)
	t = {}
	for word in str:gmatch("%w+") do table.insert(t, word) end
	
	return t
end

function E:GetNPartOfName(str, n)
	if not str then return end
	
	local data = {}
	data = E:Split(str)
	
	return data[n]
end

function E:print_r(t)
    local print_r_cache={}
    local function sub_print_r(t,indent)
        if (print_r_cache[tostring(t)]) then
            print(indent.."*"..tostring(t))
        else
            print_r_cache[tostring(t)]=true
            if (type(t)=="table") then
                for pos,val in pairs(t) do
                    if (type(val)=="table") then
                        print(indent.."["..pos.."] => "..tostring(t).." {")
                        sub_print_r(val,indent..rep(" ",len(pos)+8))
                        print(indent..rep(" ",len(pos)+6).."}")
                    elseif (type(val)=="string") then
                        print(indent.."["..pos..'] => "'..val..'"')
                    else
                        print(indent.."["..pos.."] => "..tostring(val))
                    end
                end
            else
                print(indent..tostring(t))
            end
        end
    end
    if (type(t)=="table") then
        print(tostring(t).." {")
        sub_print_r(t,"  ")
        print("}")
    else
        sub_print_r(t,"  ")
    end
    print()
end

function E:makePositive(num)
	if num < 0 then num = num * (-1) end
	return num
end

function E:removeDigits(str)
	return gsub(str, '%d+', '')
end

function E:ExtractDigits(str)
	local num = ""
	if match(str, "%d+") then
		num = match(str, "%d+")
	end
	local str = E:removeDigits(str)
	return str, num
end

function E:getDigits(str)
	return match(str, "%d+") or ""
end

function E:getFromGlobal()
	for n in pairs(_G) do 
		if match(tostring(n), "TRACKING") ~= nil then
			print(n)
		end
	end
end

function E:printChildren(parentFrame)
	local kids = { parentFrame:GetChildren() };

	for _, child in ipairs(kids) do
	  print(E:GetFrameName(child))
	end
end

function E:getParent(childFrame)
	return E:GetFullFrameName(childFrame:GetParent())
end

function E:firstToUpper(str)
    return (str:gsub("^%l", upper))
end

function E:stringToUpper(str)
	return upper(str)
end

function E:getHighestFrameLevelChild(parentFrame)
local kids = { parentFrame:GetChildren() };
	local highestChild = nil
	local lastLevel = 0

	for _, child in ipairs(kids) do
		if child:GetFrameLevel() > lastLevel then
			lastLevel = child:GetFrameLevel()
			highestChild = child
		end
	end
	
	return highestChild
end

function E:GetBiggestChildrenInfo(parentFrame)
	local kids = { parentFrame:GetChildren() };
	local biggestChild = nil
	local lastX = 1
	local lastY = 1

	for _, child in ipairs(kids) do
		if child:GetWidth() > lastX or child:GetHeight() > lastY then
			if child:GetWidth() > lastX and lastX then
				lastX = child:GetWidth()
			end
			if child:GetHeight() > lastY and lastY then
				lastY = child:GetHeight()
			end
			
			biggestChild = E:GetFullFrameName(child)
		end
	end
	
	return biggestChild, lastX, lastY
end

function E:readableNumber(num, places)
    local ret, placeValue
    placeValue = ("%%.%df"):format(places or 1)
	
    if not num then
        return 0
    elseif num >= (1000000000000 * 1) then
        ret = placeValue:format(num / 1000000000000) .. " T" -- trillion
    elseif num >= (1000000000 * 1) then
        ret = placeValue:format(num / 1000000000) .. " G" -- billion
    elseif num >= (1000000 * 1) then
        ret = placeValue:format(num / 1000000) .. " M" -- million
    elseif num >= (1000 * 1) then
        ret = placeValue:format(num / 1000) .. " K" -- thousand
    else
        ret = num -- hundreds
    end
	
	-- To correctly format to target delimiter
	if ret ~= nil then
		return ret
	end
	
    -- return ret
end

local FormatTimeY, FormatTimeM, FormatTimeD, FormatTimeh, FormatTimem
function E:FormatTime(s, places)
	if not places then places = 0 end

	FormatTimeY = s / (3600*24*356)
	FormatTimeM = s / (3600*24*31)
	FormatTimed = s / (3600*24)
	FormatTimeh = s / 3600
	FormatTimem = s / 60
	
	if FormatTimeY >= 1 then
		TimeStr = E:Round(FormatTimeY, places) .. "Y"
	elseif FormatTimeM >= 1 then
		TimeStr = E:Round(FormatTimeM, places) .. "M"
	elseif FormatTimed >= 1 then
		TimeStr = E:Round(FormatTimed, places) .. "d"
	elseif FormatTimeh >= 1 then
		TimeStr = E:Round(FormatTimeh, places) .. "h"
	elseif FormatTimem >= 2 then
		TimeStr = E:Round(FormatTimem, places) .. "m"
	elseif s > 0 then
		if s / 60 > 1 then
			TimeStr = E:Round(s / 60,places) .. "m"
		else
			TimeStr = E:Round(s,places)
		end
	end
	
	return TimeStr
end

local units = {"player", "pet", "target", "targettarget", "focus", "focustarget", "party", "raid", "boss"}
function E:ExtractUnit(unit)
	local unit, unitNum = E:ExtractDigits(unit)
	
	for k,v in pairs(units) do
		if match(lower(unit), v) then
			return v .. unitNum
		end
	end
end

local RoundMultiplier = 0
function E:Round(num, numDecimalPlaces)
  RoundMultiplier = 10^(numDecimalPlaces or 0)
  return floor(num * RoundMultiplier + 0.5) / RoundMultiplier
end

local function Remove(o)
	if Frame.UnregisterAllEvents then
		Frame:UnregisterAllEvents()
	else
		Frame.Show = Frame.Hide
	end

	Frame:SetScript("OnShow", function(self) self:Hide() end)
	Frame:Hide()
end


local function AddAPI(object)
	local metatable = getmetatable(object).__index
	if not object.Remove then metatable.Remove = Remove end
end

local frame = CreateFrame("Frame")
AddAPI(frame)