local export = {}

local lang = require("Module:languages").getByCode("zu")
local common = require("Module:zu-common")

local ACUTE = mw.ustring.char(0x0301)

local vowels = "aeiouAEIOU"
local prefixes = {
	["1"] = {"umu", "um"},
	["2"] = "aba",
	["1a"] = {"u"},
	["2a"] = "ō",
	["3"] = {"umu", "um", "u"},
	["4"] = "imi",
	["5"] = {"ili", "ī", "i"}, --should we require long vowel marking?
	["6"] = "ama",
	["7"] = {"isi", "is"},
	["8"] = "izi",
	["9"] = {"i"},
	["10"] = "izin",
	["11"] = {"ulu", "ū", "u"}
}

local classes = {
	["1"] = "2", 
	["1a"] = "2a", 
	["3"] = "4", 
	["5"] = "6", 
	["7"] = "8",
	["9"] = "10", 
	["11"] = "10"
}

function export.noun(frame)
	local params = {
		[1] = {},
		[2] = {},
		[3] = {}
	}
	
	local args = require("Module:parameters").process(frame:getParent().args, params)
	
	local categories = {}
	local head
	if not args[1] then
		args[1] = mw.title.getCurrentTitle().subpageText
		head = args[1]:gsub("^-", "") .. "<sup title=\"tones missing\">?</sup>"
		table.insert(categories, "Requests for tone in " .. lang:getCanonicalName() .. " noun entries")
	end
	
	local class
	if args[2] then
		class = mw.text.split(args[2], "%/")[1]
	else
		class = "?"
	end
	
	local data = {lang = lang, pos_category = "nouns", categories = categories, heads = {head or args[1]}, genders = {"c" .. class}, inflections = {}}
	
	if class ~= "?" then
		table.insert(data.categories, lang:getCanonicalName() .. " class " .. class .. " nouns")
	end
	
	if args[3] ~= "-" and classes[args[2]] then
		local infl_plural = {label = "plural", accel = {form = "p", gender = classes[args[2]]}, request = true}
		
		-- If no plural was provided, generate one
		if not args[3] then
			local singular = args[1] and require("Module:links").remove_links(args[1]) or mw.title.getCurrentTitle().text
			if args[2] == "1" or args[2] == "3" then
				-- add a '.' after the syllabic m
				singular = mw.ustring.toNFC(mw.ustring.gsub(mw.ustring.toNFD(singular), "^um(" .. ACUTE .. "?)([^u])", "um%1.%2"))
			end
			local split_tone = common.split_tone(singular)
			singular = split_tone[1]
			local tones = adjust_tones(args[2], split_tone[2])
			args[3] = pluralize(singular, args[2])
			args[3] = common.apply_tone(args[3], tones, true)
		end
		
		table.insert(infl_plural, {term = args[3], genders = {classes[args[2]]}})
		
		table.insert(data.inflections, infl_plural)
	end
	
	return require("Module:headword").full_headword(data)
end

function agglutinate(prefix, stem)
	local nasal_changes = {
		["ph"] = "p",
		["th"] = "t",
		["kh"] = "k",
		["ch"] = "c",
		["qh"] = "q",
		["xh"] = "x",
		["sh"] = "tsh",
		["c"] = "gc",
		["q"] = "gq",
		["x"] = "gx"
	}

	local pre_len = prefix:len()
	local first_letter = stem:sub(1, 1)
	if prefix:sub(pre_len) == "n" then
		if first_letter == "b" or first_letter == "p" or first_letter == "f" or first_letter == "v" then
			prefix = prefix:gsub("n$", "m")
		elseif first_letter == "n" or first_letter == "m" or first_letter == "l" then
			prefix = prefix:sub(1, pre_len-1)
		end

		for init, changed in pairs(nasal_changes) do
			if stem:find("^" .. init) then
				stem = stem:gsub("^" .. init, changed)
				break
			end
		end
	end

	if stem:find("^["..vowels.."]") then
		prefix = prefix:sub(1, pre_len-1)
	end
	
	return prefix .. stem
