Documentation for this module may be created at Module:Infobox3/doc

-- Mòdulu pro implementare sas funtzionalidades de Infobox (adatadu dae sa versione italiana)
local p = {} -- pro s'esportatzione de sas funziones de su mòdulu

local args = {}-- variàbile chi cuntenet sos argumentos colados a su template
local origArgs
local root -- raighina de su markup html
local dump = {}

local function checkList(valore)
	-- Permitit a su programma Mediawiki de amministrare sas listas # o *
	local c = mw.ustring.sub(valore, 1, 1)
	if c == '#' or c == '*' then
		valore = '<div>\n' .. valore .. '\n</div>'
	end
	return valore .. '\n'
end

local function getArgNums(...)
	-- Frunit una lista chi cuntenet su sufissu numèricu de totu sos argumentos
	-- chi incumintzant cun su prefissu "prefix"
	-- A esèmpiu, si in sa lista de argumentos sunt valorizados "Valore1, Valore2 e Valore4"
	-- at a frunire sa lista [1, 2, 4]
	local prefixs = {...}
	local nums = {}
	for k, _ in pairs(args) do
		local num = nil
		for _, candidate in ipairs(prefixs) do
			num = ('' .. k):match('^' .. candidate .. '(%d+)$')
			if num ~= nil then break end
		end
		if num then table.insert(nums, tonumber(num)) end
	end
	table.sort(nums)
	return nums
end

local function addRow(rowArgs)
	-- Annanghet una riga a sa tabella
	-- Si rowArgs.grupu no est nullu lu cunsiderat che a una riga de testada de grupu
	-- e ignorat valorizatziones eventuales de rowArgs.valore
	if rowArgs.grupu then
		root
			:tag('tr')
				:addClass("sinòticu_partzidura")
				:tag('th')
					:attr('colspan', 2)
					:cssText(rowArgs.istile or args.IstileGrupu or '')
					:wikitext(rowArgs.grupu)
	-- Si nono, si rowArgs.valore no est nullu insertat una riga de datos, verifichende
	-- si sa testada esistit o nono
	elseif rowArgs.valore then
		local row = root:tag('tr')
		local dataCell
		if rowArgs.numene then
			row
				:tag('th')
					:cssText(args.IstileNumene or '')
					:wikitext(rowArgs.numene)
			dataCell = row:tag('td')
		else
			dataCell = row:tag('td')
				:addClass('sinòticu_testu_tzentrale')
				:attr('colspan', 2)
		end
		dataCell
			:addClass(rowArgs.classe or '')
			:cssText(args.IstileValore or '')
			:wikitext(checkList(rowArgs.valore))
	end
end

local function renderTitle()
	local suptitle = mw.html.create('')
	if args.SubraTitulu then
		suptitle
			:tag('span')
				:addClass('sinòticu_sutatìtulu')
				:cssText(args.IstileSubraTitulu or '')
				:wikitext(args.SubraTitulu)
				:done()
			:tag('br'):done()
	end
	local subtitle = mw.html.create('')
	if args.SutaTitulu then
		subtitle
			:tag('br'):done()
			:tag('span')
				:addClass('sinòticu_sutatìtulu')
				:cssText(args.IstileSutaTitulu or '')
				:wikitext(args.SutaTitulu)
	end
	if args.TituluEst then
		root
			:tag('caption')
			:addClass('sinòticu_testada')
			:cssText(args.IstileTituluEst or '')
			:node(suptitle)
			:wikitext(args.TituluEst)
			:node(subtitle)
	elseif args.TituluInt then
		root
			:tag('tr')
			:addClass('sinòticu_testada')
			:tag('th')
				:attr('colspan', '2')
				:node(suptitle)
				:cssText(args.IstileTituluInt or '')
				:wikitext(args.TituluInt)
				:node(subtitle)
	end
end

