-- Debugging dialog for triggers. Shows a list of
-- all triggers.

if minetest.settings:get_bool("lzr_debug", false) == false then
	-- Debug dialog is only available if debug setting is
	-- enabled
	return
end

local S = minetest.get_translator("lzr_triggers")
local FS = function(...) return minetest.formspec_escape(S(...)) end
local F = minetest.formspec_escape

local COLOR_CAPTION = "#FFFFFF"
local COLOR_NONTRIGGER = "#BBBBBB"
local COLOR_ERROR = "#e28e0f"
local COLOR_SENDER = "#39df3b"
local COLOR_RECEIVER = "#df3939"
local COLOR_SENDER_RECEIVER = "#e2c70f"

local IMAGE_ID_BLANK = 0
local IMAGE_ID_SENDER = 1
local IMAGE_ID_RECEIVER = 2
local IMAGE_ID_SENDER_RECEIVER = 3
local IMAGE_ID_BAD_TRIGGER = 4


local trigger_type_images = "0=blank.png^[resize:16x16,1=lzr_triggers_icon_sender.png^[resize:16x16,2=lzr_triggers_icon_receiver.png^[resize:16x16,3=lzr_triggers_icon_sender_receiver.png^[resize:16x16,4=lzr_triggers_icon_error.png^[resize:16x16"
local sender_type_images = ""
for s=0, lzr_triggers.MAX_SENDER_TYPE do
	sender_type_images = sender_type_images .. s .. "=" .. lzr_triggers.SENDER_TYPE_ICONS[s]
	sender_type_images = sender_type_images .. ","
end
sender_type_images = sender_type_images .. (lzr_triggers.MAX_SENDER_TYPE + 1) .. "=lzr_triggers_icon_unknown.png,"
sender_type_images = sender_type_images .. (lzr_triggers.MAX_SENDER_TYPE + 2) .. "=blank.png^[resize:16x16"

local receiver_type_images = ""
for r=0, lzr_triggers.MAX_RECEIVER_TYPE do
	receiver_type_images = receiver_type_images .. r .. "=" .. lzr_triggers.RECEIVER_TYPE_ICONS[r]
	receiver_type_images = receiver_type_images .. ","
end
receiver_type_images = receiver_type_images .. (lzr_triggers.MAX_RECEIVER_TYPE + 1) .. "=lzr_triggers_icon_unknown.png,"
receiver_type_images = receiver_type_images .. (lzr_triggers.MAX_RECEIVER_TYPE + 2) .. "=blank.png^[resize:16x16"

local SENDER_TYPE_IMAGE_ID_BLANK = lzr_triggers.MAX_SENDER_TYPE + 2
local RECEIVER_TYPE_IMAGE_ID_BLANK = lzr_triggers.MAX_RECEIVER_TYPE + 2

local last_trigger_list = nil
local last_signal_list = nil

