local S = minetest.get_translator("lzr_gui")
local NS = function(s) return s end
local F = minetest.formspec_escape

lzr_gui = {}

local current_marker_group
local hud_ids = {}

local hotbar_highlight = {}

local HOTBAR_SIZE_EDITOR = tonumber(minetest.settings:get("lzr_inventory_width_editor") or 8)
HOTBAR_SIZE_EDITOR = math.min(10, math.max(8, HOTBAR_SIZE_EDITOR))

local HOTBAR_SIZE_PLAY = 4
local HOTBAR_IMG_PLAY = "lzr_gui_hotbar_4.png"
local HOTBAR_IMG_PLAY_HIGHLIGHT = "lzr_gui_hotbar_highlight_4.png"
local HOTBAR_IMG_EDITOR = "lzr_gui_hotbar_"..HOTBAR_SIZE_EDITOR..".png"
local HOTBAR_IMG_EDITOR_HIGHLIGHT = "lzr_gui_hotbar_highlight_"..HOTBAR_SIZE_EDITOR..".png"
local HOTBAR_IMG_SELECTED = "lzr_gui_hotbar_selected.png"
local HOTBAR_IMG_SELECTED_HIGHLIGHT = "lzr_gui_hotbar_selected_highlight.png"

local show_loading_screen = function(player)
	-- In the loading screen, the screen is tinted a bit
	local playername = player:get_player_name()
	if hud_ids[playername] and hud_ids[playername].loading_screen then
		-- do nothing if already shown
		return
	else
		local id_screen = player:hud_add({
			type = "image",
			position = { x = -0.01, y = -0.01 },
			name = "loading_screen",
			text = "[fill:16x16:#735D4260",
			number = 0xFFFFFF,
			alignment = { x = 1, y = 1 },
			offset = { x = 0, y = 0 },
			scale = { x = -102, y = -102 },
			size = { x = 1, y = 1 },
			z_index = 79,
		})
		if not hud_ids[playername] then
			hud_ids[playername] = {}
		end
		hud_ids[playername].loading_screen = id_screen
	end
end

local hide_loading_screen = function(player)
	local playername = player:get_player_name()
	if hud_ids[playername] then
		if hud_ids[playername].loading_screen then
			player:hud_remove(hud_ids[playername].loading_screen)
			hud_ids[playername].loading_screen = nil
		end
	end
end

local set_mode_text = function(player, text, hexcolor, z_index)
	local player_name = player:get_player_name()
	if hud_ids[player_name].mode_text then
		if not text then
			player:hud_remove(hud_ids[player_name].mode_text)
			hud_ids[player_name].mode_text = nil
			return
		end
		player:hud_change(hud_ids[player_name].mode_text, "text", text)
		player:hud_change(hud_ids[player_name].mode_text, "number", hexcolor or 0xFFFFFF)
		return
	end
	if not text then
		return
	end

	-- Smaller mode text on small windows
	-- Note this only takes effect when creating this HUD element,
	-- not when the player resizes the window
	local winfo = minetest.get_player_window_information(player_name)
	local size = { x = 3, y = 3 }
	if winfo then
		if winfo.size.y < 600 * winfo.real_hud_scaling then
			size = { x = 1, y = 1 }
		elseif winfo.size.y < 800 * winfo.real_hud_scaling then
			size = { x = 2, y = 2 }
		end
	end

	local id = player:hud_add({
		type = "text",
		position = { x = 0, y = 1 },
		name = "mode_text",
		text = text,
		number = hexcolor or 0xFFFFFF,
		alignment = { x = 1, y = -1 },
		offset = { x = 5, y = -5 },
		scale = { x = 100, y = 100 },
		size = size,
		z_index = z_index or 0,
	})
	local name = player:get_player_name()
	if id then
		hud_ids[player_name].mode_text = id
		return id
	end
end

lzr_gui.hide_treasure_status = function(player)
	local name = player:get_player_name()
	if hud_ids[name].treasures_img then
		player:hud_remove(hud_ids[name].treasures_img)
		hud_ids[name].treasures_img = nil
	end
	if hud_ids[name].treasures_cnt then
		player:hud_remove(hud_ids[name].treasures_cnt)
		hud_ids[name].treasures_cnt = nil
	end
