local S = core.get_translator("cow_gui")

cow_gui = {}

local DEFAULT_FOV = 72

local huds = {}

local countdown = nil

local FOV_MIN = 12
local FOV_MAX = 120

local function get_hud(player, hud_name)
	for h=1, #huds do
		local def = player:hud_get(huds[h])
		if def.name == hud_name then
			-- returns HUD id, list in huds table, HUD definition
			return huds[h], h, def
		end
	end
end

-- Pixel width and height of a single score digit image
local DIGIT_SIZE = 64
-- Width of colon image in pixels
local COLON_WIDTH = 20

-- Maximum score that can be displayed. At very high scores,
-- precision errors due to the Lua number format might kick in,
-- but also the score image might become too dig for [combine:,
-- so we stop right at this score.
local MAX_DISPLAYABLE_SCORE = 999999999999999

local render_integer_combine_string = function(num, start_x, leading_zeroes, y_coord)
	local digits = {}
	local m = 1
	if not leading_zeroes then
		leading_zeroes = 1
	end
	repeat
		local digit = math.floor((num % (10^m)) / (10^(m-1)))
		table.insert(digits, digit)
		m = m+1
	until 10^(m-1) > num and m > leading_zeroes
	local tex = ""
	local i = 0
	if not start_x then
		start_x = 0
	end
	if not y_coord then
		y_coord = 0
	end
	for d=#digits, 1, -1 do
		local digit = digits[d]
		local x = start_x + i*DIGIT_SIZE
		tex = tex .. x..","..y_coord.."=cow_gui_digits.png\\^[sheet\\:10x1\\:"..digit..",0"
		if d > 1 then
			tex = tex .. ":"
		end
		i = i + 1
	end
	return tex, start_x + #digits * DIGIT_SIZE
end

function cow_gui.render_integer(num, leading_zeroes, square)
	num = math.min(MAX_DISPLAYABLE_SCORE, math.max(0, num))
	num = math.floor(num)
	local tex, width
	if square then
		local _
		_, width = render_integer_combine_string(num, nil, leading_zeroes)
		local sw = math.max(width, DIGIT_SIZE)
		local center_y = math.floor(sw/2)
		tex, width = render_integer_combine_string(num, nil, leading_zeroes, center_y)
		tex = "[combine:"..sw.."x"..sw..":"..tex
	else
		tex, width = render_integer_combine_string(num, nil, leading_zeroes)
		tex = "[combine:"..width.."x"..DIGIT_SIZE..":"..tex
	end
	return tex, { x = width, y = DIGIT_SIZE }
end

function cow_gui.show_game_message(player, message_type)
	local texture
	if message_type == "timeout" then
		texture = "cow_gui_times_up.png"
	elseif message_type == "game_over" then
		texture = "cow_gui_game_over.png"
	else
		core.log("error", "[cow_gui] Invalid message_type in show_game_message: "..tostring(message_type))
		return
	end
	local hud, list_id = get_hud(player, "game_message")
	if hud then
		player:hud_change(hud, "text", texture)
	else
		hud = player:hud_add({
			type = "image",
			name = "game_message",
			text = texture,
			position = { x = 0.5, y = 0 },
			scale = { x = 1, y = 1 },
			alignment = { x = 0, y = 1 },
			offset = { x = 0, y = 100 },
			z_index = 71,
		})
		table.insert(huds, hud)
	end
end
function cow_gui.hide_game_message(player)
	local hud, list_id = get_hud(player, "game_message")
	if hud then
		player:hud_remove(hud)
		table.remove(huds, list_id)
	end
end

function cow_gui.show_countdown(player, new_countdown)
	local texture
	if new_countdown == countdown then
		return
	end
	if new_countdown > 0 then
		texture = "cow_gui_countdown_"..new_countdown..".png"
	else
		texture = "cow_gui_countdown_go.png"
	end
	local hud, list_id = get_hud(player, "countdown")
	if hud then
		player:hud_change(hud, "text", texture)
	else
		hud = player:hud_add({
			type = "image",
			name = "countdown",
			text = texture,
			position = { x = 0.5, y = 0 },
			scale = { x = 1, y = 1 },
			alignment = { x = 0, y = 1 },
			offset = { x = 0, y = 40 },
			z_index = 70,
		})
		table.insert(huds, hud)
	end
	countdown = new_countdown
end
function cow_gui.hide_countdown(player)
	local hud, list_id = get_hud(player, "countdown")
	if hud then
		player:hud_remove(hud)
		table.remove(huds, list_id)
	end
end

function cow_gui.show_score(player, score)
	local hud = get_hud(player, "score")
	local tex, size = cow_gui.render_integer(score)
	if hud then
		player:hud_change(hud, "text", tex)
		player:hud_change(hud, "size", size)
	else
		hud = player:hud_add({
			type = "image",
			name = "score",
			text = tex,
			position = { x = 1, y = 0 },
			scale = { x = 1, y = 1 },
			size = size,
			alignment = { x = -1, y = 1 },
			offset = { x = -32, y = 32 },
			z_index = 80,
		})
		table.insert(huds, hud)
	end
end
function cow_gui.hide_score(player, score)
	local hud, list_id = get_hud(player, "score")
	if hud then
		player:hud_remove(hud)
		table.remove(huds, list_id)
	end
end

function cow_gui.show_score_in_world(pos, score)
	local size
	if score < 10 then
		size = 5
	elseif score < 100 then
		size = 10
	elseif score < 1000 then
		size = 24
	else
		size = 36
	end
	core.add_particlespawner({
		amount = 1,
		time = 0.001,
		pos = pos,
		vel = vector.new(0, 1, 0),
		texture = {
			name = cow_gui.render_integer(score, nil, true),
			alpha_tween = { start = 0.8, 1, 0 },
		},
		exptime = 3,
		size = size,
	})
end

local render_time = function(seconds)
	seconds = math.floor(seconds)
	seconds = math.max(0, seconds)
	local minutes = math.floor(seconds / 60)
	local seconds_mod = seconds % 60

	-- Limit maximum displayable minutes and seconds
	if minutes >= 999999 then
		minutes = 999999 
		seconds_mod = 59
	end

	local tex_minutes, m_w = render_integer_combine_string(minutes)
	local c_w = COLON_WIDTH
	local tex_seconds, s_w = render_integer_combine_string(seconds_mod, m_w + c_w, 2)
	local w = m_w + c_w + s_w
	local tex = "[combine:"..w.."x"..DIGIT_SIZE..":"..tex_minutes..":"..(m_w)..",0=cow_gui_colon.png:"..tex_seconds
	return tex, { x = w, y = DIGIT_SIZE }
end

function cow_gui.show_time(player, seconds)
	local hud = get_hud(player, "time")
	local tex, size = render_time(seconds)
	if hud then
		player:hud_change(hud, "text", tex)
		player:hud_change(hud, "size", size)
	else
		hud = player:hud_add({
			type = "image",
			name = "time",
			text = tex,
			position = { x = 0.5, y = 0 },
			scale = { x = 1, y = 1 },
			size = size,
			alignment = { x = 0, y = 1 },
			offset = { x = 0, y = 32 },
			z_index = 60,
		})
		table.insert(huds, hud)
	end
end
function cow_gui.hide_time(player)
	local hud, list_id = get_hud(player, "time")
	if hud then
		player:hud_remove(hud)
		table.remove(huds, list_id)
	end
end

function cow_gui.show_lives(player, lives)
	local hud = get_hud(player, "lives")
	if hud then
		player:hud_change(hud, "number", lives*2)
	else
		hud = player:hud_add({
			type = "statbar",
			name = "lives",
			number = lives*2,
			text = "cow_gui_life.png",
			position = { x = 0, y = 0 },
			scale = { x = 1, y = 1 },
			size = { x = 64, y = 64 },
			alignment = { x = 1, y = 1 },
			offset = { x = 32, y = 32 },
			z_index = 59,
		})
		table.insert(huds, hud)
	end
end
function cow_gui.hide_lives(player)
	local hud, list_id = get_hud(player, "lives")
	if hud then
		player:hud_remove(hud)
		table.remove(huds, list_id)
	end
end

function cow_gui.show_boost(player, state)
	local hud = get_hud(player, "boost")
	local texture
	if state == "recharging" then
		texture = "cow_gui_boost_recharging.png"
	elseif state == "ready" then
		texture = "cow_gui_boost_ready.png"
	elseif state == "arming" then
		texture = "cow_gui_boost_arming.png"
	end

	if hud then
		player:hud_change(hud, "text", texture)
	else
		hud = player:hud_add({
			type = "image",
			name = "boost",
			text = texture,
			position = { x = 0.5, y = 1 },
			scale = { x = 1, y = 1 },
			size = { x = 64, y = 64 },
			alignment = { x = 0, y = -1 },
			offset = { x = 0, y = -24 },
			z_index = 81,
		})
		table.insert(huds, hud)
	end
end
function cow_gui.hide_boost(player)
	local hud, list_id = get_hud(player, "boost")
	if hud then
		player:hud_remove(hud)
		table.remove(huds, list_id)
	end
end

core.register_on_joinplayer(function(player)
	player:set_formspec_prepend("bgcolor[#a2c04700]"..
		"background9[0,0;10,10;cow_gui_formspec_border.png;true;12]"..
		"style_type[image_button;border=false;content_offset=0]"..
		"style_type[button;bgcolor=#55a058;textcolor=#ebecdc]"..
		"style_type[button,button_exit,image_button;sound=cow_gui_select]"..
		"style_type[label;textcolor=#232228]"..
		"style_type[textarea;textcolor=#232228]")
end)
