This module page is experimental.
The details of its operation have not yet been fully decided upon. Do not deploy widely until the module page is finished.
This module needs documentation.
Please document this module by describing its purpose and usage on the documentation page.

local export = {}

local m_links = require("Module:links")
local lang = require("Module:languages").getByCode("ro")
local m_gen = require("Module:gender and number")

local PAGENAME = PAGENAME or mw.title.getCurrentTitle().text

local data = {}
data.forms = {}

function export.show(frame)
	local args = frame:getParent().args
	data.n = args['n']
	data.g = args[1] or PAGENAME == 'Redboywild/ro-noun' and 'n' or error('Please provide gender as first parameter')
	data.pl = args[2] or data.n == 'pl' and PAGENAME or PAGENAME == 'Redboywild/ro-noun' and 'cuvinte'
	data.word = args['word'] or PAGENAME == 'Redboywild/ro-noun' and 'cuvânt' or 'PAGENAME'
	data.gd = args['gd']
	data.hyphen = args['hyphen']
	
	data.forms = inflect(data.word, data.g, data.pl, data.gd, data.hyphen)
	for key, val in pairs(data.forms) do
		if type(data.forms[key]) == 'string' then
			data.forms[key] = { data.forms[key] }
		end
		for i, form in ipairs(data.forms[key]) do
			data.forms[key][i] = m_links.full_link({term = form, lang = lang}, nil, false)
		end
		data.forms[key] = table.concat(data.forms[key], ', ')
	end
	return make_table(data)
end

function inflect(word, g, pl, gd, hyphen)
	local forms = {}
	local shortcut = false
	if not pl or pl:sub(1, 1) == '-' then
		shortcut = true
	end
	if shortcut then
		pl = export.make_plural(word, g, pl, hyphen)
	end
	hyph = hyphen and '-' or ''
	if g == 'm' then
		forms.na_sg_indef = word
		forms.na_pl_indef = pl
		forms.na_pl_def = pl .. 'i'
		forms.gd_sg_indef = word
		forms.gd_pl_indef = pl
		forms.gd_pl_def = pl .. 'lor'
		forms.v_pl = pl .. 'lor'
		if not hyphen and mw.ustring.find(word, 'u$') then
			forms.na_sg_def = word .. 'l'
			forms.gd_sg_def = word .. 'lui'
			forms.v_sg = word .. 'le'
		elseif not hyphen and mw.ustring.find(word, 'e$') then
			forms.na_sg_def = word .. 'le'
			forms.gd_sg_def = word .. 'lui'
			forms.v_sg = word
		else
			forms.na_sg_def = word .. hyph .. 'ul'
			forms.gd_sg_def = word .. hyph .. 'ului'
			forms.v_sg = word .. hyph .. 'ule'
		end
	elseif g == 'f' then
		if pl:match('uri$') and not word:match('ură$') then
			if gd then
				gd = export.make_plural(word, g, gd, hyphen)
			else
				error('Please provide the genitive/dative form as the gd= parameter')
			end
		else
			gd = pl
		end
		forms.na_sg_indef = word
		forms.na_pl_indef = pl
		forms.na_pl_def = pl .. 'le'
		forms.gd_sg_indef = gd
		forms.gd_pl_indef = pl
		forms.gd_pl_def = pl .. 'lor'
		forms.v_pl = pl .. 'lor'
		if mw.ustring.find(word, 'ă$') then
			forms.na_sg_def = word:gsub('ă$', 'a')
			forms.gd_sg_def = gd .. 'i'
			forms.v_sg = {word:gsub('ă$', 'o'), word}
		elseif mw.ustring.find(word, '[aeiouăâî]ie') then
			forms.na_sg_def = word:gsub('e$', 'a')
			forms.gd_sg_def = gd .. 'i'
			forms.v_sg = {word:gsub('e$', 'o'), word}
		elseif mw.ustring.find(word, 'ie$') then
			forms.na_sg_def = word:gsub('e$', 'a')
			forms.gd_sg_def = word .. 'i'
			forms.v_sg = {word:gsub('e$', 'o'), word}
		elseif mw.ustring.find(word, 'e$') then
			forms.na_sg_def = word .. 'a'
			forms.gd_sg_def = gd .. 'i'
			forms.v_sg = {word .. 'o', word}
		elseif mw.ustring.find(word, 'a$') then
			forms.na_sg_def = word .. 'ua'
			forms.gd_sg_def = gd .. 'i'
			forms.v_sg = word
		end
	elseif g == 'n' then
		forms.na_sg_indef = word
		forms.na_pl_indef = pl
		forms.na_pl_def = pl .. 'le'
		forms.gd_sg_indef = word
		forms.gd_pl_indef = pl
		forms.gd_pl_def = pl .. 'lor'
		forms.v_pl = pl .. 'lor'
		if mw.ustring.find(word, 'u$') then
			forms.na_sg_def = word .. 'l'
			forms.gd_sg_def = word .. 'lui'
			forms.v_sg = word .. 'le'
		elseif mw.ustring.find(word, 'e$') then
			forms.na_sg_def = word .. 'le'
			forms.gd_sg_def = word .. 'lui'
			forms.v_sg = word
		else
			forms.na_sg_def = word .. hyph .. 'ul'
			forms.gd_sg_def = word .. hyph .. 'ului'
			forms.v_sg = word .. hyph .. 'ule'
		end
	end
	return forms
