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

local lang = require("Module:languages").getByCode("gmw-pro")

local export = {}

local function detect_j(stem)
	local rest, nucleus, coda = mw.ustring.match(stem, "^(.-)([aeiouāēīōū]+)([bdfghjklmnprʀstþw]+)$")

	if mw.ustring.len(coda) > 1 or mw.ustring.find(nucleus, "^[āēīōū]$") or mw.ustring.find(nucleus, "^[aeiou][aeiou]$") then
		return "ij"
	elseif mw.ustring.find(rest, "^[bdfghjklmnprʀstþw]*$") then
		return "j"
	else
		error("Stem consists of multiple syllables or its weight cannot be otherwise be determined")
	end
end

local function geminate(stem)
	stem = mw.ustring.gsub(stem, "w$", "uw")
	stem = mw.ustring.gsub(stem, "([bdghklmnpstþ])$", "%1%1")
	return stem
end


-- Inflection functions

function export.reg(frame)
	local params = {
		[1] = {default = mw.title.getCurrentTitle().nsText == "Template" and "{{{1}}}" or mw.title.getCurrentTitle().subpageText},
	}
	
	local args = require("Module:parameters").process(frame:getParent().args, params)

	local data = {
		forms = {},
		info = nil,
		categories = {},
	}

	local stem, suffix = mw.ustring.match(args[1], "^(.-)([iīu])$")
	local stem_u

	if suffix == "ī" then
		stem = stem .. "ij"
		data.info = "''ja''-stem"
		table.insert(data.categories, lang:getCanonicalName() .. " ja-stem adjectives")
	elseif suffix == "i" then
		stem = geminate(stem) .. "j"
		data.info = "''ja''-stem"
		table.insert(data.categories, lang:getCanonicalName() .. " ja-stem adjectives")
	elseif suffix == "u" then
		stem_u = stem
		stem = stem .. "w"
		data.info = "''wa''-stem"
		table.insert(data.categories, lang:getCanonicalName() .. " wa-stem adjectives")
	else
		stem = args[1]
		data.info = "''a''-stem"
		table.insert(data.categories, lang:getCanonicalName() .. " a-stem adjectives")
	end
	
	stem_u = stem_u or stem

	data.forms["m|nom|s"] = {args[1]}
	data.forms["m|acc|s"] = {stem .. "anā"}
	data.forms["m|gen|s"] = {stem .. "as"}
	data.forms["m|dat|s"] = {stem_u .. "umē"}
	data.forms["m|ins|s"] = {stem_u .. "u"}

	data.forms["f|nom|s"] = {stem_u .. "u"}
	data.forms["f|acc|s"] = {stem .. "ā"}
	data.forms["f|gen|s"] = {stem .. "eʀā"}
	data.forms["f|dat|s"] = {stem .. "eʀē"}
	data.forms["f|ins|s"] = {stem .. "eʀu"}

	data.forms["n|nom|s"] = {args[1]}
	data.forms["n|acc|s"] = {args[1]}
	data.forms["n|gen|s"] = {stem .. "as"}
	data.forms["n|dat|s"] = {stem_u .. "umē"}
	data.forms["n|ins|s"] = {stem_u .. "u"}

	data.forms["m|nom|p"] = {stem .. "ē"}
	data.forms["m|acc|p"] = {stem .. "ā"}
	data.forms["m|gen|p"] = {stem .. "eʀō"}
	data.forms["m|dat|p"] = {stem .. "ēm", stem_u .. "um"}
	data.forms["m|ins|p"] = {stem .. "ēm", stem_u .. "um"}

	data.forms["f|nom|p"] = {stem .. "ō"}
	data.forms["f|acc|p"] = {stem .. "ā"}
	data.forms["f|gen|p"] = {stem .. "eʀō"}
	data.forms["f|dat|p"] = {stem .. "ēm", stem_u .. "um"}
	data.forms["f|ins|p"] = {stem .. "ēm", stem_u .. "um"}

	data.forms["n|nom|p"] = {stem_u .. "u"}
	data.forms["n|acc|p"] = {stem_u .. "u"}
	data.forms["n|gen|p"] = {stem .. "eʀō"}
	data.forms["n|dat|p"] = {stem .. "ēm", stem_u .. "um"}
	data.forms["n|ins|p"] = {stem .. "ēm", stem_u .. "um"}

	return make_table(data)