local function renderImage()
	if not args.Immagine then return end
	local cell_immagine = mw.html.create('td')
	cell_immagine
		:addClass('sinòticu_testu_tzentrale ' .. (args.ClasseImmagine or ''))
		:attr('colspan', '2')
		:cssText(args.IstileImmagine or '')
		:wikitext(args.Immagine)
	 if args.Didascalia then
		cell_immagine
			:tag('br', {selfClosing = true})
				:done()
			:tag('span')
			:cssText(args.IstileDidascalia or '')
			:wikitext(args.Didascalia)
	end
	root:tag('tr'):node(cell_immagine)
end


local function renderRows()
	local rownums = getArgNums('Valore', 'GrupuOptzionale',  'Grupu')
	for k, num in ipairs(rownums) do
		local skip = false
		if args['GrupuOptzionale' .. num] ~= nil then
			skip = true
			for j = k+1, #rownums do
				if args['Grupu' .. rownums[j]] ~= nil or args['GrupuOptzionale' .. rownums[j]]~=nil then break end
				if args['Valore' .. rownums[j]] ~= nil then
					skip = false
					break
				end
			end
		end
		if not skip and args['GrupuOptzionale' .. num] ~= '$fine' then
			addRow({
				grupu = args['GrupuOptzionale' .. num] or args['Grupu' .. num],
				numene = args['Numene' .. num],
				valore = args['Valore' .. num],
				classe = args['Classe' .. num],
				istile = args['GrupuIstile' .. num]
			})
		end
	end
end

local function renderLastRow()
	if not args.Urtima then return end
	root
		:tag('tr')
			:tag('td')
				:attr('colspan', '2')
				:addClass('sinòticu_pee')
				:cssText(args.IstileUrtima or '')
				:wikitext(args.Urtima)
				:newline()
end

local function renderNavBar()
	if not args.NumeneTemplate then return end
	root
		:tag('tr')
			:tag('td')
				:addClass('sinòticu_pee2 noprint nomobile metadata')
				:attr('colspan', '2')
				:wikitext(mw.getCurrentFrame():expandTemplate({
					title = 'Ligàmene sinòticu',
					args = args.LinkWikidata and
							{ args.NumeneTemplate } or
							{ args.NumeneTemplate, nowd = 1 }
				}))
end

local function _infobox()
	-- Creat s'àrbore chi rapresentat sa tabella de su sinòticu e frunit su markup
	if args.CreaTable == 'no' then
		root = mw.html.create('')
	else
		root = mw.html.create('table')
		root
			:addClass('sinòticu')
			:cssText(args.IstileTabella or '')
			:attr('summary', args.Summary or 'Tabella sinòtica chi resumet sos datos printzipales de su sugetu')
	end
	renderTitle()
	renderImage()
	renderRows()
	renderLastRow()
	renderNavBar()
	return tostring(root)
end

local function preprocessSingleArg(argName)
	-- Si s'argumentu esistet e no est un'istringat bòida l'agiunghet a sa tabella de sos argumentos
	-- Argumentos uguales a un'istringa bòida sunt tratados comente a nullos sighende su cumportamentu
	-- antepostu de su template {{Infobox}}
	if origArgs[argName] and origArgs[argName] ~= '' then
		args[argName] = origArgs[argName]
	end
end