end

lzr_gui.show_pirate_sense_icon = function(player, is_permanent)
	local name = player:get_player_name()
	local texture
	if is_permanent then
		texture = "lzr_gui_pirate_sense.png"
	else
		texture = "lzr_gui_pirate_sense.png^[opacity:130"
	end
	if hud_ids[name].pirate_sense_img then
		player:hud_change(hud_ids[name].pirate_sense_img, "text", texture)
		return
	end

	local winfo = minetest.get_player_window_information(name)
	local position = { x = 1, y = 1 }
	local alignment = { x = -1, y = -1 }
	if winfo and winfo.touch_controls then
		position.y = 0.5
		alignment.y = 0
	end

	local id = player:hud_add({
		type = "image",
		position = position,
		name = "pirate_sense_img",
		text = texture,
		alignment = alignment,
		offset = { x = -10, y = -80 },
		scale = { x = 3, y = 3 },
		size = { x = 3, y = 3 },
		z_index = 5,
	})
	hud_ids[name].pirate_sense_img = id
end

lzr_gui.hide_pirate_sense_icon = function(player)
	local name = player:get_player_name()
	if hud_ids[name].pirate_sense_img then
		player:hud_remove(hud_ids[name].pirate_sense_img)
		hud_ids[name].pirate_sense_img = nil
	end
end

lzr_gui.update_treasure_status = function(player, treasures, total_treasures)
	local name = player:get_player_name()
	local winfo = minetest.get_player_window_information(name)
	local position = { x = 1, y = 1 }
	local alignment = { x = -1, y = -1 }
	if winfo and winfo.touch_controls then
		position.y = 0.5
		alignment.y = 0
	end
	if not hud_ids[name].treasures_img then
		local id = player:hud_add({
			type = "image",
			position = position,
			name = "treasure_img",
			text = "lzr_treasure_gold_block.png",
			alignment = alignment,
			offset = { x = -10, y = -20 },
			scale = { x = 3, y = 3 },
			size = { x = 3, y = 3 },
			z_index = 0,
		})
		hud_ids[name].treasures_img = id
	end
	--~ Treasure count in HUD. @1 = number of found treasures, @2 number of total treasures in level
	local treasure_text = S("@1 / @2", treasures, total_treasures)
	local color = 0xFFFFFFFF
	if treasures >= total_treasures then
		color = 0xFF00FF00
	end
	if not hud_ids[name].treasures_cnt then
		local id = player:hud_add({
			type = "text",
			position = position,
			name = "treasure_cnt",
			text = treasure_text,
			number = color,
			alignment = alignment,
			offset = { x = -70, y = -20 },
			scale = { x = 100, y = 100 },
			size = { x = 3, y = 3 },
			z_index = 0,
		})
		hud_ids[name].treasures_cnt = id
	else
		player:hud_change(hud_ids[name].treasures_cnt, "text", treasure_text)
		player:hud_change(hud_ids[name].treasures_cnt, "number", color)
	end
end

lzr_gui.set_play_gui = function(player, is_testing, hide_hotbar)
	if hide_hotbar then
		player:hud_set_flags({hotbar=false})
	else
		player:hud_set_flags({hotbar=true})
	end
	player:hud_set_hotbar_itemcount(HOTBAR_SIZE_PLAY)
	local name = player:get_player_name()
	if hotbar_highlight[name] then
		player:hud_set_hotbar_image(HOTBAR_IMG_PLAY_HIGHLIGHT)
	else
		player:hud_set_hotbar_image(HOTBAR_IMG_PLAY)
	end
	if is_testing then
		set_mode_text(player, S("Level solution test"))
	else
		set_mode_text(player, nil)
	end
	lzr_gui.hide_level_bounds(player)
	lzr_gui.hide_menu_markers(player)
	hide_loading_screen(player)
end
lzr_gui.set_loading_gui = function(player)
	player:hud_set_flags({hotbar=false})
	show_loading_screen(player)
	set_mode_text(player, S("Loading … "), nil, 80)
	lzr_gui.hide_treasure_status(player)
	lzr_gui.hide_menu_markers(player)
	lzr_gui.hide_level_bounds(player)
	lzr_messages.show_message(player, "")