end

function export.n(frame)
	local params = {
		[1] = {default = mw.title.getCurrentTitle().nsText == "Template" and "{{{1}}}ō" or mw.title.getCurrentTitle().subpageText},
	}

	local args = require("Module:parameters").process(frame:getParent().args, params)

	local data = {
		forms = {},
		info = nil,
		categories = {},
	}
	
	local stem, suffix = mw.ustring.match(args[1], "^(.-)([ō])$")
	local stem_i, stem_u

	if mw.ustring.sub(stem, -1) == "j" then
		stem_i = mw.ustring.sub(stem, 1, -2)
	elseif mw.ustring.sub(stem, -1) == "w" then
		stem_u = mw.ustring.sub(stem, 1, -2)
	end
	
	stem_i = stem_i or stem
	stem_u = stem_u or stem

	if suffix == "ō" then
		data.info = "''n''-stem"
		table.insert(data.categories, lang:getCanonicalName() .. " n-stem adjectives")
	else
		error("n-stems must end in -ō")
	end

	data.forms["m|nom|s"] = {args[1]}
	data.forms["m|acc|s"] = {stem .. "an"}
	data.forms["m|gen|s"] = {stem_i .. "ini", stem .. "an"}
	data.forms["m|dat|s"] = {stem_i .. "ini", stem .. "an"}
	data.forms["m|ins|s"] = {stem_i .. "ini", stem .. "an"}

	data.forms["f|nom|s"] = {stem .. "ā"}
	data.forms["f|acc|s"] = {stem .. "ōn"}
	data.forms["f|gen|s"] = {stem .. "ōn"}
	data.forms["f|dat|s"] = {stem .. "ōn"}
	data.forms["f|ins|s"] = {stem .. "ōn"}

	data.forms["n|nom|s"] = {stem .. "ā"}
	data.forms["n|acc|s"] = {stem .. "ā"}
	data.forms["n|gen|s"] = {stem_i .. "ini", stem .. "an"}
	data.forms["n|dat|s"] = {stem_i .. "ini", stem .. "an"}
	data.forms["n|ins|s"] = {stem_i .. "ini", stem .. "an"}

	data.forms["m|nom|p"] = {stem .. "an"}
	data.forms["m|acc|p"] = {stem .. "an"}
	data.forms["m|gen|p"] = {stem .. "anō"}
	data.forms["m|dat|p"] = {stem_u .. "um"}
	data.forms["m|ins|p"] = {stem_u .. "um"}

	data.forms["f|nom|p"] = {stem .. "ōn"}
	data.forms["f|acc|p"] = {stem .. "ōn"}
	data.forms["f|gen|p"] = {stem .. "ōnō"}
	data.forms["f|dat|p"] = {stem .. "ōm", stem_u .. "um"}
	data.forms["f|ins|p"] = {stem .. "ōm", stem_u .. "um"}

	data.forms["n|nom|p"] = {stem .. "ōn"}
	data.forms["n|acc|p"] = {stem .. "ōn"}
	data.forms["n|gen|p"] = {stem .. "anō"}
	data.forms["n|dat|p"] = {stem_u .. "um"}
	data.forms["n|ins|p"] = {stem_u .. "um"}

	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 forms = data.forms[param]
		
		if not forms then
			return "—"
		end
		
		local ret = {}
		
		for key, subform in ipairs(forms) do
			-- i-umlaut
			if mw.ustring.find(subform, "[iīįǐj]") then
			    subform = mw.ustring.gsub(subform, "([bdfghjklmnprʀstþwBDFGHJKLMNPRƦSTÞW])e(u?)([bdfghjklmnprʀstþw]+)([iīįj])", "%1i%2%3%4")
			    subform = mw.ustring.gsub(subform, "([bdfghjklmnprʀstþwBDFGHJKLMNPRƦSTÞW])o([bdfghjklmnprʀstþw]+)([iīįj])", "%1u%2%3")
			end
			
			-- *u[+stress] > *o /{C,#}_C[-nasal]V[+back]
			if mw.ustring.find(subform, "u") then
			    subform = mw.ustring.gsub(subform, "^([bdfghjklmnprʀstþwBDFGHJKLMNPRƦSTÞW]+)u([bdfghklprʀstþw]+)([aoāōą])", "%1o%2%3")
			end
			
			-- Mahlow's Law (*ōu > *ō / _C{#,V})
			if mw.ustring.find(subform, "ō[uw]") then
			    subform = mw.ustring.gsub(subform, "(ō)[uw]", "%1")
			end
			
			if mw.ustring.find(subform, "ū[uw]") then
			    subform = mw.ustring.gsub(subform, "(ū)[uw]", "%1")
			end
			
			-- P > PP /_LV (Ringe 2014:54)
			if mw.ustring.find(subform, "[ptkh][lr]") then
			    subform = mw.ustring.gsub(subform, "([aeiouāēīōūAEIOUĀĒĪŌŪ])([ptkh])([lr][aeiouāēīōūąįų])", "%1%2%2%3")
			end
			
			table.insert(ret, require("Module:links").full_link({lang = lang, alt = "*" .. subform}))
		end
		
		return table.concat(ret, ", ")
	end
	
	local wikicode = {}
	table.insert(wikicode, [=[
{| class="inflection-table vsSwitcher" data-toggle-category="inflection" style="border: solid 1px #CCCCCC;"
|- style="background: #CCCCCC; text-align: left;"
! class="vsToggleElement" colspan="4" | {{{info}}}
|- class="vsShow"
! style="width: 9em;" | Singular
! style="width: 15em; background: #DDDDDD;" colspan="3" | Masculine
|- class="vsShow"
! style="background: #EEEEEE" | Nominative
| colspan="3" | {{{m|nom|s}}}
|- class="vsShow"
! style="background: #EEEEEE" | Genitive
| colspan="3" | {{{m|gen|s}}}
|- class="vsHide"
! style="width: 9em;" | Singular
! style="width: 15em; background: #DDDDDD;" | Masculine
! style="width: 15em; background: #DDDDDD;" | Feminine
! style="width: 15em; background: #DDDDDD;" class="vsHide" | Neuter
|- class="vsHide"
! style="background: #EEEEEE" | Nominative
| {{{m|nom|s}}}
| {{{f|nom|s}}}
| {{{n|nom|s}}}
|- class="vsHide"
! style="background: #EEEEEE" | Accusative
| {{{m|acc|s}}}
| {{{f|acc|s}}}
| {{{n|acc|s}}}
|- class="vsHide"
! style="background: #EEEEEE" | Genitive
| {{{m|gen|s}}}
| {{{f|gen|s}}}
| {{{n|gen|s}}}
|- class="vsHide"
! style="background: #EEEEEE" | Dative
| {{{m|dat|s}}}
| {{{f|dat|s}}}
| {{{n|dat|s}}}
|- class="vsHide"
! style="background: #EEEEEE" | Instrumental
| {{{m|ins|s}}}
| {{{f|ins|s}}}
| {{{n|ins|s}}}
|- class="vsHide"
! Plural
! style="background: #DDDDDD;" | Masculine
! style="background: #DDDDDD;" | Feminine
! style="background: #DDDDDD;" | Neuter
|- class="vsHide"
! style="background: #EEEEEE" | Nominative
| {{{m|nom|p}}}
| {{{f|nom|p}}}
| {{{n|nom|p}}}
|- class="vsHide"
! style="background: #EEEEEE" | Accusative
| {{{m|acc|p}}}
| {{{f|acc|p}}}
| {{{n|acc|p}}}
|- class="vsHide"
! style="background: #EEEEEE" | Genitive
| {{{m|gen|p}}}
| {{{f|gen|p}}}
| {{{n|gen|p}}}
|- class="vsHide"
! style="background: #EEEEEE" | Dative
| {{{m|dat|p}}}
| {{{f|dat|p}}}
| {{{n|dat|p}}}
|- class="vsHide"
! style="background: #EEEEEE" | Instrumental
| {{{m|ins|p}}}
| {{{f|ins|p}}}
| {{{n|ins|p}}}
|}]=])

	return mw.ustring.gsub(table.concat(wikicode), "{{{([#!]?[a-z0-9|]+)}}}", repl) .. require("Module:utilities").format_categories(data.categories, lang)
end

return export