-- Druid helper module for gui layouts
-- @module helper

local const = require("druid.const")

local M = {}

--- Text node or icon node can be nil
local function get_text_width(text_node)
	if text_node then
		local text_metrics = gui.get_text_metrics_from_node(text_node)
		local text_scale = gui.get_scale(text_node).x
		return text_metrics.width * text_scale
	end

	return 0
end


local function get_icon_width(icon_node)
	if icon_node then
		local icon_scale_x = gui.get_scale(icon_node).x
		return gui.get_size(icon_node).x * icon_scale_x -- icon width
	end

	return 0
end


local function get_width(node)
	return gui.get_text(node) and get_text_width(node) or get_icon_width(node)
end


--- Center two nodes.
-- Nodes will be center around 0 x position
-- text_node will be first (at left side)
-- @function helper.centrate_text_with_icon
-- @tparam[opt] text text_node Gui text node
-- @tparam[opt] box icon_node Gui box node
-- @tparam number margin Offset between nodes
function M.centrate_text_with_icon(text_node, icon_node, margin)
	M.centrate_nodes(margin, text_node, icon_node)
end


--- Center two nodes.
-- Nodes will be center around 0 x position
-- icon_node will be first (at left side)
-- @function helper.centrate_icon_with_text
-- @tparam[opt] box icon_node Gui box node
-- @tparam[opt] text text_node Gui text node
-- @tparam[opt=0] number margin Offset between nodes
function M.centrate_icon_with_text(icon_node, text_node, margin)
	M.centrate_nodes(margin, icon_node, text_node)
end


--- Center several nodes nodes.
-- Nodes will be center around 0 x position
-- @function helper.centrate_nodes
-- @tparam[opt=0] number margin Offset between nodes
-- @tparam[opt] Node ... Any count of gui Node
function M.centrate_nodes(margin, ...)
	margin = margin or 0

	local width = 0
	local count = select("#", ...)
	local node_widths = {}

	-- We need to get total width
	for i = 1, count do
		local node = select(i, ...)
		node_widths[i] = get_width(node)
		width = width + node_widths[i]
	end

	-- Posing all elements
	local pos_x = 0
	for i = 1, count do
		local node = select(i, ...)
		local node_width = node_widths[i]
		local pos = gui.get_position(node)

		pos_x = pos_x + node_width/2 -- made offset for single item

		local pivot_offset = M.get_pivot_offset(gui.get_pivot(node))
		pos.x = pos_x - width/2 + pivot_offset.x * node_width -- centrate node
		gui.set_position(node, pos)

		pos_x = pos_x + node_widths[i]/2 + margin -- add second part of offset
	end
end


function M.step(current, target, step)
	if current < target then
		return math.min(current + step, target)
	else
		return math.max(target, current - step)
	end
end


function M.clamp(a, min, max)
	if min > max then
		min, max = max, min
	end

	if a >= min and a <= max then
		return a
	elseif a < min then
		return min
	else
		return max
	end
end


function M.distance(x1, y1, x2, y2)
	return math.sqrt((x2 - x1) ^ 2 + (y2 - y1) ^ 2)
end


function M.sign(val)
	if val == 0 then
		return 0
	end

	return (val < 0) and -1 or 1
end


function M.round(num, numDecimalPlaces)
	local mult = 10^(numDecimalPlaces or 0)
	return math.floor(num * mult + 0.5) / mult
end


function M.lerp(a, b, t)
	return a + (b - a) * t
end


function M.contains(t, value)
	for i = 1, #t do
		if t[i] == value then
			return i
		end
	end
	return false
end


--- Check if node is enabled in gui hierarchy.
-- Return false, if node or any his parent is disabled
-- @function helper.is_enabled
-- @tparam node node Gui node
-- @treturn bool Is enabled in hierarchy
function M.is_enabled(node)
	local is_enabled = gui.is_enabled(node)
	local parent = gui.get_parent(node)
	while parent and is_enabled do
		is_enabled = is_enabled and gui.is_enabled(parent)
		parent = gui.get_parent(parent)
	end

	return is_enabled
end


--- Get node offset for given gui pivot
-- @function helper.get_pivot_offset
-- @tparam gui.pivot pivot The node pivot
-- @treturn vector3 Vector offset with [-1..1] values
function M.get_pivot_offset(pivot)
	return const.PIVOTS[pivot]
end


--- Check if device is mobile (Android or iOS)
-- @function helper..is_mobile
function M.is_mobile()
	return const.CURRENT_SYSTEM_NAME == const.OS.IOS or
			 const.CURRENT_SYSTEM_NAME == const.OS.ANDROID
end


--- Check if device is HTML5
-- @function helper.is_web
function M.is_web()
	return const.CURRENT_SYSTEM_NAME == const.OS.BROWSER
end


--- Distance from node position to his borders
-- @function helper.get_border
-- @tparam node node The gui node to check
-- @tparam vector3 offset The offset to add to result
-- @return vector4 Vector with distance to node border: (left, top, right, down)
function M.get_border(node, offset)
	local pivot = gui.get_pivot(node)
	local pivot_offset = M.get_pivot_offset(pivot)
	local size = vmath.mul_per_elem(gui.get_size(node), gui.get_scale(node))
	local border = vmath.vector4(
		-size.x*(0.5 + pivot_offset.x),
		size.y*(0.5 - pivot_offset.y),
		size.x*(0.5 - pivot_offset.x),
		-size.y*(0.5 + pivot_offset.y)
	)

	if offset then
		border.x = border.x + offset.x
		border.y = border.y + offset.y
		border.z = border.z + offset.x
		border.w = border.w + offset.y
	end

	return border
end


--- Show deprecated message. Once time per message
-- @function helper.deprecated
-- @tparam string message The deprecated message
local _deprecated_messages = {}
function M.deprecated(message)
	if _deprecated_messages[message] then
		return
	end

	print("[Druid]: " .. message)
	_deprecated_messages[message] = true
end


-- Show message to require extended component
function M.extended_component(component_name)
	print(string.format("[Druid]: The component %s is extended component. You have to register it via druid.register to use it", component_name))
	print("[Druid]: Use next code:")
	print(string.format('local %s = require("druid.extended.%s")', component_name, component_name))
	print(string.format('druid.register("%s", %s)', component_name, component_name))
end


return M