end

function split(word)
	local stem, vow, cons
	if word:match('[aeiouăâî][iu]$') then
		stem, vow, cons = word:match('^(.-)([aeiouăâî]-)([iu])$')
	else
		stem, vow, cons = word:match('^(.-)([aeiouăâî]-)([bcdfghj-np-tv-zșț]-)$')
	end
	return stem, vow, cons
end

function pl_error(g, no_error, sg_end)
	if no_error then
		if sg_end == "?" then
			return nil, "sg"
		else
			return nil, "pl"
		end
	else
		if sg_end == "?" then
			return error("Unrecognized word ending for \"" .. g .. "\" gender")
		elseif sg_end then
			return error("Unrecognized plural ending for \"" .. sg_end .. "\" singular ending and " .. g .. " gender")
		else
			return error("Unrecognized plural ending for " .. g .. " gender")
		end
	end
end

function find_cons(cons, array, len)
	for i = mw.ustring.len(cons) < len and -mw.ustring.len(cons) or -len, -1 do
		if array[mw.ustring.sub(cons, i)] then
			cons = mw.ustring.sub(cons, 1, i-1) .. array[mw.ustring.sub(cons, i)]
			break
		end
	end
	return cons
end

function export.make_plural(word, g, ending, hyphen, no_error)
	local pl = ''
	if ending then
		ending = ending:sub(2)
	end
	local suf1, suf2, pre1, pre2 = mw.ustring.sub(word, -1), mw.ustring.sub(word, -2), mw.ustring.sub(word, 1, -2), mw.ustring.sub(word, 1, -3)
	if g == 'm' then
		if hyphen then
			pl = word .. '-i'
		elseif suf1 == 'i' then
			pl = word
		else
			local stem, vow, cons = split(word:match('^(.-)[eu]?$'))
			cons = find_cons(cons, cons_m, 3)
			pl = stem .. vow .. cons .. 'i'
		end
	elseif g == 'f' then
		if suf1 == 'a' then
			if suf2 == 'ea' then
				pl = mw.ustring.sub(word, 1, -2) .. 'le'
			elseif suf2 == 'ia' then
				pl = mw.ustring.sub(word, 1, -2) .. 'ele'
			else
				pl = word .. 'le'
			end
		else
			if ending and ending ~= 'e' and ending ~= 'i' and ending ~= 'uri' then
				return pl_error(g, no_error)
			end
			if suf2 == 'ie' then
				if not ending then
					error('Please provide plural ending or full plural')
				end
				if ending == 'e' then
					pl = word
				else
					local stem, vow, cons = split(pre2)
					if cons ~= '' then
						if ending == 'i' then
							pl = stem .. vow .. cons .. 'ii'
						elseif ending == 'uri' then
							pl = stem .. vow .. cons .. 'iuri'
						else
							return pl_error(g, no_error)
						end
					else
						if ending == 'i' then
							pl = stem .. (vow_f[vow] or vow) .. 'i'
						elseif ending == 'uri' then
							pl = stem .. (vow_f[vow] or vow) .. 'iuri'
						else
							return pl_error(g, no_error)
						end
					end
				end
			elseif suf1 == 'e' then
				if not ending then
					error('Please provide plural ending or full plural')
				end
				if ending == 'e' then
					pl = word
				else
					local stem, vow, cons = split(pre1)
					if ending == 'i' then
						cons = find_cons(cons, cons_f, 2)
						pl = stem .. (vow_f[vow] or vow) .. cons .. 'i'
					elseif ending == 'uri' then
						pl = stem .. (vow_f[vow] or vow) .. cons .. 'uri'
					else
						return pl_error(g, no_error)
					end
				end
			elseif suf1 == 'ă' then
				if not ending then
					error('Please provide plural ending or full plural')
				end
				local stem, vow, cons = split(pre1)
				if ending == 'e' then
					cons = find_cons(cons, cons_f_e, 2)
					pl = stem .. (vow_f_e[vow] or vow) .. cons .. 'e'
				elseif ending == 'i' then
					cons = find_cons(cons, cons_f, 2)
					pl = stem .. (vow_f[vow] or vow) .. cons .. 'i'
				elseif ending == 'uri' then
					cons = find_cons(cons, cons_f, 2)
					pl = stem .. (vow_f[vow] or vow) .. cons .. 'uri'
				else
					return pl_error(g, no_error)
				end
			else
				return pl_error(g, no_error, "?")
			end
		end
	elseif g == 'n' then
		if not ending then
			error('Please provide plural ending or full plural')
		end
		if hyphen then
			pl = word .. '-' .. ending
		elseif word:match('[cg]h?i$') then
			if ending == 'uri' then
				pl = word .. 'uri'
			elseif ending == "e" then
				local stem, vow, cons = split(pre1)
				pl = stem .. (vow_n[vow] or vow) .. cons .. 'e'
			else
				return pl_error(g, no_error, word:match("[cg]h?i$"))
			end
		elseif suf2 == 'iu' then
			if ending == 'i' then
				pl = mw.ustring.sub(word, 1, -2) .. 'i'
			elseif ending == 'uri' then
				pl = word .. 'ri'
			elseif ending == "e" then
				pl = pre1 .. "e"
			else
				return pl_error(g, no_error)
			end
		elseif suf1 == 'e' then
			if ending == 'e' then
				pl = word
			elseif ending == 'uri' then
				if word:find('[cg]e$') then
					pl = mw.ustring.sub(word, 1, -2) .. 'iuri'
				else
					pl = mw.ustring.sub(word, 1, -2) .. 'uri'
				end
			else
				return pl_error(g, no_error, "-e")
			end
		elseif suf1 == 'u' then
			if ending == 'uri' then
				pl = word .. 'ri'
			elseif ending == 'e' then
				local stem, vow, cons = split(pre1)
				pl = stem .. (vow_n[vow] or vow) .. cons .. 'e'
				if pl:find('[aâî]e') then
					pl = mw.ustring.sub(pl, 1, -2) .. 'ie'
				end
			else
				return pl_error(g, no_error)
			end
		else
			if ending == 'uri' then
				pl = word .. 'uri'
			elseif ending == 'e' then
				local stem, vow, cons = split(word)
				pl = stem .. (vow_n[vow] or vow) .. cons .. 'e'
				if pl:find('[aâî]e$') then
					pl = mw.ustring.sub(pl, 1, -2) .. 'ie'
				end
			else
				return pl_error(g, no_error)
			end
		end
	end
	return pl
