--[=[

This module is a rewrite of the existing wikitext template ((Language with name/for)).  The primary purpose of
the rewrite is to bring the non-English text into the template so that it can be marked up by ((lang)).

To accomodate the variety of uses of the template, news parameters are introduced to allow variable styling.

supported parameters (original)
	(({1))} – language tag
	(({2))} – non-English 'term' to be wrapped in ((lang)) using tag in (({1))}; modified to accept keyword 'none' to prevent categorization
	(({3))} – English translation of (({2))} in single quotes; alias: |term1=
	|links= – 'yes' or 'no'; default is 'yes'; links language name derived from (({2))}

supported parameters (new)
	|term1= – alias of (({3))}
	|term2= .. |termn= – additional 'or'-like translations; each rendered in single quotes; quoted terms separated by '<space>/<space>'
	|italic-term= 'yes' or 'no'; default is 'no'; useful to multi-term translations when all should be italicized
	|lang-name= – for those cases where ISO 639 does not have a language tag; (({1))} ignored; template wraps (({2))} with ((lang)) using 'mis' (uncoded language)
	|break= – 'yes' or 'no'; default is 'no'; inserts <br /> between (({2))} and the rest of the rendering
	|paren= – takes one of three values:
		'none' – omit left and right parens around '<language-name> for <term>'
		'left' – includes left paren, omits right paren
		'right' – includes right paren, omits left paren

because this template now calls ((lang)) properly, it also supports the ((lang)) parameters:
	|rtl=
	|italic= (and aliases |italics= and |i=)
	|size=
	|cat=
	|nocat=
	
basic rendering
	<non-English text> (<language-name> for '<term>')

multiple terms
	<non-English text> (<language-name> for '<term>' / '<term>' / '<term>')

|paren=none
	<non-English text> <language-name> for '<term>'

|break=yes
	<non-English text><br />(<language-name> for '<term>')

|italic-term=yes
	<non-English text> (<language-name> for '<i><term></i>' / '<i><term></i>' / '<i><term></i>')

|lang-name=<lang-name>
	<non-English text> ([[<lang-name> language|<lang-name>]] for '<term>')

]=]

require ('strict');
local get_args = require ('Module:Arguments').getArgs;
local lang_mod = require ('Module:Lang');


--[[--------------------------< E R R O R _ M E S S A G E >----------------------------------------------------

render an error message with help-text link and category.

]]

local function error_message (message)
	local err_msg_t = {'<span style="color:#d33">Error: ((language with name/for)): '};		-- open span and initial bit of the error message
	table.insert (err_msg_t, message);											-- the rest of the message
	table.insert (err_msg_t, ' ([[Template:Language with name/for|help]])</span>');	-- the help link

	local namespace = mw.title.getCurrentTitle().namespace;						-- namespace number
	if 0 == namespace or 10 == namespace then
		table.insert (err_msg_t, '[[Category:Language with name/for errors]]');	-- categorize in main and template namespaces
	end

	return table.concat (err_msg_t);											-- make a big string and done
end


--[[--------------------------< T E R M S _ G E T >------------------------------------------------------------

get value(s) assigned to (({3))} or to any number of |termn= parameters.  Return a string where each term is in
single quotes.  If more than one |termn= parameter, separate each term with <space>/<space>.  Apply italic markup
when |itlaic-term=yes

]]