local function preprocessArgs(prefixTable, step)
	-- Assignat sos paràmetros cun sos datos prefissos a sa tabella args, in òrdine e segundu lotos de
	-- mannària ispetzificada. Sa prefixTable diat dèpere èssere un'array chi cuntenet tabellas, cada una
	-- de sas cales cun duos campos possìbiles, un'istringa "prefissu" e una tabella de "dipendèntzias". Sa
	-- funzione esàminat totu sos paràmetros chi cuntenet s'istringa prefissu, ma esàminat sos de sa
	-- tabella dipendentes petzi si su prefissu dae su cale dipendent est presente e non nullu.
	if type(prefixTable) ~= 'table' then
		error("Valore non tabella agatadu in sa tabella prefissos", 2)
	end
	if type(step) ~= 'number' then
		error("Passu de casta non vàlida", 2)
	end

	-- Otenet sos argumentos chene unu sufissu numèricu e còmpidat pro input isballiados.
	for i,v in ipairs(prefixTable) do
		if type(v) ~= 'table' or type(v.prefix) ~= "string" or (v.depend and type(v.depend) ~= 'table') then
			error('Valores non vàlidos agatados pro sa tabella de prefissos preprocessArgs', 2)
		end
		preprocessSingleArg(v.prefix)
		-- Esàminat sos paràmetros dipendentes petzi si su paràmetru prefissu est presente e non nullu.
		if args[v.prefix] and v.depend then
			for j, dependValue in ipairs(v.depend) do
				if type(dependValue) ~= 'string' then
					error('Paràmetru "dipendente"  non vàlidu agatadu in preprocessArgs')
				end
				preprocessSingleArg(dependValue)
			end
		end
	end
	if step == 0 then return end
	-- Estraet sos argumentos cun unu sufissu numèricu
	local a = 1 -- Counter variable.
	local moreArgumentsExist = true
	while moreArgumentsExist == true do
		moreArgumentsExist = false
		for i = a, a + step - 1 do
			for j,v in ipairs(prefixTable) do
				local prefixArgName = v.prefix .. tostring(i)
				if origArgs[prefixArgName] then
					moreArgumentsExist = true -- Annanghet una colada si unu paràmetru est istadu agatadu, fintzas si est nullu.
					preprocessSingleArg(prefixArgName)
				end
				-- Protzessat sa tàula de sos dipendentes si su paràmetru dae su cale dipendent esistit e no est nullu
				if v.depend and args[prefixArgName] then
					for j,dependValue in ipairs(v.depend) do
						local dependArgName = dependValue .. tostring(i)
						preprocessSingleArg(dependArgName)
					end
				end
			end
		end
		a = a + step
	end
end

function p.infobox(frame)
	-- Se chiamata mediante  #invoke, usa gli argomenti passati al template invocante.
	-- Altrimenti a scopo di test assume che gli argomenti siano passati direttamente
	if frame == mw.getCurrentFrame() then
		origArgs = frame:getParent().args
	else
		origArgs = frame.args
	end

	-- Sas funtziones Parser cunsìderant s'istringat bòida comente a farsa, duncas pro preservare su
	-- cumportamentu de {{infobox}} totu sos argumentos bòidos non benint ammentados
	-- in sa tabella globale args, in manera de èssere cunsiderados farsos
	-- Ammenta·ti: args est una variàbile globale pro su mòdulu decrarada a su cumintzu suo
	-- Iscandit sos paràmetros in su matessi òrdine in su cale lu faghiat su {{infobox}} betzu
	-- in manera chi istrutziones ref eventuales ant a cumpàrrere in positzione e òrdine currigidu. Paràmetros chi dipendent dae
	-- àteros paràmetros sunt protzessados solu si su paràmetru est presente, in manera de evitare
	-- sa cumparta de riferimentos pantasma in logos no isetados.
	preprocessSingleArg('IstileTabella')
	preprocessArgs({
		{prefix='SubraTitulu', depend={'IstileSubraTitulu'}}
		}, 0)
	preprocessArgs({
		{prefix='TituluEst', depend={'IstileTituluEst'}}
		 }, 0)
	preprocessArgs({
		{prefix='TituluInt', depend={'IstileTituluInt'}}
		}, 0)
	preprocessArgs({
		{prefix='SutaTitulu', depend={'IstileSutaTitulu'}}
		}, 0)
	preprocessArgs({
		{prefix='Immagine', depend={'ClasseImmàagine', 'IstileImmagine',
						'Didascalia', 'IstileDidascalia'}}
		}, 0)
	preprocessSingleArg('IstileGrupu')
	preprocessSingleArg('IstileNumene')
	preprocessSingleArg('IstileValore')
	preprocessArgs({
		{prefix = 'Grupu', depend={'GrupuIstile'}},
		{prefix = 'GrupuOptzionale', depend={'GrupuIstile'}},
		{prefix = 'Valore', depend={'Numene', 'Classe'}},
	}, 50)
	preprocessSingleArg('Urtima')
	preprocessSingleArg('IstileUrtima')
	preprocessSingleArg('NumeneTemplate')
	preprocessSingleArg('LigàmeneWikidata')
	preprocessSingleArg('CreaTable')
	preprocessSingleArg('Summary')
	return _infobox()
end

return p