local show_trigger_dialog = function(player, selected_trigger)
	local form = "formspec_version[7]"..
		"size[14,10]"..
		"box[0,0;14,0.8;#00000080]"..
		"label[0.4,0.4;"..FS("Triggers").."]"

	local tstrs = {}
	local triggers = lzr_triggers.get_triggers()
	local row = 1
	local selected_idx
	last_trigger_list = { false }

	local triggers_ok, _, bad_trigger_ids_list = lzr_triggers.check_triggers(false)
	local bad_trigger_ids_keyed = {}
	if not triggers_ok then
		for i=1, #bad_trigger_ids_list do
			bad_trigger_ids_keyed[bad_trigger_ids_list[i]] = true
		end
	end

	local sorted_triggers = lzr_triggers.sort_triggers(triggers)

	for t=1, #sorted_triggers do
		local trigger_id = sorted_triggers[t].trigger_id
		local def = sorted_triggers[t].def
		if trigger_id == selected_trigger then
			selected_idx = row + 1
		end
		table.insert(last_trigger_list, trigger_id)
		local cnt_receivers = #lzr_triggers.get_receivers(trigger_id)
		local cnt_senders = #lzr_triggers.get_senders(trigger_id)
		local tstr = ""
		-- bad trigger (error)
		if bad_trigger_ids_keyed[trigger_id] then
			tstr = tstr .. COLOR_ERROR..","..IMAGE_ID_BAD_TRIGGER..","
		-- neither sender nor receiver
		elseif cnt_receivers == 0 and cnt_senders == 0 then
			tstr = tstr .. COLOR_NONTRIGGER..","..IMAGE_ID_BLANK..","
		-- sender
		elseif cnt_receivers > 0 and cnt_senders == 0 then
			tstr = tstr .. COLOR_SENDER..","..IMAGE_ID_SENDER..","
		-- receiver
		elseif cnt_receivers == 0 and cnt_senders > 0 then
			tstr = tstr .. COLOR_RECEIVER..","..IMAGE_ID_RECEIVER..","
		-- sender-receiver
		else
			tstr = tstr .. COLOR_SENDER_RECEIVER..","..IMAGE_ID_SENDER_RECEIVER..","
		end
		tstr = tstr .. F(trigger_id) .. ","
		if def.location == "player" then
			tstr = tstr .. FS("player")..","

			local item = lzr_triggers.find_trigger_in_player_inventory(player, trigger_id)
			if item then
				tstr = tstr .. F(ItemStack(item:get_name()):get_short_description()) .. ","
			else
				-- not translated; "unknown" refers to the unknown item
				tstr = tstr .. "unknown,"
			end
		elseif type(def.location) == "table" then
			local pstr = minetest.pos_to_string(def.location)
			if pstr == trigger_id then
				-- If location is equal to the trigger_id,
				-- this implies the node is still at the
				-- initial position (since trigger_id is based
				-- on the initial node position).
				-- This is indicated by the word "start"
				tstr = tstr .. FS("start")..","
			else
				tstr = tstr .. F(minetest.pos_to_string(def.location))..","
			end

			local node = minetest.get_node(def.location)
			local ndesc = ItemStack(node.name):get_short_description()
			if not ndesc or ndesc == "" then
				ndesc = node.name
			end
			tstr = tstr .. F(ndesc) .. ","
		else
			tstr = tstr .. F(tostring(def.location))..","
			-- not translated; "unknown" refers to the unknown item
			tstr = tstr .. "unknown,"
		end
		tstr = tstr .. cnt_receivers..","
		tstr = tstr .. cnt_senders..","

		local sender_type = def.sender_type
		if sender_type < 0 or sender_type > lzr_triggers.MAX_SENDER_TYPE then
			sender_type = lzr_triggers.MAX_SENDER_TYPE+1
		end
		local sender_type_desc = lzr_triggers.SENDER_TYPE_NAMES_SHORT[def.sender_type] or def.sender_type
		tstr = tstr .. sender_type..","..sender_type_desc..","

		local receiver_type = def.receiver_type
		if receiver_type < 0 or receiver_type > lzr_triggers.MAX_RECEIVER_TYPE then
			receiver_type = lzr_triggers.MAX_RECEIVER_TYPE+1
		end
		local receiver_type_desc = lzr_triggers.RECEIVER_TYPE_NAMES_SHORT[def.receiver_type] or def.receiver_type
		tstr = tstr .. receiver_type..","..receiver_type_desc

		table.insert(tstrs, tstr)

		row = row + 1
	end
	if not selected_idx then
		selected_idx = 1
	end

	local triggers_str = table.concat(tstrs, ",")
	local trigger_list_elem
	if triggers_str == "" then
		trigger_list_elem = "label[0.5,1.5;"..FS("No triggers.").."]"
	else
		-- Header
		triggers_str = COLOR_CAPTION..","..
			IMAGE_ID_BLANK..","..
			--~ Trigger list header: Trigger identifier
			FS("ID")..","..
			--~ Trigger list header: Trigger location
			FS("Location")..","..
			--~ Trigger list header: Trigger node
			FS("Node")..","..
			--~ Trigger list header: Number of receivers
			FS("#Recv.")..","..
			--~ Trigger list header: Number of senders
			FS("#Send.")..","..
			SENDER_TYPE_IMAGE_ID_BLANK..","..
			--~ Trigger list header: Sender type
			FS("Send. type")..","..
			RECEIVER_TYPE_IMAGE_ID_BLANK..","..
			--~ Trigger list header: Receiver type
			FS("Recv. type")..","..
			triggers_str

		local C_HEAD = "#FFFF00"
		local C_DEF = "#FFFFA0"

		trigger_list_elem = "label[0.5,1.25;"..FS("Triggers:").."]" ..

			-- Explain table columns
			"image[12,1;0.5,0.5;lzr_triggers_icon_tooltip.png]"..
			"tooltip[12,1;0.5,0.5;"..
				minetest.colorize(C_HEAD, FS("Columns:")).."\n"..
				FS("@1: Unique trigger identifier", minetest.colorize(C_DEF, S("ID"))).."\n"..
				FS("@1: Current node location (start = initial position, player = in player inventory)", minetest.colorize(C_DEF, S("Location"))).."\n"..
				FS("@1: Name of the node that triggers", minetest.colorize(C_DEF, S("Node"))).."\n"..
				FS("@1: Number of receivers this trigger sends to", minetest.colorize(C_DEF, S("#Recv."))).."\n"..
				FS("@1: Number of senders this trigger receives from", minetest.colorize(C_DEF, S("#Send."))).."\n"..
				FS("@1: Sender type", minetest.colorize(C_DEF, S("Send. type"))).."\n"..
				FS("@1: Receiver type", minetest.colorize(C_DEF, S("Recv. type"))).."]"

		-- Explain sender type and receiver type abbreviations
		trigger_list_elem = trigger_list_elem ..
			"image[12.75,1;0.5,0.5;lzr_triggers_icon_tooltip.png]"..
			"tooltip[12.75,1;0.5,0.5;"..
			minetest.colorize("#FFFF00", FS("Sender types:")).."\n"

		for i=0, lzr_triggers.MAX_SENDER_TYPE do
			trigger_list_elem = trigger_list_elem .. FS("@1: @2", minetest.colorize(C_DEF, lzr_triggers.SENDER_TYPE_NAMES_SHORT[i]), lzr_triggers.SENDER_TYPE_NAMES[i]) .. "\n"
		end
		trigger_list_elem = trigger_list_elem .. "\n"..minetest.colorize(C_HEAD, FS("Receiver types:")).."\n"
		for i=0, lzr_triggers.MAX_RECEIVER_TYPE do
			trigger_list_elem = trigger_list_elem .. FS("@1: @2", minetest.colorize(C_DEF, lzr_triggers.RECEIVER_TYPE_NAMES_SHORT[i]), lzr_triggers.RECEIVER_TYPE_NAMES[i])
			if i < lzr_triggers.MAX_RECEIVER_TYPE then
				trigger_list_elem = trigger_list_elem .. "\n"
			end
		end
		trigger_list_elem = trigger_list_elem .. "]"

		-- The table columns, in this order
		-- row color, sender/receiver icon, trigger_id, location, node name, receiver count, sender count, sender type icon, sender type text, receiver type icon, receiver type text
		trigger_list_elem = trigger_list_elem .. "tablecolumns[color;"..
			"image,"..trigger_type_images..";"..
			"text;text;text;text;text;"..
			"image,"..sender_type_images..";"..
			"text;"..
			"image,"..receiver_type_images..";"..
			"text]"..
			"table[0.5,1.75;13,5;trigger_list;"..triggers_str..";"..selected_idx.."]"
	end
	form = form .. trigger_list_elem

	-- List receivers and senders of selected trigger
	if selected_trigger then
		local receivers = lzr_triggers.get_receivers(selected_trigger)
		local senders = lzr_triggers.get_senders(selected_trigger)
		local info_str = ""
		if #senders > 0 or #receivers > 0 then
			last_signal_list = { false }
			info_str = COLOR_CAPTION..","..
				IMAGE_ID_BLANK..","..
				--~ Trigger list header: Trigger type
				FS("Type")..","..
				--~ Trigger list header: Trigger identifier
				FS("ID")..","
			for r=1, #receivers do
				info_str = info_str .. COLOR_RECEIVER..","..IMAGE_ID_RECEIVER..","..FS("Receiver")..","..F(receivers[r])
				if r < #receivers or #senders > 0 then
					info_str = info_str .. ","
				end
				table.insert(last_signal_list, receivers[r])
			end
			for s=1, #senders do
				info_str = info_str .. COLOR_SENDER ..","..IMAGE_ID_SENDER ..","..FS("Sender")..","..F(senders[s])
				if s < #senders then
					info_str = info_str .. ","
				end
				table.insert(last_signal_list, senders[s])
			end
		else
			last_signal_list = {}
			--~ Shown when there are no triggers in a trigger list
			info_str = COLOR_CAPTION..","..IMAGE_ID_BLANK..","..FS("None")..","
		end

		local info_elem = "label[0.5,7;"..FS("Signals of trigger @1:", selected_trigger).."]" ..
			"tablecolumns[color;image,"..trigger_type_images..";text;text]"..

			"table[0.5,7.25;13,2.25;signal_list;"..info_str..";1]"
		form = form .. info_elem
	end

	minetest.show_formspec(player:get_player_name(), "lzr_triggers:triggers", form)