end

function adjust_tones(class, tones)
	--Adjust tone pattern for monosyllable prefix -> disyllable prefix
	if class == "5" or class == "9" or class == "11" then
		if tones:find("^F") then -- Class 5 or 11 before H
			tones = "HL"..tones:sub(2)
		elseif tones:find("^HH") then -- Class 9 before H
			tones = "HL"..tones:sub(2)
		else -- H prefix before L becomes LH, or L prefix becomes LL
			tones = "L"..tones
		end
	elseif class == "1a" then --long vowel prefix
		if tones:find("^HH") then
			tones = "F"..tones:sub(2)
		end
	end
	
	return tones
end

function pluralize(word, class)
	local is_singular = false
	for sg, pl in pairs(classes) do
		if class == sg then is_singular = true end
	end

	if not is_singular then error("Must give word in singular.") end

	local stem

	for _, prefix in ipairs(prefixes[class]) do
		local i, j = word:find("^" .. prefix)
		if j then
			stem = word:sub(j+1)
			break
		end
	end

	if not stem then error("Could not parse stem.") end

	return agglutinate(prefixes[classes[class]], stem)
end

function export.adjective(frame)
	local params = {
		[1] = {},
		}
	
	local args = require("Module:parameters").process(frame:getParent().args, params)
	
	local data = {lang = lang, pos_category = "adjectives", categories = {}, heads = {args[1]}, inflections = {}}
	
	if not args[1] then
		data.heads[1] = mw.title.getCurrentTitle().subpageText:gsub("^-", "") .. "<sup title=\"tones missing\">?</sup>"
		table.insert(data.categories, "Requests for tone in " .. lang:getCanonicalName() .. " adjective entries")
	end
	
	data.heads[1] = "-" .. data.heads[1]
	
	return require("Module:headword").full_headword(data)
end


function export.relative(frame)
	local params = {
		[1] = {},
		}
	
	local args = require("Module:parameters").process(frame:getParent().args, params)
	
	local data = {lang = lang, pos_category = "relatives", categories = {}, heads = {args[1]}, inflections = {}}
	
	if not args[1] then
		data.heads[1] = mw.title.getCurrentTitle().subpageText:gsub("^-", "") .. "<sup title=\"tones missing\">?</sup>"
		table.insert(data.categories, "Requests for tone in " .. lang:getCanonicalName() .. " relative entries")
	end
	
	data.heads[1] = "-" .. data.heads[1]
	
	return require("Module:headword").full_headword(data)
end

function export.ideophone(frame)
	local params = {
		[1] = {},
		}
	
	local args = require("Module:parameters").process(frame:getParent().args, params)
	
	local data = {lang = lang, pos_category = "ideophones", categories = {}, heads = {args[1]}, inflections = {}}
	
	if not args[1] then
		data.heads[1] = mw.title.getCurrentTitle().subpageText:gsub("^-", "") .. "<sup title=\"tones missing\">?</sup>"
		table.insert(data.categories, "Requests for tone in " .. lang:getCanonicalName() .. " ideophone entries")
	end
	
	return require("Module:headword").full_headword(data)
end


function export.verb(frame)
	local params = {
		[1] = {},
		}
	
	local args = require("Module:parameters").process(frame:getParent().args, params)
	
	local data = {lang = lang, pos_category = "verbs", categories = {}, heads = {args[1]}, inflections = {}}
	
	if not args[1] then
		data.heads[1] = mw.title.getCurrentTitle().subpageText:gsub("^-", "") .. "<sup title=\"tones missing\">?</sup>"
		table.insert(data.categories, "Requests for tone in " .. lang:getCanonicalName() .. " verb entries")
	end
	
	data.heads[1] = "-" .. data.heads[1]
	
	return require("Module:headword").full_headword(data)
end

return export