This module needs documentation.
Please document this module by describing its purpose and usage on the documentation page.

local aux = {}
local forms = {}
local export = {}
local theme_vowels = {}

local vl_translit = require("Module:VL-translit")

local fallback_conj = {
	["4th-esco"] = "4th",
	["contrāfac"] = "3rd",
}

local forms_to_use = {
	["It-W"] = {"top", "nom_inf", "nom_pres_part", "nom_gerund", "nom_past_part", "ind_header", "ind_pres", "ind_imperf", "ind_perf", "ind_pluperf",
				"ind_fut_perf", "ind_fut", "ind_comp_header", "ind_comp_perf", "ind_comp_pluperf", "ind_comp_fut_perf", "cond_header", "cond",
				"sub_header", "sub_pres", "sub_imperf", "sub_pluperf", "imp_header", "imp", "bottom", "categories"},
	["E"] = {"top", "nom_inf", "nom_pres_part", "nom_gerund", "nom_past_part", "ind_header", "ind_pres", "ind_imperf", "ind_perf", "ind_fut_perf",
			 "ind_comp_header", "ind_comp_perf", "ind_comp_pluperf", "ind_comp_fut_perf", "ind_comp_fut",
			 "sub_header", "sub_pres", "sub_pluperf", "bottom", "categories"},
	["S"] = {"top", "nom_inf", "nom_pres_part", "nom_gerund", "nom_past_part", "ind_header", "ind_pres", "ind_imperf", "ind_perf",
			 "ind_comp_header", "ind_comp_perf", "ind_comp_pluperf", "ind_comp_fut_perf", "ind_comp_fut",
			 "sub_header", "sub_pres", "sub_imperf", "bottom", "categories"}
}

local simple_colspan = {["It-W"] = "6", ["E"] = "4", ["S"] = "3"}
local comp_colspan = {["It-W"] = "3", ["E"] = "4", ["S"] = "4"}
local label_colors = {["ind"] = "#c0cfe4", ["con"] = "#c0d8e4", ["sub"] = "#c0e4c0", ["imp"] = "#e4d4c0"}
local long_family_names = {["It-W"] = "Italo-Western Romance", ["E"] = "Eastern Romance", ["S"] = "Sardinian"}

local refl_prons = {"me", "te", "se", "nos", "vos", "se"}
local refl_add_to_end = {["nom_inf"] = true, ["nom_pres_part"] = true, ["imp"] = true}

local function show_forms(words, family, form, person, refl)
	if mw.ustring.find(words, "—") then return "—" end
	local result = vl_translit.convert_words(words, family)
	if refl and form ~= "nom_past_part" then
		if refl_add_to_end[form] then
			result = result .. " " .. refl_prons[person]
		else
			result = "*" .. refl_prons[person] .. " " .. mw.ustring.sub(result, 2, -1)
		end
	end
	return result
end

local function get_forms(form, conj)
	return (form[conj] == nil) and form[fallback_conj[conj]] or form[conj]
end

function forms.top()
	return [=[<div class="NavFrame">
	<div class="NavHead">&nbsp; &nbsp; {{{family}}} conjugation of ''*{{{inf}}}''</div>
	<div class="NavContent">
	{| style="background:#F0F0F0;border-collapse:separate;border-spacing:2px;width:100%" class="inflection-table"]=] .. "\n|-\n"
end

function forms.ind_header(args, conj, family)
	return [=[
	! colspan="2" rowspan="2" style="background:#c0cfe4" | indicative
	! colspan="3" style="background:#c0cfe4" | singular
	! colspan="3" style="background:#c0cfe4" | plural
	|-
	! style="background:#c0cfe4" | first
	! style="background:#c0cfe4" | second
	! style="background:#c0cfe4" | third
	! style="background:#c0cfe4" | first
	! style="background:#c0cfe4" | second
	! style="background:#c0cfe4" | third
	|-
	! rowspan="]=] .. simple_colspan[family] .. [=[" style="background:#c0cfe4" | simple tenses]=] .. "\n"
end

function forms.ind_comp_header(args, conj, family)
	return [=[
	! rowspan="]=] .. comp_colspan[family] .. [=[" style="background:#c0cfe4" | compound tenses]=] .. "\n"
end

function forms.cond_header()
	return [=[
	! colspan="2" rowspan="2" style="background:#c0d8e4" | conditional
	! colspan="3" style="background:#c0d8e4" | singular
	! colspan="3" style="background:#c0d8e4" | plural
	|-
	! style="background:#c0d8e4" | first
	! style="background:#c0d8e4" | second
	! style="background:#c0d8e4" | third
	! style="background:#c0d8e4" | first
	! style="background:#c0d8e4" | second
	! style="background:#c0d8e4" | third]=] .. "\n|-\n"
end

function forms.sub_header()
	return [=[
	! colspan="2" rowspan="2" style="background:#c0e4c0" | subjunctive
	! colspan="3" style="background:#c0e4c0" | singular
	! colspan="3" style="background:#c0e4c0" | plural
	|-
	! style="background:#c0e4c0" | first
	! style="background:#c0e4c0" | second
	! style="background:#c0e4c0" | third
	! style="background:#c0e4c0" | first
	! style="background:#c0e4c0" | second
	! style="background:#c0e4c0" | third]=] .. "\n|-\n"
end

function forms.imp_header()
	return [=[
	! colspan="2" rowspan="2" style="background:#e4d4c0" | imperative
	! colspan="3" style="background:#e4d4c0" | singular
	! colspan="3" style="background:#e4d4c0" | plural
	|-
	! style="background:#e4d4c0" | &mdash;
	! style="background:#e4d4c0" | second
	! style="background:#e4d4c0" | &mdash;
	! style="background:#e4d4c0" | &mdash;
	! style="background:#e4d4c0" | second
	! style="background:#e4d4c0" | &mdash;]=] .. "\n|-\n"
end

function forms.bottom()
	return "|}</div></div>"
end

local function loop_over(self, args, conj, family)
	local names = tostring(self)
	local ret = {'! style="background:' .. label_colors[mw.ustring.sub(names[2], 1, 3)] .. '" colspan=' ..
				(mw.ustring.find(names[2], "ind") and "1" or "2") .. '| ' .. names[1]}
	local conj_endings = get_forms(self, conj)
	for i, v in ipairs(conj_endings) do
		table.insert(ret, "\n| " .. show_forms(args[1] .. conj_endings[i], family, names[2], i, args["reflexive"]))
	end
	return table.concat(ret) .. "\n|-\n"
end

local function loop_over_perf(self, args, conj, family)
	local names = tostring(self)
	local ret = {'! style="background:' .. label_colors[mw.ustring.sub(names[2], 1, 3)] .. '" colspan=' ..
				(mw.ustring.find(names[2], "ind") and "1" or "2") .. '| ' .. names[1]}
	perf_stem = args[2] or args[1]
	local conj_endings = get_forms(self, conj)
	for i, v in ipairs(conj_endings) do
		table.insert(ret, "\n| " .. show_forms(perf_stem .. conj_endings[i], family, names[2], i, args["reflexive"]))
	end
	return table.concat(ret) .. "\n|-\n"
end

aux.ind_comp_perf = {
	["essere"] = {"sum ", "es ", "est ", "sumus ", "estes ", "sunt "},
	["habēre"] = {"habeō ", "habēs ", "habet ", "habēmus ", "habētis ", "habent "}
}

aux.ind_comp_pluperf = {
	["essere"] = {"eram ", "erās ", "erat ", "erāmus ", "erātis ", "erant "},
	["habēre"] = {"habēbam ", "habēbās ", "habēbat ", "habēbāmu ", "habēbātis ", "habēbant "}
}

aux.ind_comp_fut_perf = {
	["essere"] = {"essere habeō ", "essere habēs ", "essere habet ", "essere habēmus ", "essere habētis ", "essere habent "},
	["habēre"] = {"habēre habeō ", "habēre habēs ", "habēre habet ", "habēre habēmus ", "habēre habētis ", "habēre habent "}
}

aux.ind_comp_fut = {
	["E"] = {"voleō ", "velis ", "volet ", "volēmus ", "volētis ", "volēnt "},
	["S"] = {"habeō ad ", "habēs ad ", "habet ad ", "habēmus ad ", "habētis ad ", "habent ad "}
}

forms.nom_inf = {
	["1st"] = {"āre"},
	["2nd"] = {"ēre"},
	["3rd"] = {"ere"},
	["4th"] = {"īre"},
}
setmetatable(forms.nom_inf, {__call = function(self, args, conj, family)
	return '! colspan="3" style="background:#e2e4c0" | infinitive\n| colspan="1" | ' .. show_forms(args[1] .. get_forms(self, conj)[1], family, "nom_inf", 3, args["reflexive"]) .. "\n|-\n"
end,
__tostring = function() return "infinitive" end
})

forms.nom_pres_part = {
	["1st"] = {"antis"},
	["2nd"] = {"entis"},
	["3rd"] = {"entis"},
	["4th"] = {"entis"},
}
setmetatable(forms.nom_pres_part, {__call = function(self, args, conj, family)
	return '! colspan="4" style="background:#e2e4c0" | present participle\n| ' .. show_forms(args[1] .. get_forms(self, conj)[1], family, "nom_pres_part", 3, args["reflexive"]) .. "\n|-\n"
end,
__tostring = function() return "present participle" end
})

forms.nom_gerund = {
	["1st"] = {"andō"},
	["2nd"] = {"endō"},
	["3rd"] = {"endō"},
	["4th"] = {"endō"},
}
setmetatable(forms.nom_gerund, {__call = function(self, args, conj, family)
	return '! colspan="4" style="background:#e2e4c0" | gerund\n| ' .. show_forms(args[1] .. get_forms(self, conj)[1], family, "nom_gerund", 3, args["reflexive"]) .. "\n|-\n"
end,
__tostring = function() return "gerund" end
})

forms.nom_past_part = {
	["1st"] = {"ātum"},
	["2nd"] = {"ūtum"},
	["3rd"] = {"ūtum"},
	["4th"] = {"ītum"},
}
setmetatable(forms.nom_past_part, {__call = function(self, args, conj, family)
	return '! colspan="4" style="background:#e2e4c0" | past participle\n| ' ..
				show_forms(args["pastpart"] or (args[1] .. get_forms(self, conj)[1]), family, "nom_past_part", 3, args["reflexive"]) .. "\n|-\n"
end,
__tostring = function() return "past participle" end
})

forms.ind_pres = {
	["1st"] = {"ō", "ās", "at", "āmus", "ātis", "ant"},
	["2nd"] = {"eō", "ēs", "et", "ēmus", "ētis", "ēnt"},
	["3rd"] = {"ō", "is", "it", "imus", "itis", "unt"},
	["4th"] = {"iō", "īs", "īt", "īmus", "ītis", "unt"},
	["4th-esco"] = {"ēscō", "ēscis", "ēscit", "īmus", "ītis", "ēscunt"},
	["contrāfac"] = {"iō", "is", "it", "imus", "itis", "unt"}
}
setmetatable(forms.ind_pres, {__call = loop_over, __tostring = function() return {"present", "ind_pres"} end})

forms.ind_imperf = {
	["1st"] = {"ābam", "ābās", "ābat", "ābāmus", "ābātis", "ābānt"},
	["2nd"] = {"ēbam", "ēbās", "ēbat", "ēbāmus", "ēbātis", "ēbānt"},
	["3rd"] = {"ēbam", "ēbās", "ēbat", "ēbāmus", "ēbātis", "ēbānt"},
	["4th"] = {"ībam", "ībās", "ībat", "ībāmus", "ībātis", "ībānt"},
}
setmetatable(forms.ind_imperf, {__call = loop_over, __tostring = function() return {"imperfect", "ind_imperf"} end})

forms.ind_perf = {
	["1st"] = {"āī", "āstī", "'aut", "āmmus", "āstis", "ārunt"},
	["2nd"] = {"ī", "istī", "it", "immus", "istis", "ērunt"},
	["3rd"] = {"ī", "istī", "it", "immus", "istis", "ērunt"},
	["4th"] = {"īī", "īstī", "'īt", "īmmus", "īstis", "īrunt"}
}
setmetatable(forms.ind_perf, {__call = loop_over_perf, __tostring = function() return {"perfect", "ind_perf"} end})

forms.ind_pluperf = {
	["1st"] = {"āram", "ārās", "'ārat", "ārāmus", "ārātis", "ārant"},
	["2nd"] = {"eram", "erās", "'erat", "erāmus", "erātis", "erant"},
	["3rd"] = {"eram", "erās", "'erat", "erāmus", "erātis", "erant"},
	["4th"] = {"īram", "īrās", "'īrat", "īrāmus", "īrātis", "īrant"},
}
setmetatable(forms.ind_pluperf, {__call = loop_over_perf, __tostring = function() return {"pluperfect", "ind_pluperf"} end})

forms.ind_fut_perf = {
	["1st"] = {"ārim", "āris", "ārit", "ārimus", "āritis", "ārint"},
	["2nd"] = {"erim", "eris", "'erit", "erimus", "eritis", "erint"},
	["3rd"] = {"erim", "eris", "'erit", "erimus", "eritis", "erint"},
	["4th"] = {"īrim", "īris", "īrit", "īrimus", "īritis", "īrint"}
}
setmetatable(forms.ind_fut_perf, {__call = loop_over_perf, __tostring = function() return {"future perfect", "ind_fut_perf"} end})

forms.ind_fut = {
	["1st"] = {"āre habeō", "āre habēs", "āre habet", "āre habēmus", "āre habētis", "āre habent"},
	["2nd"] = {"ēre habeō", "ēre habēs", "ēre habet", "ēre habēmus", "ēre habētis", "ēre habent"},
	["3rd"] = {"ere habeō", "ere habēs", "ere habet", "ere habēmus", "ere habētis", "ere habent"},
	["4th"] = {"īre habeō", "īre habēs", "īre habet", "īre habēmus", "īre habētis", "īre habent"}
}
setmetatable(forms.ind_fut, {__call = loop_over, __tostring = function() return {"future", "ind_fut"} end})

forms.cond = {
	["1st"] = {"āre habēbam", "āre habēbās", "āre habēbat", "āre habēbāmus", "āre habēbātis", "āre habēbant"},
	["2nd"] = {"ēre habēbam", "ēre habēbās", "ēre habēbat", "ēre habēbāmus", "ēre habēbātis", "ēre habēbant"},
	["3rd"] = {"ere habēbam", "ere habēbās", "ere habēbat", "ere habēbāmus", "ere habēbātis", "ere habēbant"},
	["4th"] = {"īre habēbam", "īre habēbās", "īre habēbat", "īre habēbāmus", "īre habēbātis", "īre habēbant"}
}
setmetatable(forms.cond, {__call = loop_over, __tostring = function() return {"present", "cond"} end})

function forms.ind_comp_perf(args, conj, family)
	local aux_to_use = args["aux"] or "habēre"
	local ret = {'! style="background:#c0cfe4" colspan="1"| perfect'}
	for i, v in ipairs(aux.ind_comp_perf[aux_to_use]) do
		table.insert(ret, "\n| " .. show_forms(v .. " " .. (args.pastpart or (args[1] .. get_forms(forms.nom_past_part, conj)[1])), family, "ind_comp_perf", i, args["reflexive"]))
	end
	return table.concat(ret) .. "\n|-\n"
end

function forms.ind_comp_pluperf(args, conj, family)
	local aux_to_use = args["aux"] or "habēre"
	local ret = {'! style="background:#c0cfe4" colspan="1"| pluperfect'}
	for i, v in ipairs(aux.ind_comp_pluperf[aux_to_use]) do
		table.insert(ret, "\n| " .. show_forms(v .. " " .. (args.pastpart or (args[1] .. get_forms(forms.nom_past_part, conj)[1])), family, "ind_comp_pluperf", i, args["reflexive"]))
	end
	return table.concat(ret) .. "\n|-\n"
end

function forms.ind_comp_fut_perf(args, conj, family)
	local aux_to_use = args["aux"] or "habēre"
	local ret = {'! style="background:#c0cfe4" colspan="1"| future perfect'}
	for i, v in ipairs(aux.ind_comp_fut_perf[aux_to_use]) do
		table.insert(ret, "\n| " .. show_forms(v .. " " .. (args.pastpart or (args[1] .. get_forms(forms.nom_past_part, conj)[1])), family, "ind_comp_fut_perf", i, args["reflexive"]))
	end
	return table.concat(ret) .. "\n|-\n"
end

function forms.ind_comp_fut(args, conj, family)
	local inf_vowels = {["1st"] = "ā", ["2nd"] = "ē", ["3rd"] = "e", ["4th"] = "ī", ["4th-esco"] = "ī"}
	local ret = {'! style="background:#c0cfe4" colspan="1"| future\n'}
	for i, v in ipairs(aux.ind_comp_fut[family]) do
		table.insert(ret, "\n| " .. show_forms(v .. args[1] .. get_forms(inf_vowels, conj) .. "re", family, "ind_comp_fut", i, args["reflexive"]))
	end
	return table.concat(ret) .. "\n|-\n"
end

forms.sub_pres = {
	["1st"] = {"em", "ēs", "et", "ēmus", "ētis", "ent"},
	["2nd"] = {"am", "ās", "at", "āmus", "ātis", "ant"},
	["3rd"] = {"am", "ās", "at", "āmus", "ātis", "ant"},
	["4th"] = {"iam", "iās", "iat", "iāmus", "iātis", "iant"},
	["4th-esco"] = {"ēscam", "ēscās", "ēscat", "iāmus", "iātis", "ēscant"},
	["contrāfac"] = {"iam", "iās", "iat", "iāmus", "iātis", "iant"},
}
setmetatable(forms.sub_pres, {__call = loop_over, __tostring = function() return {"present", "sub_pres"} end})

forms.sub_imperf = {
	["1st"] = {"ārem", "ārēs", "āret", "ārēmus", "ārētis", "ārent"},
	["2nd"] = {"ērem", "ērēs", "ēret", "ērēmus", "ērētis", "ērent"},
	["3rd"] = {"erem", "erēs", "eret", "erēmus", "erētis", "erent"},
	["4th"] = {"īrem", "īrēs", "īret", "īrēmus", "īrētis", "īrent"}
}
setmetatable(forms.sub_imperf, {__call = loop_over, __tostring = function() return {"imperfect", "sub_imperf"} end})

forms.sub_pluperf = {
	["1st"] = {"āssem", "āssēs", "āsset", "āssēmus", "āssētis", "āssent"},
	["2nd"] = {"issem", "issēs", "isset", "issēmus", "issētis", "issent"},
	["3rd"] = {"issem", "issēs", "isset", "issēmus", "issētis", "issent"},
	["4th"] = {"īssem", "īssēs", "īsset", "īssēmus", "īssētis", "īssent"}
}
setmetatable(forms.sub_pluperf, {__call = loop_over_perf, __tostring = function() return {"pluperfect", "sub_pluperf"} end})

forms.imp = {
	["1st"] = {"—", "ā", "—", "—", "āte", "—"},
	["2nd"] = {"—", "e", "—", "—", "ete", "—"},
	["3rd"] = {"—", "e", "—", "—", "ite", "—"},
	["4th"] = {"—", "ī", "—", "—", "īte", "—"},
	["4th-esco"] = {"—", "ēsce", "—", "—", "īte", "—"}
}
setmetatable(forms.imp, {__call = loop_over, __tostring = function() return {"present", "imp"} end})

forms.categories = {
	["1st"] = {"first"},
	["2nd"] = {"second"},
	["3rd"] = {"third"},
	["4th"] = {"fourth"},
}
setmetatable(forms.categories, {__call = function(self, args, conj, family)
	return "[[Category:Latin " .. get_forms(self, conj)[1] .. " conjugation verbs]]"
end
})

local function make_table(args, conj, family)
	local tb = {}
	for i, v in ipairs(forms_to_use[family]) do
		table.insert(tb, forms[v](args, conj, family))
	end
	local tb_string = table.concat(tb)
	tb_string = mw.ustring.gsub(tb_string, "{{{family}}}", long_family_names[family])
	tb_string = mw.ustring.gsub(tb_string, "{{{inf}}}", args[1] .. get_forms(forms.ind_pres, conj)[1])
	return tb_string
end

function export.show(frame)
	if  mw.title.getCurrentTitle().nsText == "Template" then return end
	local parent_args = frame:getParent().args
	local conj = frame.args["conj"] or parent_args["conj"] or "1st"
	if not parent_args[1] then
		parent_args[1] = "am"
	end
	local ret = ""
	if parent_args["family"] then
		ret = make_table(parent_args, conj, parent_args["family"])
		if parent_args["family2"] then
			ret = ret .. make_table(parent_args, conj, parent_args["family2"])
		end
	else
		ret = make_table(parent_args, conj, "It-W") .. make_table(parent_args, conj, "E") .. make_table(parent_args, conj, "S")
	end
	return ret
end

return export