end

minetest.register_chatcommand("show_triggers", {
	description = S("Show a list of all triggers"),
	privs = { debug = true },
	params = "",
	func = function(name, param)
		local player = minetest.get_player_by_name(name)
		if not player then
			return false, S("No player.")
		end
		show_trigger_dialog(player)
		return true
	end
})


minetest.register_on_player_receive_fields(function(player, formname, fields)
	if formname ~= "lzr_triggers:triggers" then
		last_trigger_list = nil
		last_signal_list = nil
		return
	end
	if fields.quit then
		last_trigger_list = nil
		last_signal_list = nil
		return
	end
	if fields.trigger_list then
		if not last_trigger_list then
			return
		end
		local expl = minetest.explode_table_event(fields.trigger_list)
		if expl.type == "DCL" or expl.type == "CHG" then
			local trigger_id = last_trigger_list[expl.row]
			if trigger_id then
				show_trigger_dialog(player, trigger_id)
			else
				show_trigger_dialog(player)
			end
		end
	end
	if fields.signal_list then
		if not last_signal_list then
			return
		end
		local expl = minetest.explode_table_event(fields.signal_list)
		if expl.type == "DCL" then
			local trigger_id = last_signal_list[expl.row]
			if trigger_id then
				show_trigger_dialog(player, trigger_id)
			end
		end
	end

end)