end

function export.make_feminine(word)
	word = "tor"
	local iea = false
	if word:find("iea") then
		iea = true
	end
	local f = ""
	if word:find("e$") then
		f = word
	elseif word:find("ui$") then
		f = word .. "e"
	elseif word:find("iu$") then
		f = word:gsub("u$", "e")
	elseif word:find("tor$") then
		f = word:gsub("tor$", "toare")
	elseif word:find("esc$") then
		f = word:gsub("esc$", "ească")
	elseif word:find("os$") then
		f = word:gsub("os$", "oasă")
	elseif word:find("u$") then
		f = word:sub(1, -2) .. "ă"
	else
		f = word .. "ă"
	end
	f:gsub("iea", "ia")
	return f
end

cons_m = {
	str = 'ștr';
	st = 'șt';
	['șt'] = 'șt'; -- this prevents the plural of "pește" from being generated as "peșți"
	d = 'z';
	s = 'ș';
	t = 'ț';
	x = 'cș';
}

cons_f_e = {
	sc = 'șt';
	['șc'] = 'șt';
}

vow_f_e = {
	ea = 'e'
}

cons_f = {
	sc = 'șt';
	['șc'] = 'șt';
	t = 'ț';
	d = 'z';
	x = 'cș'; --probably useless
}

vow_f = {
	ea = 'e';
	oa = 'o';
	a = 'ă';
}