local function terms_get (args_t)
	local function render_term (term, is_italic)								-- local function to do the rendering
		if is_italic then
			term = term:gsub ('.+', '<i>%1</i>');								-- apply italic markup; html to avoid converting '' to ''' when quoted
		end
		if is_italic or term:match ('[^\']\'\'$') then
			term = term:gsub ('.+', '&#39;%1<span style="margin-left:.09em">&#39;</span>');
		else
			term = term:gsub ('.+', '&#39;%1&#39;');								-- quote using &#39; in case term uses italic or bold wikimarkup
		end
		return term;															-- done this was to avoid second string.gsub() return value
	end

	local is_italic = 'yes' == args_t['italic-term'];							-- make boolean
	
	if args_t[3] then															-- if (({3))} has a value
		return render_term (args_t[3], is_italic);
	end
	
	local terms = {};															-- a table to hold one or more non-English terms
	
	for k, v in pairs (args_t) do
		if 'string' == type (k) and k:match ('term%d') then						-- string parameter names only
			table.insert (terms, k:match ('term(%d+)') .. '=' .. v);			-- convert k/v pairs to a sequence that can be sorted by |termn= enumerator (enum=term)
		end
	end
	
	table.sort (terms, function (a, b)											-- sort the sequence using local sort function
		local enum_a = a:match ('^%d+');										-- make numbers for the comparison
		local enum_b = b:match ('^%d+');
		return tonumber(enum_a) < tonumber(enum_b)								-- and compare
		end
		);
	
	for i, v in ipairs (terms) do												-- rewrite the sequence to be sorted sequence of terms
		terms[i] = render_term (v:gsub ('%d+=(.+)', '%1'), is_italic);			-- extract term; italicize as required, and quote
	end

	return table.concat (terms, ' / ');											-- form a string and done
end


--[[--------------------------< T E X T _ M A K E >------------------------------------------------------------

if (({2))} has a value (the non-English text) use ((lang)) to apply proper html markup.  When |lang-name= has a
value, override any value that might be in (({1))} with 'mis' (uncoded languages) 

TODO: error condition when both of (({2))} and |lang-name= have values?

]]

local function text_make (lang_params_t)
	if not lang_params_t[2] then
		return '';
	end

	return lang_mod._lang (lang_params_t);
end


--[[--------------------------< L A N G _ M A K E >------------------------------------------------------------

render the language name portion of the output.  |lang-name= overrides (({1))}.  Language name links to language
article through '<language name> language' redirect except when |links=no

]]

local function lang_make (args_t, lang_params_t)
	if args_t['lang-name'] then
		if 'no' == args_t.links then
			return args_t['lang-name'];
		end
		
		local lang_t = {};														-- holds component parts of language name link when using |lang-name=<language>
		table.insert (lang_t, '[[');											-- open wikilink
		table.insert (lang_t, args_t['lang-name']);								-- add the name from |lang-name=
		table.insert (lang_t, ' language|');									-- add ' languge' for redirect and pipe for link label
		table.insert (lang_t, args_t['lang-name']);								-- add language name as label for wikilink
		table.insert (lang_t, ']]');											-- close wikilink
		return table.concat (lang_t);											-- and make a big string and done
	end
		
	return lang_mod._name_from_tag (lang_params_t);								-- get language name (linked or not) from ((lang|fn=name_from_tag))
end


--[[--------------------------< _ L A N G N F >----------------------------------------------------------------

entry point from another module

]]

local function _langnf (args_t)
	if not (args_t[1] or args_t['lang-name']) then
		return error_message ('missing language tag or language name');
	end

	if (args_t[1] and args_t['lang-name']) then
		return error_message ('only one of <kbd>(({1))}</kbd> and <kbd>|lang-name=</kbd> allowed');
	end

	if not (args_t[3] or args_t.term1) then
		return error_message ('missing English translation');
	end

	local lang_params_t = {														-- build a table of parameters to be used by ((lang))
		link = args_t.links or 'yes', ['rtl']=args_t.rtl,						-- used by ((lang|fn=tag_from_name))
		[1] = args_t['lang-name'] and 'mis' or args_t[1],						-- used by ((lang)) and by ((lang|fn=tag_from_name))
		[2] = args_t[2],														-- the rest of these are ((lang)) parameters used only by ((lang))
		rtl = args_t.rtl,														-- right-to-left; not normally needed
		i = args_t.i,															-- |italic= alias
		italic = args_t.italic,
		italics = args_t.italics,												-- |italic= alias
		size = args_t.size,
		cat = args_t.cat,
		nocat = args_t.nocat,
		template = 'Language with name/for',
		}

	local out_t = {};															-- components of the rendering go here
	local left_paren = ('none' == args_t.paren or 'right' == args_t.paren) and '' or '(';
	local right_paren = (not args_t[2] or 'none' == args_t[2] or 'left' == args_t.paren or 'none' == args_t.paren) and '' or ')';
	
	if args_t[2] and ('none' ~= args_t[2]) then									-- optional;  (({2))} may be omitted; keyword 'none' prevents categorization; used in ((infobox papal document))
		table.insert (out_t, text_make (lang_params_t));						-- the non-English text marked up by ((lang))
		table.insert (out_t, 'yes' == args_t['break'] and '<br />' or ' ');		-- <br /> when |break=yes; <space> else
		table.insert (out_t, left_paren);										-- omit left paren around '<language name> for <term>' when |paren=none or |paren=right
	end
	table.insert (out_t, lang_make (args_t, lang_params_t));					-- language name; linked unless |links=no
	table.insert (out_t, ' for ');												-- the 'for' static text
	table.insert (out_t, terms_get (args_t));									-- and the term(s) italicized as appropriate and quoted
	table.insert (out_t, right_paren);											-- omit right paren around '<language name> for <term>' when |paren=none or |paren=left or (({2))} omitted
	
	if not args_t[2] then														-- if this template doesn't use (({2))} for the non-English text
		table.insert (out_t, '[[Category:Pages with Langnf omitting second positional parameter]]');	-- add this category
	end
	
	return table.concat (out_t);												-- make a big string and done
end


--[[--------------------------< L A N G N F >------------------------------------------------------------------

implements ((language with name/for))

((#invoke:Language with name/for|langnf))

]]

local function langnf (frame)
	local args_t = get_args (frame);
	return _langnf (args_t)
end


--[[--------------------------< E X P O R T S >----------------------------------------------------------------
]]

return {
	langnf = langnf,															-- entry point from a template
	
	_langnf = _langnf,															-- entry point from another module
	}