local export = {}

local m_IPA = require("Module:IPA")
local lang = require("Module:languages").getByCode("pl")

local V = "aɒõẽɛeɔoɨui";

local di = {
	["cz"]="t_ʂ", ["rz"]="ꙮ", ["sz"]="ʂ", ["dz"]="d_z",
}

local phon = {
	["a"]="a",	["á"]="ɒ",	["å"]="ɒ",	["ą"]="õ",
	["b"]="b",	[""]="bJ",	["c"]="t_s", ["ć"]="t_ɕ", ["d"]="d",
	["e"]="ɛ",	["é"]="e",	["ę"]="ɛ̃",
	["f"]="f",	["g"]="ɡ",	["h"]="x",
	["i"]="i",	["j"]="j",	["k"]="k",	["l"]="l",	["ł"]="ɫ",	
	["m"]="m",	["ḿ"]="mJ",	["n"]="n",	["ń"]="ɲ",	["o"]="ɔ",	["ó"]="o",
	["p"]="p",	["ṕ"]="pJ", ["r"]="r",	["s"]="s",	["ś"]="ɕ",	["t"]="t",
	["u"]="u",	["w"]="v",	["ẃ"]="vJ",	["y"]="ɨ",
	["z"]="z",	["ż"]="ʐ",	["ź"]="ʑ",
}

local function phonemic(text, keep_rz)

	local ante = false;
	local unstressed = false;

	if (text:find('^*')) then
		unstressed = true;
		text = text:sub(2);
	elseif (text:find('^%^')) then
		ante = true;
		text = text:sub(2);
	end

	function rsub(s, r) text = mw.ustring.gsub(text, s, r); end

	text = mw.ustring.lower(text);

	rsub('ch', 'x'); rsub('[crsd]z', di); rsub('dż', 'd_ʐ'); -- handle digraphs
	rsub(".", phon) -- basic orthographical rules
	rsub('b́', 'bJ'); rsub('au', 'aW'); rsub('ɒu', 'ɒW');
	rsub("n(%.?[kɡx])", "ŋ%1");

	-- palatalisation
	local C_palat = 'bdfɡxklmnprstvzʐʂ'
	-- palatilisation by <-i->
	rsub("(["..C_palat.."])i(["..V.."])", function (c, v)
		return (({
			['n'] = 'ɲ',
			['s'] = 'ɕ', ['z'] = 'ʑ',
		})[c] or c .. 'I') .. v;
	end);
	-- palatalisation by front vowels
	local F = 'eéiy';
	rsub('(['..C_palat..'])i', function (c)
		return (({
			['n'] = 'ɲ',
			['s'] = 'ɕ', ['ʃ'] = 'ɕ',
			['z'] = 'ʑ', ['ʒ'] = 'ʑ',
		})[c] or c) .. 'i';
	end);

	-- voicing and devoicing
	local T = 'ptsʂɕkx';
	local D = 'bdzʐʑɡ';

	rsub('(['..T..'])v', '%1f');
	if (not keep_rz) then
		rsub('(['..T..'])ꙮ', '%1ʂ'); rsub('ꙮ', 'ʐ');
	end

	local function arr_list(x) local r = ''; for i in pairs(x) do r = r..i; end return r; end
	local devoice = {
		['b'] = 'p', ['d'] = 't', ['ɡ'] = 'k',
		['z'] = 's', ['v'] = 'f', ['ʒ'] = 'ʃ',
		['ʑ'] = 'ɕ', ['ʐ'] = 'ʂ',
	};
	rsub('['..arr_list(devoice)..']$', devoice);
	rsub('vJ$', 'fJ'); rsub('bJ$', 'pJ');

	local voice = {}; for i, v in pairs(devoice) do voice[v] = i; end

	local arr_list_devoice = arr_list(devoice);
	local arr_list_voice = arr_list(voice);

	for _ = 0, 5 do
		rsub('(['..arr_list_devoice..'])([._]?['..T..'])', function (a, b) return devoice[a] .. b; end)
		rsub('([bv])J([._]?['..T..'])', function (a, b) return devoice[a] .. 'I' .. b; end)
		rsub('(['..arr_list_voice..'])([._]?['..D..'])', function (a, b) return voice[a] .. b; end)
	end

	rsub("t([sɕ])", "t_%1"); rsub("d([zʑ])", "d_%1"); -- affricates

	-- hyphenation 
	rsub('%.', '!');
	for _ = 0, 1 do
		rsub('(['..V..'W])([^'..V..'W!.]*)(['..V..'])', function (a, b, c)
			local function find(x) return mw.ustring.find(b, x); end
			if ((mw.ustring.len(b) < 2) or find('^([td]_.)$')) then
				b = '.'..b;
			else
				local i = 2;
				if (find('^([td]_.)')) then i = 4; end
				if (mw.ustring.sub(b, i, i):find('^[rlwIJ]$')) then
					b = '.'..b;
				else
					b = mw.ustring.sub(b, 0, i - 1)..'.'..mw.ustring.sub(b, i);
				end
			end
			return a..b..c;
		end);
	end
	rsub('!', '.')

	-- stress
	if (not unstressed) then
		if (ante) then
			rsub('%.([^.]+%.[^.]+%.[^.]+)$', 'ˈ%1');
		else
			rsub('%.([^.]+%.[^.]+)$', 'ˈ%1');
		end
		if (not mw.ustring.find(text, 'ˈ')) then
			text = 'ˈ' .. text;
		end
	end

	rsub('õ', 'ɔ̃'); rsub('ẽ', 'ɛ̃');

	if (keep_rz) then rsub('ꙮ', 'r̝'); end
	
	rsub('_', '͡'); rsub('I', 'j'); rsub('J', 'ʲ');

	text = mw.ustring.lower(text);

	return text

end

function export.convert_to_IPA(term, keep_rz)
	if (term:find(' ')) then
		local s = '';
		for v in term:gmatch('[^ ]+') do
			s = s..phonemic(v, keep_rz)..' ';
		end
		return s:sub(0, -2);
	else
		return phonemic(term, keep_rz);
	end
end

function export.convert_to_IPA_tables(terms)
	local IPA_results = {};
	for _, term in ipairs(terms) do
		table.insert(IPA_results, { pron = "/" .. export.convert_to_IPA(term) .. "/" })
		if (term:find('rz')) then
			table.insert(IPA_results, { pron = "/" .. export.convert_to_IPA(term, true) .. "/" })
		end
	end
	return IPA_results;
end

function export.IPA(frame)
	local terms = {}

	local args = frame:getParent().args;

	for _, term in ipairs(args) do
		table.insert(terms, term)
	end

	if #terms == 0 then
		terms = {mw.title.getCurrentTitle().text}
	end

	local IPA_results = export.convert_to_IPA_tables(terms);

	return require('Module:accent qualifier').format_qualifiers(lang, {'โปแลนด์กลาง'})
		..' '.. m_IPA.format_IPA_full { lang = lang, items = IPA_results }
end

return export