vow_n = {
	o = 'oa'
}

function make_table(data)
	local result = ''
	if data.n == 'sg' then
		result = result .. '<div class="NavFrame" style="width:57.5%">\n'
		result = result .. '<div class="NavHead" style="background:#e2e4c0" align=center>declension of ' .. data.word .. ' (singular only)</div>\n'
		result = result .. '<div class="NavContent">\n'
		result = result .. '{| border="1px solid #000000" style="border-collapse:collapse; width:100%; background:#F0F0F0; text-align:center" class="inflection-table"\n'
		result = result .. '|-\n'
		result = result .. '! style="background:#e2e4c0" |\n'
		result = result .. '! colspan="2" style="background:#e2e4c0" | singular\n'
		result = result .. '|-\n'
		result = result .. '| style="width:26%;background:#e2e4cb" | ' .. m_gen.format_list({data.g}) .. ' gender\n'
		result = result .. '! style="width:37%;background:#e2e4cb" | indefinite articulation\n'
		result = result .. '! style="width:37%;background:#e2e4cb" | definite articulation\n'
		result = result .. '|-\n'
		result = result .. '! style="height:3em;background:#e2e4cb;border" | nominative/accusative\n'
		result = result .. '| (' .. (data.g == 'f' and 'o' or 'un') .. ') ' .. data.forms.na_sg_indef .. '\n'
		result = result .. '| ' .. data.forms.na_sg_def .. '\n'
		result = result .. '|-\n'
		result = result .. '! style="height:3em;background:#e2e4cb" | genitive/dative\n'
		result = result .. '| (' .. (data.g == 'f' and 'unei' or 'unui') .. ') ' .. data.forms.gd_sg_indef .. '\n'
		result = result .. '| ' .. data.forms.gd_sg_def .. '\n'
		result = result .. '|-\n'
		result = result .. '! style="height:3em;background:#e2e4cb" | vocative\n'
		result = result .. '| colspan="2" | ' .. data.forms.v_sg .. '\n'
		result = result .. '|}\n'
		result = result .. '</div></div>'
	elseif data.n == 'pl' then
		result = result .. '<div class="NavFrame" style="width:57.5%">\n'
		result = result .. '<div class="NavHead" style="background:#e2e4c0" align=center>declension of ' .. data.word .. ' (plural only)</div>\n'
		result = result .. '<div class="NavContent">\n'
		result = result .. '{| border="1px solid #000000" style="border-collapse:collapse; width:100%; background:#F0F0F0; text-align:center" class="inflection-table"\n'
		result = result .. '|-\n'
		result = result .. '! style="background:#e2e4c0" |\n'
		result = result .. '! colspan="2" style="background:#e2e4c0" | plural\n'
		result = result .. '|-\n'
		result = result .. '| style="width:26%;background:#e2e4cb" | ' .. m_gen.format_list({data.g}) .. ' gender\n'
		result = result .. '! style="width:37%;background:#e2e4cb" | indefinite articulation\n'
		result = result .. '! style="width:37%;background:#e2e4cb" | definite articulation\n'
		result = result .. '|-\n'
		result = result .. '! style="height:3em;background:#e2e4cb;border" | nominative/accusative\n'
		result = result .. '| (niște) ' .. data.forms.na_pl_indef .. '\n'
		result = result .. '| ' .. data.forms.na_pl_def .. '\n'
		result = result .. '|-\n'
		result = result .. '! style="height:3em;background:#e2e4cb" | genitive/dative\n'
		result = result .. '| (unor) ' .. data.forms.gd_pl_indef .. '\n'
		result = result .. '| ' .. data.forms.gd_pl_def .. '\n'
		result = result .. '|-\n'
		result = result .. '! style="height:3em;background:#e2e4cb" | vocative\n'
		result = result .. '| colspan="2" | ' .. data.forms.v_pl .. '\n'
		result = result .. '|}\n'
		result = result .. '</div></div>'
	else
		result = result .. '<div class="NavFrame">\n'
		result = result .. '<div class="NavHead" style="background:#e2e4c0" align=center>declension of ' .. data.word .. '</div>\n'
		result = result .. '<div class="NavContent">\n'
		result = result .. '{| border="1px solid #000000" style="border-collapse:collapse; width:100%; background:#F0F0F0; text-align:center" class="inflection-table"\n'
		result = result .. '|-\n'
		result = result .. '! style="background:#e2e4c0" |\n'
		result = result .. '! colspan="2" style="background:#e2e4c0" | singular\n'
		result = result .. '! colspan="2" style="background:#e2e4c0" | plural\n'
		result = result .. '|-\n'
		result = result .. '| colspan="1" style="width:15%;background:#e2e4cb" | ' .. m_gen.format_list({data.g}) .. ' gender\n'
		result = result .. '! style="width:21.25%;background:#e2e4cb" | indefinite articulation\n'
		result = result .. '! style="width:21.25%;background:#e2e4cb" | definite articulation\n'
		result = result .. '! style="width:21.25%;background:#e2e4cb" | indefinite articulation\n'
		result = result .. '! style="width:21.25%;background:#e2e4cb" | definite articulation\n'
		result = result .. '|-\n'
		result = result .. '! style="height:3em;background:#e2e4cb;border" | nominative/accusative\n'
		result = result .. '| (' .. (data.g == 'f' and 'o' or 'un') .. ') ' .. data.forms.na_sg_indef .. '\n'
		result = result .. '| ' .. data.forms.na_sg_def .. '\n'
		result = result .. '| (niște) ' .. data.forms.na_pl_indef .. '\n'
		result = result .. '| ' .. data.forms.na_pl_def .. '\n'
		result = result .. '|-\n'
		result = result .. '! style="height:3em;background:#e2e4cb" | genitive/dative\n'
		result = result .. '| (' .. (data.g == 'f' and 'unei' or 'unui') .. ') ' .. data.forms.gd_sg_indef .. '\n'
		result = result .. '| ' .. data.forms.gd_sg_def .. '\n'
		result = result .. '| (unor) ' .. data.forms.gd_pl_indef .. '\n'
		result = result .. '| ' .. data.forms.gd_pl_def .. '\n'
		result = result .. '|-\n'
		result = result .. '! style="height:3em;background:#e2e4cb" | vocative\n'
		result = result .. '| colspan="2" | ' .. data.forms.v_sg .. '\n'
		result = result .. '| colspan="2" | ' .. data.forms.v_pl .. '\n'
		result = result .. '|}\n'
		result = result .. '</div></div>'
	end
	return result
end

return export