addonName, PakuHud = ...

local GetMapId = C_Map.GetBestMapForUnit
local GetPlayerPos = C_Map.GetPlayerMapPosition
local MapToWorld = C_Map.GetWorldPosFromMapPos

PakuHud.ToString = function(arg)
	local t = type(arg)
	if t == "nil" then
		return "nil"
	elseif t == "table" then
		return PakuHud.TableToString(arg)
	else
		return tostring(arg)
	end
end

PakuHud.ArgsToString = function(arg, ...)
	if select("#", ...) > 0 then
		return PakuHud.ToString(arg), ArgsToString(...)
	else
		return PakuHud.ToString(arg)
	end
end

PakuHud.Print = function(...)
	local output = strjoin("\n", PakuHud.ArgsToString(...))
	print("|cFFFF0000PakuHud: |r" .. output)
end

PakuHud.TableToString = function(tbl)
    -- to make output beautiful
    local function tab(amt)
        local str = ""
        for i=1,amt do
            str = str .. "    "
        end
        return str
    end

    local cache, stack, output = {},{},{}
    local depth = 1
    local output_str = "{\n"

    while true do
        local size = 0
        for k,v in pairs(tbl) do
            size = size + 1
        end

        local cur_index = 1
        for k,v in pairs(tbl) do
            if (cache[tbl] == nil) or (cur_index >= cache[tbl]) then

                if (string.find(output_str,"}",output_str:len())) then
                    output_str = output_str .. ",\n"
                elseif not (string.find(output_str,"\n",output_str:len())) then
                    output_str = output_str .. "\n"
                end

                -- This is necessary for working with HUGE tables otherwise we run out of memory using concat on huge strings
                table.insert(output,output_str)
                output_str = ""

                local key
                if (type(k) == "number" or type(k) == "boolean") then
                    key = "["..tostring(k).."]"
                else
                    key = "['"..tostring(k).."']"
                end

                if (type(v) == "number" or type(v) == "boolean") then
                    output_str = output_str .. tab(depth) .. key .. " = "..tostring(v)
                elseif (type(v) == "table") then
                    output_str = output_str .. tab(depth) .. key .. " = {\n"
                    table.insert(stack,tbl)
                    table.insert(stack,v)
                    cache[tbl] = cur_index+1
                    break
                else
                    output_str = output_str .. tab(depth) .. key .. " = '"..tostring(v).."'"
                end

                if (cur_index == size) then
                    output_str = output_str .. "\n" .. tab(depth-1) .. "}"
                else
                    output_str = output_str .. ","
                end
            else
                -- close the table
                if (cur_index == size) then
                    output_str = output_str .. "\n" .. tab(depth-1) .. "}"
                end
            end

            cur_index = cur_index + 1
        end

        if (size == 0) then
            output_str = output_str .. "\n" .. tab(depth-1) .. "}"
        end

        if (#stack > 0) then
            tbl = stack[#stack]
            stack[#stack] = nil
            depth = cache[tbl] == nil and depth + 1 or depth - 1
        else
            break
        end
    end

    -- This is necessary for working with HUGE tables otherwise we run out of memory using concat on huge strings
    table.insert(output,output_str)
    output_str = table.concat(output)

    return output_str
end

PakuHud.GetPlayerWorldPosition = function()
	local mapId = GetMapId("player")
	local mapPosition = GetPlayerPos(mapId, "player")
	local continent, worldPosition = MapToWorld(mapId, mapPosition)
	return continent, worldPosition
end

PakuHud.PrintPlayerWorldPosition = function()
	local _, position = PakuHud.GetPlayerWorldPosition()
	PakuHud.Print("Position = {x = " .. position.x .. ", y = " .. position.y .. "}")
end

PakuHud.DistanceSquared = function(x1, y1, x2, y2)
	--PakuHud.Print(x1, y1, x2, y2)
	local point1 = {}
	local point2 = {}
	
	-- x2 will be null if we're passed two tables
	if x2 then
		point1.x = x1
		point1.y = y1
		point2.x = x2
		point2.y = y2
	else
		point1 = x1
		point2 = y1
	end
	
	-- distance = sqrt((x2 - x1)^2 + (y2 - y1)^2)
	-- thus distance^2 = (x2 - x1)^2 + (y2 - y1)^2
	local xDiff = point2.x - point1.x
	local yDiff = point2.y - point1.y
	return (xDiff * xDiff) + (yDiff * yDiff)
end

PakuHud.Distance = function(x1, y1, x2, y2)
	return math.sqrt(PakuHud.DistanceSquared(x1, y1, x2, y2))
end

PakuHud.Round = function(num)
	return num + 0.5 - (num + 0.5) % 1
end