end

lzr_gui.set_editor_gui = function(player)
	player:hud_set_flags({hotbar=true})
	player:hud_set_hotbar_itemcount(HOTBAR_SIZE_EDITOR)
	local name = player:get_player_name()
	if hotbar_highlight[name] then
		player:hud_set_hotbar_image(HOTBAR_IMG_EDITOR_HIGHLIGHT)
	else
		player:hud_set_hotbar_image(HOTBAR_IMG_EDITOR)
	end
	set_mode_text(player, S("Level Editor"))
	lzr_gui.hide_treasure_status(player)
	lzr_gui.hide_menu_markers(player)
	hide_loading_screen(player)
end
lzr_gui.set_dev_gui = function(player)
	player:hud_set_flags({hotbar=true})
	player:hud_set_hotbar_itemcount(HOTBAR_SIZE_EDITOR)
	local name = player:get_player_name()
	if hotbar_highlight[name] then
		player:hud_set_hotbar_image(HOTBAR_IMG_EDITOR_HIGHLIGHT)
	else
		player:hud_set_hotbar_image(HOTBAR_IMG_EDITOR)
	end
	set_mode_text(player, S("Development Mode"))
	lzr_gui.hide_treasure_status(player)
	lzr_gui.hide_level_bounds(player)
	lzr_gui.hide_menu_markers(player)
	hide_loading_screen(player)
end

