This module implements the template {{given name}}.


local m_languages = require("Module:languages")
local m_links = require("Module:links")
local m_utilities = require("Module:utilities")

local export = {}

local rfind = mw.ustring.find

local function ine(x)
	if x == "" then
		return nil
	else
		return x
	end
end

-- Clone parent's args while also assigning nil to empty strings.
local function clone_args(frame)
	local args = {}
	for pname, param in pairs(frame:getParent().args) do
		args[pname] = ine(param)
	end
	return args
end

local en
local function join_names(lang, args, param, paramalt, paramtr)
	local words
	local val = args[param]
	local alt = args[paramalt]
	local tr = paramtr and args[paramtr]
	local i = 2

	while val do
		words = words or {} -- Don't create new table unless it's actually needed
		local sep
		if i == 2 then
			sep = ""
		elseif not args[param .. i] then
			sep = " or "
		else
			sep = ", "
		end
		
		local link
		
		if not lang then
			en = en or m_languages.getByCode("en")
			link = m_links.language_link({lang = en, term = val, alt = alt}, nil, true)
		else
			link = m_links.full_link({lang = lang, term = val, alt = alt, tr = tr}, nil, true)
		end
		
		table.insert(words, sep)
		table.insert(words, link)
		val = args[param .. i]
		alt = args[paramalt .. i]
		tr = paramtr and args[paramtr .. i]
		i = i + 1
	end
	
	return words and table.concat(words, "") or "", i - 2
end

-- The main entry point.
function export.given_name(frame)
	local parent_args = frame:getParent().args
	local compat = parent_args["lang"]
	local offset = compat and 0 or 1

	local params = {
		[compat and "lang" or 1] = { required = true },
		["gender"] = { default = "{{{2}}}" },
		[1 + offset] = { alias_of = "gender" },
		-- second gender
		["or"] = {},
		["from"] = {},
		[2 + offset] = { alias_of = from },
		["diminutive"] = { list = true },
		["diminutivealt"] = { list = true },
		["diminutivetr"] = { list = true },
		["dim"] = { alias_of = "diminutive" },
		["dimalt"] = { alias_of = "diminutivealt" },
		["dimtr"] = { alias_of = "diminutivetr" },
		["eq"] = { list = true },
		["eqalt"] = { list = true },
		["xlit"] = { list = true },
		["xlitalt"] = { list = true },
		-- initial article: A or An
		["A"] = {},
		["sort"] = {},
		["dimtype"] = {},
	}
	
	local args = clone_args(frame)
	local textsegs = {}
	local lang = args[compat and "lang" or 1]
	if not lang and mw.title.getCurrentTitle().nsText == "Template" then
		lang = "und"
	end
	lang = lang and m_languages.getByCode(lang) or m_languages.err(lang, compat and "lang" or 1)
	local gender = args["gender"] or args[1 + offset] or "{{{2}}}"
	local from = args["from"] or args[2 + offset]

	local dimtext, numdims
	if args["diminutive"] then
		dimtext, numdims = join_names(lang, args, "diminutive",
			"diminutivealt", "diminutivetr")
	else
		dimtext, numdims = join_names(lang, args, "dim", "dimalt", "dimtr")
	end
	local xlittext = join_names(nil, args, "xlit", "xlitalt")
	local eqtext = join_names(nil, args, "eq", "eqalt")

	table.insert(textsegs, "<span class='use-with-mention'>")
	local dimtype = args["dimtype"]
	local article = args["A"] or
		dimtype and rfind(dimtype, "^[aeiouAEIOU]") and "An" or "A"

	table.insert(textsegs, article .. " ")
	if numdims > 0 then
		table.insert(textsegs,
			(dimtype and dimtype .. " " or "") ..
			"[[]]diminutive" ..
			(xlittext ~= "" and ", " .. xlittext .. "," or "") ..
			" of the ")
	end
	table.insert(textsegs, gender .. " " .. (
		args["or"] and ("or " .. args["or"] .. " ") or ""))
	table.insert(textsegs, numdims > 1 and "[[|given name|given names]]" or
		"[[|given name]]")
	if numdims > 0 then
		table.insert(textsegs, " " .. dimtext)
	elseif xlittext ~= "" then
		table.insert(textsegs, ", " .. xlittext)
	end
	--if from then
	--	table.insert(textsegs, ", from " .. from)
	--end
	if eqtext ~= "" then
		table.insert(textsegs, ", equivalent to English " .. eqtext)
	end
	table.insert(textsegs, "</span>")

	local categories = {}
	local langname = lang:getCanonicalName() .. " "
	local function validate_gender(gender)
		if gender == "male" or gender == "female" or gender == "unisex" then
			return true
		else
			require("Module:debug").track {
				"given name/unrecognized gender",
				"given name/unrecognized gender/" .. tostring(gender)
			}	
			return false
		end
	end
	local function insert_cats(isdim)
		if isdim == "" then
			-- No category such as "English diminutives of given names"
			table.insert(categories, langname .. isdim .. "given names")
		end
		local function insert_cats_gender(g)
			if not validate_gender(g) then return end
			table.insert(categories, langname .. isdim .. g .. " given names")
			if from then
				table.insert(categories, langname .. isdim .. g .. " given names from " .. from)
			end
		end
		insert_cats_gender(gender)
		if args["or"] then
			insert_cats_gender(args["or"])
		end
	end
	insert_cats("")
	if numdims > 0 then
		insert_cats("diminutives of ")
	end

	if from and not m_languages.getByCanonicalName(from) 
			and not require("Module:etymology languages").getByCanonicalName(from) then
		removed, count = mw.ustring.gsub(from, " languages$", "")
		if count == 0 or not require("Module:families").getByCanonicalName(removed) then
			table.insert(categories,"Kenny's testing category 6")
		end
	end

	return table.concat(textsegs, "") ..
		m_utilities.format_categories(categories, lang, args["sort"])
end

return export

-- For Vim, so we get 4-space tabs
-- vim: set ts=4 sw=4 noet: