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

local m_links = require("Module:links")

local lang = require("Module:languages").getByCode("dum")

local export = {}


local function append(l, key, val)
	if not l[key] then
		l[key] = {}
	end
	
	table.insert(l[key], val)
end


local function checked(stem)
	local rest, vowel, cons = mw.ustring.match(stem, "^(.-)([aeiouâêîôûāēōë]+)([^aeiouâêîôûāēōë]+)$")
	
	if not rest then
		return stem
	end
	
	if mw.ustring.len(cons) == 1 and mw.ustring.len(vowel) == 1 then
		if mw.ustring.find(vowel, "[âêāē]") then
			vowel = vowel .. "e"
		elseif mw.ustring.find(vowel, "[iî]") then
			vowel = vowel .. "j"
		elseif mw.ustring.find(vowel, "[ôō]") then
			vowel = vowel .. "o"
		elseif mw.ustring.find(vowel, "[uû]") then
			vowel = vowel .. "u"
		end
	end
	
	if cons == "w" then
		if mw.ustring.find(vowel, "[uû]$") then
			cons = ""
		else
			cons = "u"
		end
	end
	
	cons = mw.ustring.gsub(cons, "(.)%1", "%1")
	cons = mw.ustring.gsub(cons, "c?k$", "c")
	
	return rest .. vowel .. cons
end


local function free(stem)
	if mw.ustring.find(stem, "u?w$") then
		return (mw.ustring.gsub(stem, "u?w$", "u"))
	else
		return checked(stem)
	end
end


local function devoiced(stem)
	local rest, cons = mw.ustring.match(stem, "^(.-)([^aeiouâêîôûāēōë]+)$")
	
	if not rest then
		return stem
	end
	
	cons = mw.ustring.gsub(cons, "(.)%1", "%1")
	cons = mw.ustring.gsub(cons, "ng$", "nc")
	cons = mw.ustring.gsub(cons, "[bdgv]", {["b"] = "p", ["d"] = "t", ["g"] = "ch", ["v"] = "f"})
	
	return rest .. cons
end


local function shortened(stem)
	local rest, vowel, cons = mw.ustring.match(stem, "^(.-)([aeiouâêîôûāēōë]+)([^aeiouâêîôûāēōë]+)$")
	
	if not rest then
		return stem
	end
	
	if mw.ustring.len(cons) == 1 then
		if mw.ustring.find(vowel, "^[aā]e?$") then
			vowel = "a"
		elseif mw.ustring.find(vowel, "^[eē]e?$") then
			vowel = "e"
		elseif mw.ustring.find(vowel, "^[oō]o?$") then
			vowel = "o"
		end
	end
	
	return rest .. vowel .. cons
end


function export.weak(frame)
	local params = {
		[1] = {required = true, default = "{{{1}}}"},
		--[2] = {required = true, default = "{{{2}}}", list = "past"},
	}
	
	local args = require("Module:parameters").process(frame:getParent().args, params)
	
	local data = {forms = {}, info = "weak", categories = {lang:getCanonicalName() .. " weak verbs"}}
	local stem_devoiced = devoiced(checked(args[1]))
	
	data.forms["inf"]     = {args[1] .. "en"}
	data.forms["inf_gen"] = {args[1] .. "ens"}
	data.forms["inf_dat"] = {args[1] .. "ene"}
	
	data.forms["pres_indc_1s"] = {args[1] .. "e"}
	data.forms["pres_indc_2s"] = {stem_devoiced .. (mw.ustring.find(stem_devoiced, "s$") and "" or "s"), args[1] .. "es"}
	data.forms["pres_indc_3s"] = {stem_devoiced .. (mw.ustring.find(stem_devoiced, "t$") and "" or "t"), args[1] .. "et"}
	data.forms["pres_indc_1p"] = {args[1] .. "en"}
	data.forms["pres_indc_2p"] = {stem_devoiced .. (mw.ustring.find(stem_devoiced, "t$") and "" or "t"), args[1] .. "et"}
	data.forms["pres_indc_3p"] = {args[1] .. "en"}
	
	data.forms["pres_subj_1s"] = {args[1] .. "e"}
	data.forms["pres_subj_2s"] = {stem_devoiced .. (mw.ustring.find(stem_devoiced, "s$") and "" or "s"), args[1] .. "es"}
	data.forms["pres_subj_3s"] = {args[1] .. "e"}
	data.forms["pres_subj_1p"] = {args[1] .. "en"}
	data.forms["pres_subj_2p"] = {stem_devoiced .. (mw.ustring.find(stem_devoiced, "t$") and "" or "t"), args[1] .. "et"}
	data.forms["pres_subj_3p"] = {args[1] .. "en"}
	
	data.forms["impr_s"] = {devoiced(free(args[1])), args[1] .. "e"}
	data.forms["impr_p"] = {stem_devoiced .. (mw.ustring.find(stem_devoiced, "t$") and "" or "t"), args[1] .. "et"}
	
	data.forms["pres_ptcp"] = {args[1] .. "ende"}
	
	--[=[
	for _, past in ipairs(args[2]) do
		append(data.forms, "past_indc_1s", past .. "e")
		append(data.forms, "past_indc_2s", past .. "es")
		append(data.forms, "past_indc_3s", past .. "e")
		append(data.forms, "past_indc_1p", past .. "en")
		append(data.forms, "past_indc_2p", past .. "et")
		append(data.forms, "past_indc_3p", past .. "en")
		
		append(data.forms, "past_subj_1s", past .. "e")
		append(data.forms, "past_subj_2s", past .. "es")
		append(data.forms, "past_subj_3s", past .. "e")
		append(data.forms, "past_subj_1p", past .. "en")
		append(data.forms, "past_subj_2p", past .. "et")
		append(data.forms, "past_subj_3p", past .. "en")
		
		append(data.forms, "past_ptcp", "ge" .. devoiced(past))
	end
	]=]
	
	return make_table(data)
end


function export.strong(frame)
	local params = {
		[1] = {required = true, default = "{{{1}}}"},
		[2] = {required = true, default = "{{{2}}}"},
		[3] = {required = true, default = "{{{3}}}"},
		[4] = {required = true, default = "{{{4}}}"},
		
		["class"] = {},
	}
	
	local args = require("Module:parameters").process(frame:getParent().args, params)
	
	local data = {forms = {}, info = "strong" .. (args["class"] and " class " .. args["class"] or ""), categories = {lang:getCanonicalName() .. (args["class"] and " class " .. args["class"] or "") .. " strong verbs"}}
	local pres_devoiced    = devoiced(checked(args[1]))
	local pres_free        = devoiced(free(args[1]))
	local impr_shortened   = devoiced(free(shortened(args[1])))
	local past_sg_devoiced = devoiced(free(args[2]))
	local past_pl_devoiced = devoiced(checked(args[3]))
	
	data.forms["inf"]     = {args[1] .. "en"}
	data.forms["inf_gen"] = {args[1] .. "ens"}
	data.forms["inf_dat"] = {args[1] .. "ene"}
	
	data.forms["pres_indc_1s"] = {args[1] .. "e"}
	data.forms["pres_indc_2s"] = {pres_devoiced .. (mw.ustring.find(pres_devoiced, "s$") and "" or "s"), args[1] .. "es"}
	data.forms["pres_indc_3s"] = {pres_devoiced .. (mw.ustring.find(pres_devoiced, "t$") and "" or "t"), args[1] .. "et"}
	data.forms["pres_indc_1p"] = {args[1] .. "en"}
	data.forms["pres_indc_2p"] = {pres_devoiced .. (mw.ustring.find(pres_devoiced, "t$") and "" or "t"), args[1] .. "et"}
	data.forms["pres_indc_3p"] = {args[1] .. "en"}
	
	data.forms["pres_subj_1s"] = {args[1] .. "e"}
	data.forms["pres_subj_2s"] = {pres_devoiced .. (mw.ustring.find(pres_devoiced, "s$") and "" or "s"), args[1] .. "es"}
	data.forms["pres_subj_3s"] = {args[1] .. "e"}
	data.forms["pres_subj_1p"] = {args[1] .. "en"}
	data.forms["pres_subj_2p"] = {pres_devoiced .. (mw.ustring.find(pres_devoiced, "t$") and "" or "t"), args[1] .. "et"}
	data.forms["pres_subj_3p"] = {args[1] .. "en"}
	
	data.forms["impr_s"] = {pres_free, args[1] .. "e"} if impr_shortened ~= pres_free then table.insert(data.forms["impr_s"], 1, impr_shortened) end
	data.forms["impr_p"] = {pres_devoiced .. (mw.ustring.find(pres_devoiced, "t$") and "" or "t"), args[1] .. "et"}
	
	data.forms["pres_ptcp"] = {args[1] .. "ende"}
	
	data.forms["past_indc_1s"] = {past_sg_devoiced}
	data.forms["past_indc_2s"] = {past_pl_devoiced .. (mw.ustring.find(past_pl_devoiced, "s$") and "" or "s"), args[3] .. "es"}
	data.forms["past_indc_3s"] = {past_sg_devoiced}
	data.forms["past_indc_1p"] = {args[3] .. "en"}
	data.forms["past_indc_2p"] = {past_pl_devoiced .. (mw.ustring.find(past_pl_devoiced, "t$") and "" or "t"), args[3] .. "et"}
	data.forms["past_indc_3p"] = {args[3] .. "en"}
	
	data.forms["past_subj_1s"] = {args[3] .. "e"}
	data.forms["past_subj_2s"] = {args[3] .. "es"}
	data.forms["past_subj_3s"] = {args[3] .. "e"}
	data.forms["past_subj_1p"] = {args[3] .. "en"}
	data.forms["past_subj_2p"] = {args[3] .. "et"}
	data.forms["past_subj_3p"] = {args[3] .. "en"}
	
	data.forms["past_ptcp"] = {args[4]}
	
	return make_table(data)
end


-- Make the table
function make_table(data)
	local function repl(param)
		if param == "info" then
			return mw.getContentLanguage():ucfirst(data.info or "")
		end
		
		local form = data.forms[param]
		
		if not form or #form == 0 then
			return "—"
		end
		
		local ret = {}
		
		for key, subform in ipairs(form) do
			table.insert(ret, m_links.full_link({lang = lang, alt = subform}))
		end
		
		return table.concat(ret, ", ")
	end
	
	local names = {
		["s"] = "singular",
		["1s"] = "1st singular",
		["2s"] = "2nd singular",
		["3s"] = "3rd singular",
		["p"] = "plural",
		["1p"] = "1st plural",
		["2p"] = "2nd plural",
		["3p"] = "3rd plural",
		
		["pres"] = "present",
		["past"] = "past",
		
		["indc"] = "indicative",
		["subj"] = "subjunctive",
		["impr"] = "imperative",
		
		["inf"] = "infinitive",
		["inf_gen"] = "in genitive",
		["inf_dat"] = "in dative",
		
		["ptcp"] = "participle",
		
		["past_indc_3s"] = "3rd sg. past",
		["past_indc_3p"] = "3rd pl. past",
		["past_ptcp"] = "past participle",
	}
	
	local person_numbers = {"1s", "2s", "3s", "1p", "2p", "3p"}
	local tenses = {"pres", "past"}
	local moods = {"indc", "subj", "impr", "ptcp"}
	local infs = {"inf", "inf_gen", "inf_dat"}
	
	local wikicode = {}
	
	table.insert(wikicode, "{| class=\"inflection-table vsSwitcher\" data-toggle-category=\"inflection\" style=\"border: 1px solid #CCCCFF;\" cellspacing=\"1\" cellpadding=\"3\"")
	table.insert(wikicode, "|- style=\"background: #CCCCFF;\"")
	table.insert(wikicode, "! class=\"vsToggleElement\" style=\"text-align: left;\" colspan=\"" .. tostring(#tenses + 1) .. "\" | {{{info}}}")
	
	for _, form in ipairs({"inf", "past_indc_3s", "past_indc_3p", "past_ptcp"}) do
		table.insert(wikicode, "|- class=\"vsShow\" style=\"background: #F2F2FF;\"")
		table.insert(wikicode, "! style=\"background: #CCCCFF; min-width: 9em;\" | " .. mw.getContentLanguage():ucfirst(names[form]))
		table.insert(wikicode, "| style=\"min-width: 12em;\" | {{{" .. form .. "}}}")
	end
	
	for _, inf in ipairs(infs) do
		table.insert(wikicode, "|- class=\"vsHide\" style=\"background: #F2F2FF;\"")
		table.insert(wikicode, "! style=\"background: #CCCCFF;\" | " .. mw.getContentLanguage():ucfirst(names[inf]))
		table.insert(wikicode, "| colspan=\"" .. tostring(#tenses) .. "\" | {{{" .. inf .. "}}}")
	end
	
	for _, mood in ipairs(moods) do
		table.insert(wikicode, "|- class=\"vsHide\" style=\"background: #CCCCFF;\"")
		table.insert(wikicode, "! style=\"background: #E6E6FF; min-width: 9em;\" |" .. (mood == "ptcp" and "" or " " .. mw.getContentLanguage():ucfirst(names[mood])))
		
		if mood == "impr" then
			table.insert(wikicode, "! style=\"background: #CCCCFF; min-width: 12em;\" | " .. mw.getContentLanguage():ucfirst(names["pres"]))
			table.insert(wikicode, "! style=\"background: #CCCCFF; min-width: 12em;\" colspan=\"" .. tostring(#tenses - 1) .. "\" |")
		else
			for _, tense in ipairs(tenses) do
				table.insert(wikicode, "! style=\"background: #CCCCFF; min-width: 12em;\" | " .. mw.getContentLanguage():ucfirst(names[tense]))
			end
		end
		
		for _, pn in ipairs(mood == "impr" and {"s", "p"} or mood == "ptcp" and {"ptcp"} or person_numbers) do
			table.insert(wikicode, "|- class=\"vsHide\" style=\"background: #F2F2FF;\"")
			table.insert(wikicode, "! style=\"background: #CCCCFF;\" | " .. mw.getContentLanguage():ucfirst(names[pn]))
			
			if mood == "impr" then
				table.insert(wikicode, "| {{{" .. mood .. "_" .. pn .. "}}}")
				table.insert(wikicode, "| colspan=\"" .. tostring(#tenses - 1) .. "\" |")
			else
				for _, tense in ipairs(tenses) do
					table.insert(wikicode, "| {{{" .. tense .. "_" .. mood .. (mood == "ptcp" and "" or "_" .. pn) .. "}}}")
				end
			end
		end
	end
	
	table.insert(wikicode, "|}")
	
	wikicode = table.concat(wikicode, "\n")
	
	return (mw.ustring.gsub(wikicode, "{{{([a-z0-9_]+)}}}", repl)) .. require("Module:utilities").format_categories(data.categories, lang)
end

return export