-- Show a HUD text explaining the controls of the game.
-- * player: player object
-- * ctype: controls type:
--    * "none": Hide controls GUI
--    * "basic": Basic controls
lzr_gui.set_controls_gui = function(player, ctype)
	local oldhuds = hud_ids[player:get_player_name()].controls
	if oldhuds then
		for o=1, #oldhuds do
			player:hud_remove(oldhuds[o])
		end
	end
	if ctype == "none" then
		hud_ids[player:get_player_name()].controls = nil
		return
	end
	local winfo = minetest.get_player_window_information(player:get_player_name())
	local touch_controls = winfo and winfo.touch_controls == true
	--~ computer mouse
	local LOOK_KEYBOARD = S("Mouse")
	--~ default keys for movement
	local MOVE_KEYBOARD = S("W, A, S, D")
	--~ space bar
	local JUMP_KEYBOARD = S("Space")
	local PUNCH_KEYBOARD = S("Leftclick")
	local PLACE_KEYBOARD = S("Rightclick")
	--~ The 'I' key on the keyboard
	local INVENTORY_KEYBOARD = S("I")
	--~ the Escape key
	local PAUSE_KEYBOARD = S("Escape")
	--~ controls reference: either the mousewheel or the number keys on keyboard (not the numpad)
	local SELECT_ITEM_KEYBOARD = S("Mousewheel or number keys")

	--~ touchscreen gesture
	local LOOK_TOUCH = S("Touch and slide")
	--~ touchscreen control widget
	local MOVE_TOUCH = S("Circle")
	--~ touchscreen control widget
	local JUMP_TOUCH = S("Up arrow")
	--~ touchscreen gesture
	local PUNCH_TOUCH = S("Short tap")
	--~ touchscreen gesture
	local PLACE_TOUCH = S("Long tap")
	--~ explanation on how to open the inventory with touch controls
	local INVENTORY_TOUCH = S("Open hamburger menu, then inventory")
	--~ touchscreen control widget: a button with 3 horizontal lines
	local PAUSE_TOUCH = S("Hamburger menu")
	--~ the bar that selects items
	local SELECT_ITEM_TOUCH = S("Hotbar")

	local texts
	if ctype == "basic" then
		texts = {
			--~ Starts the list of default game controls
			{ NS("Default controls:"), },
			--~ Controls description
			{ NS("Look: @1"), "look" },
			--~ Controls description
			{ NS("Move: @1"), "move" },
			--~ Controls description
			{ NS("Jump: @1"), "jump" },
			--~ Controls description
			{ NS("Interact: @1"), "place" },
			--~ Controls description
			{ NS("Punch: @1"), "punch" },
			--~ Controls description
			{ NS("Menu: @1"), "pause" },
		}
	elseif ctype == "punch" then
		texts = {
			{ NS("Default controls:"), },
			--~ Controls description
			{ NS("Punch: @1"), "punch" },
			{ NS("Interact: @1"), "place" },
			{ NS("Menu: @1"), "pause" },
		}
	elseif ctype == "select_item" then
		texts = {
			{ NS("Default controls:"), },
			--~ Controls description
			{ NS("Select item: @1"), "select_item" },
			{ NS("Punch: @1"), "punch" },
			--~ Controls description
			{ NS("Place/Interact: @1"), "place" },
			{ NS("Inventory/Level selection: @1"), "inventory" },
			{ NS("Menu: @1"), "pause" },
		}
	end
	local yoff = 0
	local huds = {}
	local full_text = ""
	for t=1, #texts do
		local text
		local key = texts[t][2]
		if not key then
			text = S(texts[t][1])
		else
			if not touch_controls then
				if key == "look" then
					text = S(texts[t][1], LOOK_KEYBOARD)
				elseif key == "move" then
					text = S(texts[t][1], MOVE_KEYBOARD)
				elseif key == "jump" then
					text = S(texts[t][1], JUMP_KEYBOARD)
				elseif key == "punch" then
					text = S(texts[t][1], PUNCH_KEYBOARD)
				elseif key == "place" then
					text = S(texts[t][1], PLACE_KEYBOARD)
				elseif key == "inventory" then
					text = S(texts[t][1], INVENTORY_KEYBOARD)
				elseif key == "pause" then
					text = S(texts[t][1], PAUSE_KEYBOARD)
				elseif key == "select_item" then
					text = S(texts[t][1], SELECT_ITEM_KEYBOARD)
				end
			else
				if key == "look" then
					text = S(texts[t][1], LOOK_TOUCH)
				elseif key == "move" then
					text = S(texts[t][1], MOVE_TOUCH)
				elseif key == "jump" then
					text = S(texts[t][1], JUMP_TOUCH)
				elseif key == "punch" then
					text = S(texts[t][1], PUNCH_TOUCH)
				elseif key == "place" then
					text = S(texts[t][1], PLACE_TOUCH)
				elseif key == "inventory" then
					text = S(texts[t][1], INVENTORY_TOUCH)
				elseif key == "pause" then
					text = S(texts[t][1], PAUSE_TOUCH)
				elseif key == "select_item" then
					text = S(texts[t][1], SELECT_ITEM_TOUCH)
				end
			end
		end
		full_text = full_text .. text
		if t < #texts then
			full_text = full_text .. "\n"
		end
	end
	local alignment = { x = 1, y = -1 }
	local position = { x = 0, y = 1 }
	local size = { x = 2, y = 2 }
	if touch_controls then
		alignment.y = 0
		position.y = 0.5
	end
	-- Smaller controls text on small windows
	-- Note this only takes effect when creating this HUD element,
	-- not when the player resizes the window
	if winfo and ((winfo.size.y < 600 * winfo.real_hud_scaling) or (winfo.size.x <= 1680 * winfo.real_hud_scaling)) then
		size = { x = 1, y = 1 }
	end
	local id = player:hud_add({
		type = "text",
		position = position,
		name = "controls_text",
		text = full_text,
		number = 0x99FFFF,
		alignment = alignment,
		offset = { x = 20, y = -20},
		scale = { x = 100, y = 100 },
		size = size,
		z_index = 0,
	})
	table.insert(huds, id)
	hud_ids[player:get_player_name()].controls = huds
end

