"اس ماڈیول کی دستاویز ماڈیول:compound/دستاویز پر بنائی جاسکتی ہے"

local m_links = require("Module:links")
local m_utilities = require("Module:utilities")

local export = {}

-- FIXME: should be script-based
-- But we can't do that unless we do script detection before linking.
local hyphens = {
	["ar"] = "ـ",
	["fa"] = "ـ",
	["he"] = "־",
	["ja"] = "",
	["ko"] = "",
	["yi"] = "־",
	["zh"] = "",
}

local function pluralize(pos)
	if pos ~= "nouns" and mw.ustring.sub(pos, -5) ~= "verbs" and mw.ustring.sub(pos, -4) ~= "ives" then
		if pos:find("[sx]$") then
			pos = pos .. ""
		else
			pos = pos .. ""
		end
	end
	return pos
end

local function link_term(terminfo, lang, sc)
	local terminfo_new = {}
	
	for key, val in pairs(terminfo) do
		terminfo_new[key] = val
	end
	
	if terminfo_new.lang then
		return require("Module:etymology").format_borrowed(lang, terminfo, sort_key, false, true)
	else
		terminfo_new.lang = lang
		terminfo_new.sc = terminfo_new.sc or sc
		return m_links.full_link(terminfo_new, "term", false)
	end
end


local function get_hyphen(lang, sc)
	--The script will be "Latn" for transliterations.
	if sc and sc:getCode() == "Latn" then
		return "-"
	else
		return hyphens[lang:getCode()] or "-"
	end
end


local function get_affix_type(lang, sc, part)
	if not part then
		return nil
	end
	
	local hyphen = get_hyphen(lang, sc)
	local hyphen_space_hyphen = hyphen .. " " .. hyphen
	
	part = part:gsub("^*", "")

	if mw.ustring.find(part, hyphen_space_hyphen, 1, true) then
		return "circumfix"
	elseif mw.ustring.sub(part, 1, 1) == hyphen and mw.ustring.sub(part, -1) == hyphen then
		return "infix"
	elseif mw.ustring.sub(part, -1) == hyphen then
		return "prefix"
	elseif mw.ustring.sub(part, 1, 1) == hyphen then
		return "لاحقہ"
	else
		return nil
	end
end


function export.show_affixes(lang, sc, parts, pos, sort_key, nocat)
	pos = pos or "لفظ"
	
	pos = pluralize(pos)
	
	-- Process each part
	local parts_formatted = {}
	local categories_formatted = {}
	local whole_words = 0
	
	for i, part in ipairs(parts) do
		-- Make a link for the part
		table.insert(parts_formatted, link_term(part, lang, sc, sort_key))
		
		-- Is it an affix, and if so, what type of affix?
		local affix_type = get_affix_type(part.lang or lang, part.sc or sc, part.term)
		
		if affix_type then
			-- Make a sort key
			-- For the first part, use the second part as the sort key
			local part_sort_base = nil
			local part_sort = part.sort or sort_key
			
			if i == 1 and parts[2] and parts[2].term then
				part_sort_base = lang:makeEntryName(parts[2].term)
			end
			
			if affix_type == "infix" then affix_type = "interfix" end
			
			if part.pos and mw.ustring.match(part.pos, "patronym") then
				table.insert(categories_formatted, m_utilities.format_categories({lang:getCanonicalName() .. " patronymics"}, lang, part_sort, part_sort_base))
			end
			
			if pos ~= "الفاظ" and part.pos and mw.ustring.match(part.pos, "diminutive") then
				table.insert(categories_formatted, m_utilities.format_categories({lang:getCanonicalName() .. " diminutive " .. pos}, lang, part_sort, part_sort_base))
			end
			
			table.insert(categories_formatted, m_utilities.format_categories({lang:makeEntryName(part.term) .. " " .. affix_type .. " والا " .. " " .. lang:getCanonicalName() .. " " .. pos .. (part.id and " (" .. part.id .. ")" or "")}, lang, part_sort, part_sort_base))
		else
			whole_words = whole_words + 1
			
			if whole_words == 2 then
				table.insert(categories_formatted, m_utilities.format_categories({lang:getCanonicalName() .. " کے مرکب " .. pos}, lang, sort_key))
			end
		end
	end
	
	-- If there are no categories, then there were no actual affixes, only regular words.
	-- This function does not support compounds (yet?), so show an error.
	if #categories_formatted == 0 then
		error("The parameters did not include any affixes, and the word is not a compound. Please provide at least one affix.")
	end
	
	return table.concat(parts_formatted, " +‎ ") .. (nocat and "" or table.concat(categories_formatted))
