_G.round = function(val)
	return math.floor(val + 0.5)
end

function _G.destroy(entity, parent)
	if parent == nil then parent = _G.world end
	for k,v in pairs(parent) do
		if v == entity then
			if type(k) == "number" then
				--print("Remove entity at index " .. k)
				table.remove(parent, k)
			else
				--print("Remove entity by name " .. k)
				parent[k] = nil
			end
			return
		elseif type(v) == "table" then
			_G.destroy(entity, v)
		end
	end
end

function _G.find(name, parent)
	if parent == nil then parent = _G.world end
	for _,v in pairs(parent) do
		if type(v) == "table" then
			if v.name == name then
				--print("Found object with name " .. name)
				return v, parent
			else
				local foundInChildren, foundInChildrenParent = _G.find(name, v)
				if foundInChildren then
					return foundInChildren, foundInChildrenParent
				end
			end
		end
	end

end

function clamp(val, v0, v1)
	if val < math.min(v0, v1) then return math.min(v0, v1) end
	if val > math.max(v0, v1) then return math.max(v0, v1) end
	return val
end

--[[
rawnext = next
function next(t,k)
  local m = getmetatable(t)
  local n = m and m.__next or rawnext
  return n(t,k)
end
]]

function pairs(t) return next, t, nil end

function copy(entity, result)
	if result == nil then
		result = {}
	end
	for k,v in pairs(entity) do
		if (type(v) == "table") then
			result[k] = copy(v)
		else
			result[k] = v
		end
	end
	return result
end

local remainings = 0
function _G.wait(duration, ignoreTimeScale)
	local getTime = function() return ignoreTimeScale and _G.realTime or _G.time end
	local lastTime = getTime()
	duration = duration + remainings
	while duration > 0 do
		coroutine.yield()
		duration = duration - (getTime() - lastTime)
		lastTime = getTime()
	end
	remainings = duration
end

function instance(args)
	local result = copy(args[1])
	if args ~= nil then
		for k,v in pairs(args) do
			if k ~= 1 then
				if string.find(k, "_") then
					local lastObject
					local object = result
					local key
					for k in string.gmatch(k, "%w+") do
						lastObject = object
						if object == nil then print("Trying to assign value to a non-existing table in an instance. Typo?") end
						object = object[k]
						key = k
					end
					if tonumber(key) ~=nil then
						lastObject[tonumber(key)] = v
					else
						lastObject[key] = v
					end

				else
					result[k] = v
				end
			end
		end
	end
	return result
end

function get(val)
	if type(val) == "function" then
		return get(val())
	else
		return val
	end
end

function contains(table, val)
	for _,v in pairs(table) do
		if v == val then return true end
	end
	return false
end

