ctf_flag.registered_on_capture = {}
function ctf_flag.register_on_capture(func)
	if ctf._mt_loaded then
		error("You can't register callbacks at game time!")
	end
	table.insert(ctf_flag.registered_on_capture, func)
end

ctf_flag.registered_on_pick_up = {}
function ctf_flag.register_on_pick_up(func)
	if ctf._mt_loaded then
		error("You can't register callbacks at game time!")
	end
	table.insert(ctf_flag.registered_on_pick_up, func)
end

ctf_flag.registered_on_drop = {}
function ctf_flag.register_on_drop(func)
	if ctf._mt_loaded then
		error("You can't register callbacks at game time!")
	end
	table.insert(ctf_flag.registered_on_drop, func)
end

ctf_flag.registered_on_precapture = {}
function ctf_flag.register_on_precapture(func)
	if ctf._mt_loaded then
		error("You can't register callbacks at game time!")
	end
	table.insert(ctf_flag.registered_on_precapture, func)
end

ctf_flag.registered_on_prepick_up = {}
function ctf_flag.register_on_prepick_up(func)
	if ctf._mt_loaded then
		error("You can't register callbacks at game time!")
	end
	table.insert(ctf_flag.registered_on_prepick_up, func)
end

function ctf_flag.collect_claimed()
	local claimed = {}
	for _, team in pairs(ctf.teams) do
		for i = 1, #team.flags do
			if team.flags[i].claimed then
				table.insert(claimed, team.flags[i])
			end
		end
	end
	return claimed
end

function ctf_flag.has_flag(name)
	local claimed = ctf_flag.collect_claimed()
	for _, flag in pairs(claimed) do
		if flag.claimed.player == name then
			return true
		end
	end
	return false
end

function ctf_flag.player_drop_flag(name)
	if not name then
		return
	end

	local claimed = ctf_flag.collect_claimed()
	for i = 1, #claimed do
		local flag = claimed[i]
		if flag.claimed.player == name then
			flag.claimed = nil

			local flag_name = ""
			if flag.name then
				flag_name = flag.name .. " "
			end
			flag_name = flag.team .. "'s " .. flag_name .. "flag"

			ctf.hud.updateAll()

			ctf.action("flag", name .. " dropped " .. flag_name)

			local flag_return_color = "#ffffff"
			if flag_name == "red's flag" then
				flag_return_color = ctf_colors.colors["red"]
			end
			if flag_name == "blue's flag" then
				flag_return_color = ctf_colors.colors["blue"]
			end
			flag_return_color = "#" .. tostring(flag_return_color):sub(3, 8)

			minetest.chat_send_all(minetest.colorize(flag_return_color, (flag_name.." has returned.")))

			for j = 1, #ctf_flag.registered_on_drop do
				ctf_flag.registered_on_drop[j](name, flag)
			end
		end
	end
end

-- add a flag to a team
function ctf_flag.add(team, pos)
	if not team or team == "" then
		return
	end

	ctf.log("flag", "Adding flag to " .. team .. " at (" .. pos.x ..
			", " .. pos.y .. ", " .. pos.z .. ")")

	if not ctf.team(team).flags then
		ctf.team(team).flags = {}
	end

	pos.team = team
	table.insert(ctf.team(team).flags,pos)
end

function ctf_flag.update(pos)
	if minetest.get_node(pos).name ~= "ctf_flag:flag" then
		return
	end

	local top = {x=pos.x,y=pos.y+1,z=pos.z}
	local flagmeta = minetest.get_meta(pos)

	if not flagmeta then
		return
	end

	local flag_team_data = ctf_flag.get(pos)
	if not flag_team_data or not ctf.team(flag_team_data.team)then
		ctf.log("flag", "Flag does not exist! Deleting nodes. "..dump(pos))
		minetest.set_node(pos,{name="air"})
		minetest.set_node(top,{name="air"})
		return
	end

	local flag_name = flag_team_data.name
	if flag_name and flag_name ~= "" then
		flagmeta:set_string("infotext", flag_name.." - "..flag_team_data.team)
	else
		flagmeta:set_string("infotext", flag_team_data.team.."'s flag")
	end

	if not ctf.team(flag_team_data.team).data.color then
		ctf.team(flag_team_data.team).data.color = "red"
	end

	if flag_team_data.claimed then
		minetest.set_node(top,{name="ctf_flag:flag_captured_top"})
	else
		minetest.set_node(top,{name="ctf_flag:flag_top_"..ctf.team(flag_team_data.team).data.color})
	end

	local topmeta = minetest.get_meta(top)
	if flag_name and flag_name ~= "" then
		topmeta:set_string("infotext", flag_name.." - "..flag_team_data.team)
	else
		topmeta:set_string("infotext", flag_team_data.team.."'s flag")
	end
end

function ctf_flag.flag_tick(pos)
	ctf_flag.update(pos)
	minetest.get_node_timer(pos):start(5)
end

-- get a flag from a team
function ctf_flag.get(pos)
	if not pos then
		return
	end

	local result = nil
	for _, team in pairs(ctf.teams) do
		for i = 1, #team.flags do
			if (
				team.flags[i].x == pos.x and
				team.flags[i].y == pos.y and
				team.flags[i].z == pos.z
			) then
				if result then
					minetest.chat_send_all("[CTF ERROR] Multiple teams have same flag. Please report this to the server operator / admin")
					print("CTF ERROR DATA")
					print("Multiple teams have same flag.")
					print("This is a sign of ctf.txt corruption.")
					print("----------------")
					print(dump(result))
					print(dump(team.flags[i]))
					print("----------------")
				else
					result = team.flags[i]
				end
			end
		end
	end
	return result
end

-- delete a flag from a team
function ctf_flag.delete(team, pos)
	if not team or team == "" then
		return
	end

	ctf.log("flag", "Deleting flag from " .. team .. " at (" .. pos.x ..
			", " .. pos.y .. ", " .. pos.z .. ")")

	for i = 1, #ctf.team(team).flags do
		if (
			ctf.team(team).flags[i].x == pos.x and
			ctf.team(team).flags[i].y == pos.y and
			ctf.team(team).flags[i].z == pos.z
		) then
			table.remove(ctf.team(team).flags,i)
			return
		end
	end
end

function ctf_flag.assert_flag(flag)
	minetest.get_voxel_manip(flag, { x = flag.x + 1, y = flag.y + 1, z = flag.z + 1})
	local nodename = minetest.get_node(flag).name
	if nodename ~= "ctf_flag:flag" then
		ctf.log("flag", flag.team .. " has wrong node at flag position, " .. nodename .. ", correcting...")
		minetest.set_node(flag, { name = "ctf_flag:flag"})
		ctf_flag.update(flag)
	end
end

function ctf_flag.assert_flags()
	for tname, team in pairs(ctf.teams) do
		ctf_flag.assert_flags_team(tname)
	end
end

function ctf_flag.assert_flags_team(tname)
	local team = ctf.team(tname)
	if not tname or not team then
		return false
	end

	if not team.flags then
		team.flags = {}
	end

	for i=1, #team.flags do
		ctf_flag.assert_flag(team.flags[i])
	end
end