end


function export.show_compound(lang, sc, parts, pos, sort_key, nocat)
	pos = pos or "الفاظ"
	local parts_formatted = {}
	local categories_formatted = {}
	table.insert(categories_formatted, m_utilities.format_categories({lang:getCanonicalName() .. " کے مرکب الفاظ"}, lang, sort_key))
	
	-- Make links out of all the parts
	local whole_words = 0
	for i, part in ipairs(parts) do
		table.insert(parts_formatted, link_term(part, lang, sc, sort_key))
		
		local affix_type = get_affix_type(part.lang or lang, part.sc or sc, part.term)
		
		if affix_type == "infix" then
			table.insert(categories_formatted, m_utilities.format_categories({lang:getCanonicalName() .. " " .. pos .. " interfixed with " .. lang:makeEntryName(part.term)}, lang, part.sort or sort_key))
		elseif affix_type then
			require("Module:debug").track{
				"compound",
				"compound/" .. affix_type,
				"compound/" .. affix_type .. "/lang/" .. lang:getCode()
			}
		else
			whole_words = whole_words + 1
		end
	end

	if whole_words == 1 then
		require("Module:debug").track("compound/one whole word")
	elseif whole_words == 0 then
		require("Module:debug").track("compound/looks like confix")
	end
	
	return table.concat(parts_formatted, " +‎ ") .. (nocat and "" or table.concat(categories_formatted))
end


function export.show_circumfix(lang, sc, prefix, base, suffix, pos, sort_key, nocat)
	local categories = {}
	pos = pos or "لفظ"
	
	pos = pluralize(pos)
	
	-- Hyphenate the affixes
	prefix.term = export.make_affix(prefix.term, prefix.lang or lang, prefix.sc or sc, "prefix")
	prefix.alt = export.make_affix(prefix.alt, prefix.lang or lang, prefix.sc or sc, "prefix")
	
	if prefix.annotations then
		prefix.annotations.tr = export.make_affix(prefix.annotations.tr, prefix.lang or lang, require("Module:scripts").getByCode("Latn"), "prefix")
	end
	
	suffix.term = export.make_affix(suffix.term, suffix.lang or lang, suffix.sc or sc, "suffix")
	suffix.alt = export.make_affix(suffix.alt, suffix.lang or lang, suffix.sc or sc, "suffix")
	
	if suffix.annotations then
		suffix.annotations.tr = export.make_affix(suffix.annotations.tr, suffix.lang or lang, require("Module:scripts").getByCode("Latn"), "suffix")
	end
	
	local prefix_affix_type = get_affix_type(prefix.lang or lang, prefix.sc or sc, prefix.term)
	if prefix_affix_type ~= "prefix" then
		require("Module:debug").track{
			"circumfix",
			"circumfix/prefix",
			"circumfix/prefix/" .. (prefix_affix_type or "none"),
			"circumfix/prefix/" .. (prefix_affix_type or "none") .. "/lang/" .. lang:getCode()
		}
	end
	
	local base_affix_type = get_affix_type(base.lang or lang, base.sc or sc, base.term)
	if base_affix_type then
		require("Module:debug").track{
			"circumfix",
			"circumfix/base",
			"circumfix/base/" .. base_affix_type,
			"circumfix/base/" .. base_affix_type .. "/lang/" .. lang:getCode()
		}
	end
	
	local suffix_affix_type = get_affix_type(suffix.lang or lang, suffix.sc or sc, suffix.term)
	if suffix_affix_type ~= "suffix" then
		require("Module:debug").track{
			"circumfix",
			"circumfix/suffix",
			"circumfix/suffix/" .. (suffix_affix_type or "none"),
			"circumfix/suffix/" .. (suffix_affix_type or "none") .. "/lang/" .. lang:getCode()
		}
	end
	
	-- Create circumfix term
	local circumfix = nil
	
	if prefix.term and suffix.term then
		circumfix = prefix.term .. " " .. suffix.term
		prefix.alt = prefix.alt or prefix.term
		suffix.alt = suffix.alt or suffix.term
		prefix.term = circumfix
		suffix.term = circumfix
	end
	
	-- Make links out of all the parts
	local parts_formatted = {}
	local sort_base = lang:makeEntryName(base.term)
	
	table.insert(parts_formatted, link_term(prefix, lang, sc, sort_key))
	table.insert(parts_formatted, link_term(base, lang, sc, sort_key))
	table.insert(parts_formatted, link_term(suffix, lang, sc, sort_key))
	
	-- Insert the categories
	table.insert(categories, lang:getCanonicalName() .. " " .. pos .. " circumfixed with " .. lang:makeEntryName(circumfix, lang))
	
	return table.concat(parts_formatted, " +‎ ") .. (nocat and "" or m_utilities.format_categories(categories, lang, sort_key, sort_base))