local book_offset_hor = 0.1
local book_offset_ver = -0.15
local markers = {
	{
		"start",
		S("Start game"),
		"lzr_menu:level_starter",
		vector.new(0, book_offset_ver, -book_offset_hor),
		"captain",
	},
	{
		"start_custom",
		S("Custom levels"),
		"lzr_menu:custom_level_starter",
		vector.new(0, book_offset_ver, -book_offset_hor),
		"captain",
	},
	{
		"editor",
		S("Level editor"),
		"lzr_menu:editor_starter",
		vector.new(0, 0.75, 0),
		"captain",
	},
	{
		"ambience",
		S("Music"),
		"lzr_menu:speaker",
		vector.new(0, 0.75, 0),
		"captain",
	},
	{
		"graphics",
		S("Graphics settings"),
		"lzr_menu:television",
		vector.new(0, 0.75, 0),
		"captain",
	},
	{
		"reset",
		S("Reset game progress"),
		"lzr_menu:reset_bomb",
		vector.new(0, 0.75, 0),
		"bombs",
	},
	{
		"howto",
		S("Game Help"),
		"lzr_menu:bookshelf_info",
		vector.new(0, 0.75, -0.5),
		"captain",
	},
	{
		"howto_editor",
		S("Level Editor Help"),
		"lzr_menu:bookshelf_info_editor",
		vector.new(-0.5, 0.6, 0),
		"captain",
	},
	{
		"howto_blocks",
		S("Blocks"),
		"lzr_menu:bookshelf_info_blocks",
		vector.new(0, 0.75, -0.5),
		"blocks",
	},
	{
		"credits",
		S("Credits"),
		"lzr_menu:bookshelf_credits",
		vector.new(0.5, 0.6, 0),
		"captain",
	},
	{
		"level_packs",
		S("Installed level packs"),
		"lzr_menu:bookshelf_level_packs",
		vector.new(0, 0.75, 0),
		"captain",
	},
}
-- Show menu markers for player. marker_group is the group of
-- markers to be shown (from the markers table)
lzr_gui.show_menu_markers = function(player, marker_group)
	if current_marker_group == marker_group then
		return
	end
	if hud_ids[player:get_player_name()].menu_markers then
		lzr_gui.hide_menu_markers(player)
	end
	if not minetest.global_exists("lzr_menu") or not lzr_menu.ship_analyzed then
		return
	end
	local huds = {}
	for m=1, #markers do
		local mgroup = markers[m][5]
		if mgroup ~= nil and mgroup == marker_group then
			local nodename = markers[m][3]
			local world_pos = vector.add(lzr_globals.MENU_SHIP_POS, lzr_menu.interactive_ship_node_offsets[nodename])
			world_pos = vector.add(world_pos, markers[m][4])
			local id_marker = player:hud_add({
				type = "image_waypoint",
				text = "lzr_gui_menu_marker.png",
				offset = { x = 0, y = 0 },
				scale = { x = 6, y = 6 },
				z_index = -301,
				world_pos = world_pos,
			})
			local id_text = player:hud_add({
				type = "waypoint",
				name = markers[m][2],
				precision = 0,
				number = 0xFFFFFF,
				offset = { x = 0, y = -80 },
				scale = { x = 1, y = 1 },
				z_index = -300,
				alignment = { x = 0, y = 0 },
				world_pos = world_pos,
			})
			if id_marker then
				table.insert(huds, id_marker)
			end
			if id_text then
				table.insert(huds, id_text)
			end
		end
	end
	hud_ids[player:get_player_name()].menu_markers = huds
	current_marker_group = marker_group
end
lzr_gui.hide_menu_markers = function(player)
	current_marker_group = nil
	local name = player:get_player_name()
	if hud_ids[name].menu_markers then
		for m=1, #hud_ids[name].menu_markers do
			player:hud_remove(hud_ids[name].menu_markers[m])
		end
		hud_ids[name].menu_markers = nil
	end
end

lzr_gui.show_level_bounds = function(player, minpos, size)
	lzr_gui.hide_level_bounds(player)
	local maxpos = vector.add(minpos, size)
	local offsets = {
		vector.new(-1, -1, -1),
		vector.new(-1, -1, 1),
		vector.new(-1, 1, -1),
		vector.new(-1, 1, 1),
		vector.new(1, -1, -1),
		vector.new(1, -1, 1),
		vector.new(1, 1, -1),
		vector.new(1, 1, 1),
	}
	local huds = {}
	for o=1, #offsets do
		local offset = offsets[o]
		local corner = vector.zero()
		for _, axis in pairs({"x","y","z"}) do
			if offset[axis] < 0 then
				corner[axis] = minpos[axis] - 0.5
			else
				corner[axis] = maxpos[axis] - 0.5
			end
		end
		local id = player:hud_add({
			type = "image_waypoint",
			name = "editor_level_corner_"..o,
			text = "lzr_gui_level_corner.png",
			precision = 0,
			number = 0xFFFFFF,
			offset = { x = 0, y = 0 },
			scale = { x = 1, y = 1 },
			z_index = -300,
			world_pos = corner,
		})
		if id then
			table.insert(huds, id)
		end
		hud_ids[player:get_player_name()].editor_corners = huds
	end
