--
--- PLAYERS
--

do
   local get_player_by_name = minetest.get_player_by_name
   function PlayerObj(player)
      local type = type(player)

      if type == "string" then
	 return get_player_by_name(player)
      elseif type == "userdata" and player:is_player() then
	 return player
      end
   end

   function PlayerName(player)
      local type = type(player)

      if type == "string" then
	 return player
      elseif type == "userdata" and player:is_player() then
	 return player:get_player_name()
      end
   end
end

--
--- FORMSPECS
--
-- If one of the callbacks for a submitted form returns true, do not process any
-- additional forms that were submitted.
-- This is commented out because it would require a lot of testing to ensure that this
-- doesn't break any non-CTF mods.

--[[
do
   local registered_on_formspec_input = {}
   function ctf_core.register_on_formspec_input(formname, func)
      table.insert(registered_on_formspec_input, {formname = formname, call = func})
   end
   -- Called when a form is submitted (e.g. pressing a button)
   minetest.register_on_player_receive_fields(function(player, formname, fields, ...)
	 -- Loop over registered forms
	 for _, func in ipairs(registered_on_formspec_input) do
	    -- If the submitted form matches this form... 
	    if formname:match(func.formname) then
	       -- Call the current form with the submitted input, and quit if it returns
	       -- "true" (Probably, this would indicate an error)
	       if func.call(PlayerName(player), formname, fields, ...) then
		  return
	       end
	    end
	 end
   end)
end
]]--

--
--- STRINGS
--

do
   local format = string.format
   local gsub   = string.gsub
   local upper  = string.upper
   local lower  = string.lower
   local remove = table.remove
   local sort   = table.sort

   function HumanReadable(input)
      if not input then return input end

      local out
      local t = type(input)

      if t == "string" then
	 out = gsub(input, "(%a)([%w'-]*)", function(a,b) return format("%s%s", upper(a), lower(b)) end)

	 out = gsub(out, "_", " ")
      elseif t == "table" then -- Only accepts lists
	 input = table.copy(input)
	 sort(input)

	 if #input >= 2 then
	    local last = remove(input)

	    for _, i in ipairs(input) do
	       out = format("%s%s, ", out or "", HumanReadable(i))
	    end

	    out = format("%sand %s", out, HumanReadable(last))
	 else
	    out = HumanReadable(input[1]) or "[ERROR]"
	 end
      end

      return out
   end
end

--
--- TABLES
--

---@param funclist table
function RunCallbacks(funclist, ...)
   for _, func in ipairs(funclist) do
      local temp = func(...)

      if temp then
	 return temp
      end
   end
end

--
--- VECTORS/POSITIONS
--

do
   local vsort = vector.sort
   function ctf_core.pos_inside(pos, pos1, pos2)
      pos1, pos2 = vsort(pos1, pos2)

      return pos.x >= pos1.x and pos.x <= pos2.x
	 and pos.y >= pos1.y and pos.y <= pos2.y
	 and pos.z >= pos1.z and pos.z <= pos2.z
   end

   if not math.round then
      local m_floor = math.floor

      function math.round(x)
	 return m_floor(x + 0.5)
      end
   end
end
--
--- MISC
--

function ctf_core.register_chatcommand_alias(name, alias, def)
   minetest.register_chatcommand(name, def)
   if alias then
      minetest.register_chatcommand(alias, {
				       description = "An alias for /" .. name,
				       func = def.func,
      })
   end
end

function ctf_core.file_exists(path)
   local file = io.open(path, "r")
   if file then
      file:close()
      return true
   end

   return false
end

--
---Debug helpers
--

function ctf_core.error(area, msg)
   minetest.log("error", "[CTF | " .. area .. "] " .. msg)
end

function ctf_core.log(area, msg)
   if area and area ~= "" then
      minetest.log("info", "[CTF | " .. area .. "] " .. msg)
   else
      minetest.log("info", "[CTF]" .. msg)
   end
end

function ctf_core.action(area, msg)
   if area and area ~= "" then
      minetest.log("action", "[CaptureTheFlag] (" .. area .. ") " .. msg)
   else
      minetest.log("action", "[CaptureTheFlag] " .. msg)
   end
end

function ctf_core.warning(area, msg)
   minetest.log("warning", "[CTF | " .. area .. "] " .. msg)
end