end


function export.show_confix(lang, sc, prefix, base, suffix, pos, sort_key, nocat)
	pos = pos or "word"
	
	pos = pluralize(pos)
	
	-- Hyphenate the affixes
	prefix.term = export.make_affix(prefix.term, prefix.lang or lang, prefix.sc or sc, "prefix")
	prefix.alt = export.make_affix(prefix.alt, prefix.lang or lang, prefix.sc or sc, "prefix")
	
	if prefix.annotations then
		prefix.annotations.tr = export.make_affix(prefix.annotations.tr, prefix.lang or lang, require("Module:scripts").getByCode("Latn"), "prefix")
	end
	
	suffix.term = export.make_affix(suffix.term, suffix.lang or lang, suffix.sc or sc, "suffix")
	suffix.alt = export.make_affix(suffix.alt, suffix.lang or lang, suffix.sc or sc, "suffix")
	
	if suffix.annotations then
		suffix.annotations.tr = export.make_affix(suffix.annotations.tr, suffix.lang or lang, require("Module:scripts").getByCode("Latn"), "suffix")
	end
	
	local prefix_affix_type = get_affix_type(prefix.lang or lang, prefix.sc or sc, prefix.term)
	if prefix_affix_type ~= "prefix" then
		require("Module:debug").track{
			"confix",
			"confix/prefix",
			"confix/prefix/" .. (prefix_affix_type or "none"),
			"confix/prefix/" .. (prefix_affix_type or "none") .. "/lang/" .. lang:getCode()
		}
	end
	
	if base then
		local base_affix_type = get_affix_type(base.lang or lang, base.sc or sc, base.term)
		if base_affix_type then
			require("Module:debug").track{
			"confix",
			"confix/base",
			"confix/base/" .. base_affix_type,
			"confix/base/" .. base_affix_type .. "/lang/" .. lang:getCode()
		}
		end
	end
	
	local suffix_affix_type = get_affix_type(suffix.lang or lang, suffix.sc or sc, suffix.term)
	if suffix_affix_type ~= "suffix" then
		require("Module:debug").track{
			"confix",
			"confix/suffix",
			"confix/suffix/" .. (suffix_affix_type or "none"),
			"confix/suffix/" .. (suffix_affix_type or "none") .. "/lang/" .. lang:getCode()
		}
	end
	
	-- Make links out of all the parts
	local parts_formatted = {}
	local prefix_sort_base = lang:makeEntryName(suffix.term)
	local prefix_categories = {}
	local suffix_categories = {}
	
	table.insert(parts_formatted, link_term(prefix, lang, sc, sort_key))
	table.insert(prefix_categories, lang:getCanonicalName() .. " " .. pos .. " prefixed with " .. lang:makeEntryName(prefix.term, lang))
	
	if base then
		prefix_sort_base = lang:makeEntryName(base.term)
		table.insert(parts_formatted, link_term(base, lang, sc, sort_key))
	end
	
	table.insert(parts_formatted, link_term(suffix, lang, sc, sort_key))
	table.insert(suffix_categories, lang:getCanonicalName() .. " " .. pos .. " suffixed with " .. lang:makeEntryName(suffix.term, lang))
	
	return table.concat(parts_formatted, " +‎ ") .. (nocat and "" or m_utilities.format_categories(prefix_categories, lang, sort_key, prefix_sort_base) .. m_utilities.format_categories(suffix_categories, lang, sort_key))
end