end
lzr_gui.hide_level_bounds = function(player)
	local name = player:get_player_name()
	if hud_ids[name].editor_corners then
		for c=1, #hud_ids[name].editor_corners do
			player:hud_remove(hud_ids[name].editor_corners[c])
		end
		hud_ids[name].editor_corners = nil
	end
end

lzr_gui.set_menu_gui = function(player, marker_group)
	player:hud_set_flags({hotbar=false})
	-- Same itemcount as in editor
	-- NOTE: Setting this to 1 might lead to problems!
	player:hud_set_hotbar_itemcount(HOTBAR_SIZE_EDITOR)
	local name = player:get_player_name()
	set_mode_text(player, nil)
	lzr_gui.hide_level_bounds(player)
	if marker_group ~= nil then
		lzr_gui.show_menu_markers(player, marker_group)
	else
		lzr_gui.hide_menu_markers(player)
	end
	lzr_gui.hide_treasure_status(player)
	hide_loading_screen(player)
end

-- Set the 'highlight' state of the hotbar for player.
-- * player: Player to set hotbar state for
-- * highlight: true to activate highlight, false to disable it
lzr_gui.set_hotbar_highlight = function(player, highlight)
	local name = player:get_player_name()
	hotbar_highlight[name] = highlight
	local state = lzr_gamestate.get_state()
	if highlight then
		if state == lzr_gamestate.EDITOR then
			player:hud_set_hotbar_image(HOTBAR_IMG_EDITOR_HIGHLIGHT)
		elseif state == lzr_gamestate.LEVEL or state == lzr_gamestate.LEVEL_TEST then
			player:hud_set_hotbar_image(HOTBAR_IMG_PLAY_HIGHLIGHT)
		end
		player:hud_set_hotbar_selected_image(HOTBAR_IMG_SELECTED_HIGHLIGHT)
	else
		if state == lzr_gamestate.EDITOR then
			player:hud_set_hotbar_image(HOTBAR_IMG_EDITOR)
		elseif state == lzr_gamestate.LEVEL or state == lzr_gamestate.LEVEL_TEST then
			player:hud_set_hotbar_image(HOTBAR_IMG_PLAY)
		end
		player:hud_set_hotbar_selected_image(HOTBAR_IMG_SELECTED)
	end
end

minetest.register_on_joinplayer(function(player)
	player:hud_set_flags({minimap = false, minimap_radar = false, healthbar = false, breathbar = false})
	lzr_player.set_menu_inventory(player)
	player:set_formspec_prepend([=[
		listcolors[#5c443280;#a87d5d80;#3b2b2080;#b75647;#ffffff]
		tableoptions[background=#00000030;highlight=#3B6322;border=false]
		background9[0,0;5,5;lzr_gui_bg.png;true;11]
		style_type[button,image_button;bgimg=lzr_gui_button.png;bgimg_middle=4]
		style_type[button:hovered,image_button:hovered;bgimg=lzr_gui_button_hover.png]
		style_type[button:pressed,image_button:pressed;bgimg=lzr_gui_button_pressed.png]
		style_type[button,image_button,item_image_button;sound=lzr_sounds_button]]=])
	player:hud_set_hotbar_selected_image(HOTBAR_IMG_SELECTED)

	local name = player:get_player_name()
	hud_ids[name] = {}
	hotbar_highlight[name] = false
end)

minetest.register_on_leaveplayer(function(player)
	local name = player:get_player_name()
	hud_ids[name] = nil
	hotbar_highlight[name] = nil
end)