function shuffle(items)
	local keys = {}
	local values = {}
	for k,v in ipairs(items) do
		table.insert(keys, k)
		table.insert(values, v)
	end
	for i in ipairs(keys) do
		local randomIndex = math.floor(math.random(1, #values))
		items[i] = values[randomIndex]
		table.remove(values, randomIndex)
	end
	return items
end

function _G.lerp(from, to, factor)
	if type(factor) == "function" then
		return function() return _G.lerp(from, to, _G.get(factor)) end
	else
		if factor == 1 then return to
		elseif factor == 0 then return from
		else return from + (to - from) * math.min(math.max(factor, 0), 1) end
	end
end

function gridLayout(objects, cols, cellWidth, cellHeight, useZ)
	cols = cols or #objects
	cellWidth = cellWidth or 0
	cellHeight = cellHeight or 0
	local width = math.min(#objects, cols) * (cellWidth or 0)
	local height = math.ceil(#objects / cols) * (cellHeight or 0)
	for k,v in ipairs(objects) do
		v.x = ((k - 1) % cols) * cellWidth - width / 2 + cellWidth / 2
		local pos = height - math.floor((k - 1) / cols) * cellHeight - height / 2 - cellHeight / 2
		if useZ then v.z = pos else	v.y = pos end
	end
	return objects
end

function calcGridPosition(cols, rows, cellWidth, cellHeight, index)
	local width = cols * cellWidth
	local height = rows * cellHeight
	return {
		x = ((index - 1) % cols) * cellWidth - width / 2 + cellWidth / 2,
		y = height - math.floor((index - 1) / cols) * cellHeight - height / 2 - cellHeight / 2
	}
end

function _G.tween(from, to, duration, delay, loop, modifier)
	if delay == nil then delay = 0 end
	local startTime = _G.time
	--duration = duration + delay
	return function()
		local time = 1 - (startTime + duration - _G.time) / duration - delay / duration
		time = math.max(time, 0)
		if loop == "pingpong" then
			time = time % 2
			if time > 1 then
				time = time - 2 * (time % 1)
			end
		elseif loop then
			time = time % 1
		else
			time = math.min(time, 1)
		end
		local val = _G.lerp(from, to, time)
		if modifier ~= nil then
			val = modifier(val, time, from, to)
		end
		return val
	end
end

function discreteTween(values, duration)
	local startTime = time
	return function()
		local factor = math.mod(1 - (startTime + duration - time) / duration, 1)
		--print(math.ceil(factor * #values))
		--return values[#values]
		return values[math.ceil(factor * #values)]
	end
end

function _G.range(from, to, table)
	local result = {}
	if type(table) == "function" then
		--print(from)
		for i = from, to do
			--print(i)
			result[i - from + 1] = table(i)
		end
	else
		for i = from, to do
			if i >= from then
				result[i - from + 1] = table[i]
			else
				table[i - from + 1] = nil
			end
		end
	end
	return result
end

function _G.take(count, tableOrFunc)
	--print("Take")
	return _G.range(1, count, tableOrFunc)
end

function _G.lazyTable(f)
	--print("Make lazy table")
	return setmetatable({}, {
		__index = function(table, key)
					if type(key) == "number" then
						local val = f(key)
						table[key] = val
						return val
					else
						return nil
					end
				end
	})
end

function clone(table, count)
	local result = {}
	for i = 1, count do
		result[i] = copy(table)
	end
	return result
end

function merge(target, source)
	for k,v in pairs(source) do
		target[k] = v
	end
	return target
end

function clear(table)
	for k in pairs(table) do
		table[k] = nil
	end
end

function concat(a,b)
	local result = {}
	for i = 1, #a do
		result[i] = a[i]
	end
	for i = 1, #b do
		result[#result+1] = b[i]
	end
	print(#result)
	return result
end

function append(target, value)
	table.insert(target, value)
	return target
end

function apply(func, table)
	for i = 1, #table do
		func(table[i], i)
	end
	return table
end

function map(func, table)
	for i = 1, #table do
		table[i] = func(table[i], i)
	end
	return table
end

function mapIndexed3D(table, func, width, height, depth)
	for x = 1, width do
		for y = 1, height do
			for z = 1, depth do
				table[(x - 1)+width*(y-1)+width*height*(z-1) + 1] = func(x, y, z)
			end
		end
	end
	return table
end

function length(x, y, z)
	return math.sqrt(x*x + y*y + z*z)
end

function crop2D(table, columns, condition)
	local left = #table
	local top = #table
	local right = 0
	local bottom = 0
	assert(#table / columns == math.floor(#table / columns))
	for x = 1, columns do
		for y = 1, #table / columns do
			if condition(table[(y - 1) * columns + x]) then
				left = math.min(left, x)
				right = math.max(right, x)
				top = math.min(top, y)
				bottom = math.max(bottom, y)
			end
		end
	end

	local croppedTable = {}
	local width = right - left + 1
	for x = 1, width do
		for y = 1, bottom - top + 1 do
			croppedTable[(y - 1) * width + x] = table[(y - 1 + top - 1) * columns + x + left - 1]
		end
	end

	for i = 1, #table do
		table[i] = croppedTable[i]
	end

	return table, width
end

function numberToCardIdentifier(i)
	if i == 1 or i == 14 then return "A" end
	if i == 11 then return "J" end
	if i == 12 then return "Q" end
	if i == 13 then return "K" end
	return i
end


if persistence.isMusicMuted == nil then persistence.isMusicMuted = false end
if persistence.isSoundMuted == nil then persistence.isSoundMuted = false end
audio.muteMusic(persistence.isMusicMuted)
audio.muteSound(persistence.isSoundMuted)

buttonMuteMusic = {
	sprite = "mute01",
	collider = "sprite",
	u_color = { 1, 1, 1, 1 },
	scale = 0.7,
	onPress = function() persistence.isMusicMuted = not persistence.isMusicMuted; audio.muteMusic(persistence.isMusicMuted); _G.save() end,
	y = 360,
	x = function() return (persistence.screenWidth / 2) / (persistence.screenHeight / config.height) - 50 end,
	{
		enabled = function() return persistence.isMusicMuted end,
		sprite = "disabled",
		x = -4,
		y = 4,
		u_color = function() return buttonMuteMusic.u_color end, --wtf
	}
}

buttonMuteSound = {
	sprite = "mute02",
	collider = "sprite",
	u_color = { 1, 1, 1, 1 },
	scale = 0.7,
	onPress = function() persistence.isSoundMuted = not persistence.isSoundMuted; audio.muteSound(persistence.isSoundMuted); _G.save() end,
	y = 260,
	x = function() return (persistence.screenWidth / 2) / (persistence.screenHeight / config.height) - 50 end,
	{
		enabled = function() return persistence.isSoundMuted end,
		sprite = "disabled",
		x = -4,
		y = 4,
		u_color = function() return buttonMuteSound.u_color end, --wtf
	}
}

function _G.timer(duration, repeatCount, f)
	local timesRepeated = 0
	local stop = false
	local overflow = 0
	return coroutine.create(function()
		while (repeatCount < 0 or timesRepeated < _G.get(repeatCount)) and stop == false do
			f()
			local nextExecute = _G.time + duration - overflow
			while _G.time < nextExecute do
				coroutine.yield()
			end
			overflow = _G.time - nextExecute
		end
	end)
end


_G.bezier = {
	findSpline = function(u, nodes)
	  for i = 1, #nodes, 8 do
	    if nodes[i] <= u and nodes[i + 6] >= u then
	      return { nodes[i], nodes[i + 1], nodes[i + 2], nodes[i + 3], nodes[i + 4], nodes[i + 5], nodes[i + 6], nodes[i + 7] }
	    end
	  end
		print("Didn't find spline " .. u)
	end,

	normalizeX = function(target, left, right, anchor1, anchor2, control1, control2)
		if left == target or right == target then
			--print("return target " .. target)
			return target
		end
	  local u = left + math.abs(right - left) / 2
	  local value = math.pow(u,3)*(anchor2.x+3*(control1.x-control2.x)-anchor1.x)+3*math.pow(u,2)*(anchor1.x-2*control1.x+control2.x)+3*u*(control1.x-anchor1.x)+anchor1.x
	  if math.abs(value - target) < 0.00001 then
	    return u
	  else
	    return _G.bezier.normalizeX(target, target > value and u or left, target < value and u or right, anchor1, anchor2, control1, control2)
	  end
	end,

	make = function(nodes, modifier)
		return function(_, time, from, to)
			local multiplier = _G.bezier.interpolate(time, nodes).y
			local result = from + (to - from) * multiplier
			--print("Result before mod " .. result)
			if modifier ~= nil then
				result = modifier(result, time, from, to)
			end
			--print("Result after mod " .. result)
			return result
		end
	end,

	interpolate = function(u, nodes)
		local spline = _G.bezier.findSpline(u, nodes)
	  local anchor1 = { x = spline[1], y = spline[2] }
	  local anchor2 = { x = spline[7], y = spline[8] }
	  local control1 = { x = spline[3], y = spline[4] }
	  local control2 = { x = spline[5], y = spline[6] }
	  u = _G.bezier.normalizeX(u, 0, 1, anchor1, anchor2, control1, control2)
	  return {
	    x = math.pow(u,3)*(anchor2.x+3*(control1.x-control2.x)-anchor1.x)+3*math.pow(u,2)*(anchor1.x-2*control1.x+control2.x)+3*u*(control1.x-anchor1.x)+anchor1.x,
	    y = math.pow(u,3)*(anchor2.y+3*(control1.y-control2.y)-anchor1.y)+3*math.pow(u,2)*(anchor1.y-2*control1.y+control2.y)+3*u*(control1.y-anchor1.y)+anchor1.y,
	  }
	end
}


function sawtooth(min, max, phase)
	local sign = phase / math.abs(phase)
	phase = (phase % 1)
	local result
	if phase < 0.25 then
		return lerp((max - min) / 2, max, phase / 0.25)
	elseif phase < 0.75 then
		return lerp(max, min, (phase - 0.25) / 0.5)
	else
		return lerp(min, (max - min) / 2, (phase - 0.75) / 0.25)
	end
end

function flipDirection(phase, offset)
	if phase % 0.5 < 0.25 then
		return offset + (0.25 - (phase % 0.25)) * 2
	else
		return offset - (phase % 0.25) * 2
	end
end

camera = { camera = { width = config.width, height = config.height } }