function export.show_infix(lang, sc, base, infix, pos, sort_key, nocat)
	local categories = {}
	pos = pos or "word"
	
	pos = pluralize(pos)
	
	-- Hyphenate the affixes
	infix.term = export.make_affix(infix.term, infix.lang or lang, infix.sc or sc, "infix")
	infix.alt = export.make_affix(infix.alt, infix.lang or lang, infix.sc or sc, "infix")
	
	if infix.annotations then
		infix.annotations.tr = export.make_affix(infix.annotations.tr, infix.lang or lang, require("Module:scripts").getByCode("Latn"), "infix")
	end
	
	local base_affix_type = get_affix_type(base.lang or lang, base.sc or sc, base.term)
	if base_affix_type then
		require("Module:debug").track{
			"infix",
			"infix/base"
		}
		require("Module:debug").track{
			"infix/base/" .. base_affix_type,
			"infix/base/" .. base_affix_type .. "/lang/" .. lang:getCode()
		}
	end
	
	local infix_affix_type = get_affix_type(infix.lang or lang, infix.sc or sc, infix.term)
	if infix_affix_type ~= "infix" then
		require("Module:debug").track{
			"infix",
			"infix/infix",
			"infix/infix/" .. (infix_affix_type or "none"),
			"infix/infix/" .. (infix_affix_type or "none") .. "/lang/" .. lang:getCode()
		}
	end
	
	-- Make links out of all the parts
	local parts_formatted = {}
	
	table.insert(parts_formatted, link_term(base, lang, sc, sort_key))
	table.insert(parts_formatted, link_term(infix, lang, sc, sort_key))
	
	-- Insert the categories
	table.insert(categories, lang:getCanonicalName() .. " " .. pos .. " infixed with " .. lang:makeEntryName(infix.term))
	
	return table.concat(parts_formatted, " +‎ ") .. (nocat and "" or m_utilities.format_categories(categories, lang, sort_key))
end


function export.show_prefixes(lang, sc, prefixes, base, pos, sort_key, nocat)
	pos = pos or "word"
	
	pos = pluralize(pos)
	
	-- Hyphenate the affixes
	for i, prefix in ipairs(prefixes) do
		prefixes[i].term = export.make_affix(prefix.term, prefix.lang or lang, prefix.sc or sc, "prefix")
		prefixes[i].alt = export.make_affix(prefix.alt, prefix.lang or lang, prefix.sc or sc, "prefix")
		
		if prefix.annotations then
			prefixes[i].annotations.tr = export.make_affix(prefix.annotations.tr, prefix.lang or lang, require("Module:scripts").getByCode("Latn"), "prefix")
		end
	end
	
	for i, prefix in ipairs(prefixes) do
		local prefix_affix_type = get_affix_type(prefix.lang or lang, prefix.sc or sc, prefix.term)
		if prefix_affix_type ~= "prefix" then
			require("Module:debug").track{
			"prefix",
			"prefix/prefix",
			"prefix/prefix/" .. (prefix_affix_type or "none"),
			"prefix/prefix/" .. (prefix_affix_type or "none") .. "/lang/" .. lang:getCode()
		}
		end
	end
	
	if base then
		local base_affix_type = get_affix_type(base.lang or lang, base.sc or sc, base.term)
		if base_affix_type then
			require("Module:debug").track{
			"prefix",
			"prefix/base",
			"prefix/base/" .. base_affix_type,
			"prefix/base/" .. base_affix_type .. "/lang/" .. lang:getCode()
		}
		end
	end
	
	-- Make links out of all the parts
	local parts_formatted = {}
	local first_sort_base = nil
	local categories = {}
	
	for i, prefix in ipairs(prefixes) do
		table.insert(parts_formatted, link_term(prefix, lang, sc, sort_key))
		table.insert(categories, lang:getCanonicalName() .. " " .. pos .. " prefixed with " .. lang:makeEntryName(prefix.term, lang) .. (prefix.id and " (" .. prefix.id .. ")" or ""))
		
		if i > 1 and first_sort_base == nil then
			first_sort_base = lang:makeEntryName(prefix.term)
		end
	end
	
	if base then
		if first_sort_base == nil then
			first_sort_base = lang:makeEntryName(base.term)
		end
		
		table.insert(parts_formatted, link_term(base, lang, sc, sort_key))
	else
		table.insert(parts_formatted, "")
	end
	
	local first_category = table.remove(categories, 1)
	return table.concat(parts_formatted, " +‎ ") .. (nocat and "" or m_utilities.format_categories({first_category}, lang, sort_key, first_sort_base) .. m_utilities.format_categories(categories, lang, sort_key))
end


function export.show_suffixes(lang, sc, base, suffixes, pos, sort_key, nocat)
	local categories = {}
	pos = pos or "word"
	
	pos = pluralize(pos)
	
	-- Hyphenate the affixes
	for i, suffix in ipairs(suffixes) do
		suffixes[i].term = export.make_affix(suffix.term, suffix.lang or lang, suffix.sc or sc, "suffix")
		suffixes[i].alt = export.make_affix(suffix.alt, suffix.lang or lang, suffix.sc or sc, "suffix")
		
		if suffix.annotations then
			suffixes[i].annotations.tr = export.make_affix(suffix.annotations.tr, suffix.lang or lang, require("Module:scripts").getByCode("Latn"), "suffix")
		end
	end
	
	if base then
		local base_affix_type = get_affix_type(base.lang or lang, base.sc or sc, base.term)
		if base_affix_type then
			require("Module:debug").track{
			"suffix",
			"suffix/base",
			"suffix/base/" .. base_affix_type,
			"suffix/base/" .. base_affix_type .. "/lang/" .. lang:getCode()
		}
		end
	end
	
	for i, suffix in ipairs(suffixes) do
		local suffix_affix_type = get_affix_type(suffix.lang or lang, suffix.sc or sc, suffix.term)
		if suffix_affix_type ~= "suffix" then
			require("Module:debug").track{
			"suffix",
			"suffix/suffix",
			"suffix/suffix/" .. (suffix_affix_type or "none"),
			"suffix/suffix/" .. (suffix_affix_type or "none") .. "/lang/" .. lang:getCode()
		}
		end
	end
	
	-- Make links out of all the parts
	local parts_formatted = {}
	
	if base then
		table.insert(parts_formatted, link_term(base, lang, sc, sort_key))
	else
		table.insert(parts_formatted, "")
	end
	
	for i, suffix in ipairs(suffixes) do
		table.insert(parts_formatted, link_term(suffix, lang, sc, sort_key))
	end
	
	-- Insert the categories
	for i, suffix in ipairs(suffixes) do
		table.insert(categories, lang:getCanonicalName() .. " " .. pos .. " suffixed with " .. lang:makeEntryName(suffix.term) .. (suffix.id and " (" .. suffix.id .. ")" or ""))
		
		if suffix.pos and mw.ustring.match(suffix.pos, "patronym") then
			table.insert(categories, lang:getCanonicalName() .. " patronymics")
		end
	end
	
	return table.concat(parts_formatted, " +‎ ") .. (nocat and "" or m_utilities.format_categories(categories, lang, sort_key))
end


function export.show_transfix(lang, sc, base, transfix, pos, sort_key, nocat)
	local categories = {}
	pos = pos or "word"
	
	pos = pluralize(pos)
	
	-- Hyphenate the affixes
	transfix.term = export.make_affix(transfix.term, transfix.lang or lang, transfix.sc or sc, "transfix")
	transfix.alt = export.make_affix(transfix.alt, transfix.lang or lang, transfix.sc or sc, "transfix")
	transfix.tr = export.make_affix(transfix.tr, transfix.lang or lang, require("Module:scripts").getByCode("Latn"), "transfix")
	
	-- Make links out of all the parts
	local parts_formatted = {}
	
	table.insert(parts_formatted, link_term(base, lang, sc, sort_key))
	table.insert(parts_formatted, link_term(transfix, lang, sc, sort_key))
	
	-- Insert the categories
	table.insert(categories, lang:getCanonicalName() .. " " .. pos .. " transfixed with " .. lang:makeEntryName(transfix.term))
	
	return table.concat(parts_formatted, " +‎ ") .. (nocat and "" or m_utilities.format_categories(categories, lang, sort_key))
end


-- Adds a hyphen to a word in the appropriate place
function export.make_affix(term, lang, sc, affixtype)
	if not (affixtype == "prefix" or affixtype == "suffix" or affixtype == "circumfix" or affixtype == "infix" or affixtype == "interfix" or affixtype == "transfix") then
		error("Invalid affix type")
	end
	
	if not term then
		return nil
	elseif affixtype == "circumfix" or affixtype == "transfix" then
		return term
	elseif affixtype == "interfix" then
		affixtype = "infix"
	end
	
	local detected_type = get_affix_type(lang, sc, term)
	
	if affixtype and detected_type == affixtype or (detected_type == "infix" and affixtype == "prefix") or (detected_type == "infix" and affixtype == "suffix") then
		return term
	end
	
	--remove an asterisk if the morpheme is reconstructed and add it in the end
	local reconstructed = ""
	if term:find("^*") then 
		reconstructed = "*"
		term = term:gsub("^*", "")
	end
	
	local hyphen = get_hyphen(lang, sc)
	
	if affixtype == "suffix" then
		term = hyphen .. term
	elseif affixtype == "prefix" then
		term = term .. hyphen
	elseif affixtype == "infix" then
		term = hyphen .. term .. hyphen
	else
		error("Invalid affix type")
	end
	
	return reconstructed .. term
end

return export