Modulo in Lua per gestire le funzioni di {{Infobox}}



-- Modulo per implementare le funzionalità di infobox
-- Il modulo è stato importato da:
-- https://it.wikipedia.org/w/index.php?title=Modulo:Infobox&oldid=74560768
local p = {} -- per l'esportazione delle funzioni del modulo

--local HtmlBuilder = require('Module:HtmlBuilder') -- richiesto per la costruzione del markup html

local args = {}-- variabile che contiene gli argomenti passati al template
local origArgs
local root -- radice del markup html
local dump = {}

local function getArgNums(...)
    -- Restituisce una lista che contiene il suffisso numerico  di tutti gli argomenti
    -- che iniziano con il prefisso "prefix"
    -- Per esempio se nella lista argomenti sono valorizzati "Valore1, Valore2 e Valore4"
    -- retistuirà la 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)
    -- Aggiunge una riga alla tabella
    -- Se rowArgs.gruppo non è nullo la considera come una riga di testata di gruppo
    -- e ignora eventuali valorizzazioni di rowArgs.valore
    if rowArgs.gruppo then
        root
            :tag('tr')
                :addClass("sinottico_divisione")
                :tag('th')
                    :attr('colspan', 2)
                    :cssText(args.StileGruppo or '')
                    :wikitext(rowArgs.gruppo)
    -- Altrimenti se rowArgs.valore non è nullo inserisce una riga dati, verificando
    -- se esiste o meno la testata
    elseif rowArgs.valore then
        local row = root:tag('tr')
        local dataCell
        if rowArgs.nome then
            row
                :tag('th')
                    :cssText(args.StileNome or '')
                    :wikitext(rowArgs.nome)
            dataCell = row:tag('td')
        else
            dataCell = row:tag('td')
                :attr('colspan', 2)
                :css('text-align', 'center')
        end
        dataCell
            :addClass(rowArgs.classe or '')
            :cssText(args.StileValore or '')
            :wikitext(rowArgs.valore)
    end
end

local function renderTitle()
    if args.TitoloEst then
        root
            :tag('caption')
            :addClass('sinottico_testata')
            :css("font-weight", "bold")
            :cssText(args.StileTitoloEst or '')
            :wikitext(args.TitoloEst)
    elseif args.TitoloInt then
        root
            :tag('tr')
            :addClass('sinottico_testata')
            :tag('th')
                :attr('colspan', '2')
                :cssText(args.StileTitoloInt or '')
                :wikitext(args.TitoloInt)
    end
end

local function renderImage()
    if not args.Immagine then return end
    local cell_immagine = mw.html.create('td')
    cell_immagine
        :addClass(args.ClasseImmagine or '')
        :attr('colspan', '2')
        :css('text-align', 'center')
        :cssText(args.StileImmagine or '')
        :wikitext(args.Immagine)
     if args.Didascalia then
        cell_immagine
            :tag('br', {selfClosing = true})
                :done()
            :tag('span')
            :cssText(args.StileDidascalia or '')
            :wikitext(args.Didascalia)
    end
    root:tag('tr'):node(cell_immagine)
end


local function renderRows()
    local rownums = getArgNums('Valore', 'GruppoOpzionale',  'Gruppo')
    for k, num in ipairs(rownums) do
        local skip = false
        if args['GruppoOpzionale' .. num] ~= nil then
            skip = true
            for j = k+1, #rownums do
                if args['Gruppo' .. rownums[j]] ~= nil or args['GruppoOpzionale' .. rownums[j]]~=nil then break end
                if args['Valore' .. rownums[j]] ~= nil then
                    skip = false
                    break
                end
            end
        end
        if not skip and args['GruppoOpzionale' .. num] ~= '$fine' then
            addRow({
                gruppo = args['GruppoOpzionale' .. num] or args['Gruppo' .. num],
                nome = args['Nome' .. num],
                valore = args['Valore' .. num],
                classe = args['Classe' .. num]
            })
        end
    end
end

local function renderLastRow()
    if not args.Ultima then return end
    root
        :tag('tr')
            :tag('td')
                :attr('colspan', '2')
                :addClass('sinottico_piede')
                :cssText(args.StileUltima or '')
                :wikitext(args.Ultima)
                :newline()
end

local function renderNavBar()
    if not args.NomeTemplate then return end
    root
        :tag('tr')
            :tag('td')
                :attr('colspan', '2')
                :css('text-align', 'right')
                :wikitext(mw.getCurrentFrame():expandTemplate({
                    title = 'Tnavbar',
                    args = { args.NomeTemplate }
                }))
end

local function _infobox()
    -- Crea l'albero html che rappresenta la tabella del sinottico e restituisce il markup
    if args.InserisciTestata == 'no' then
        root = mw.html.create('')
    else
        root = mw.html.create('table')
        root
            :addClass('sinottico')
            :cssText(args.StileTabella or '')
            :attr('summary', args.Summary or 'Tabella sinottica che riassume i principali dati del soggetto')
        renderTitle()
        renderImage()
    end
    renderRows()
    if args.InserisciCoda ~= 'no' then
        renderLastRow()
        renderNavBar()
    end
    return tostring(root)
end

local function preprocessSingleArg(argName)
    -- Se l'argomento esiste e non è una stringa vuota lo aggiunge alla tabella degli argomenti
    -- Argomenti uguali a stringa vuota sono trattati come nulli come da comportamento
    -- precedente del template {{Infobox}}
    if origArgs[argName] and origArgs[argName] ~= '' then
        args[argName] = origArgs[argName]
    end
end

local function preprocessArgs(prefixTable, step)
    -- Assegna i parametri con i dati prefissi alla tabella args, in ordine e secondo lotti di
    -- dimensione specificata. La prefixTable dovrebbe essere un  array contenente tabelle, ognuna
    -- delle quali con due possibili campi, una stringa "prefisso" e una tabella di "dipendenze". La
    -- funsione esamina tutti i parametri contenenti la stringa prefisso, ma esamina quelli della
    -- tabella dipendenti solo se il prefisso da cui dipendono è presente e non nullo.
    if type(prefixTable) ~= 'table' then
        error("Valore non tabella trovato nella tabella prefissi", 2)
    end
    if type(step) ~= 'number' then
        error("Passo di tipo non valido", 2)
    end

    -- Ottiene gli argmenti senza un suffisso numerico e controlla per input errati.
    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('Valori non validi riscontrati per la tabella di prefissi preprocessArgs', 2)
        end
        preprocessSingleArg(v.prefix)
        -- Esamina i parametri dipendenti solo se il parametro prefisso è presente e non nullo.
        if args[v.prefix] and v.depend then
            for j, dependValue in ipairs(v.depend) do
                if type(dependValue) ~= 'string' then
                    error('Parametro "dipendente"  non valido riscontrato in preprocessArgs')
                end
                preprocessSingleArg(dependValue)
            end
        end
    end
    if step == 0 then return end
    -- Estrae gli argomenti con un suffisso numerico
    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 -- Aggiunge una passata se un parametro è stato trovato, anche se nullo.
                    preprocessSingleArg(prefixArgName)
                end
                -- Processa la tavola dei dipendenti  se il parametro da cui dipendono esiste e non è nullo
                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

    -- Le funzioni Parser considerano la stringa vuota come falsa, così per preservare il
    -- comportamento di {{infobox}} tutti gli argomenti vuoti non vengono memorizzati
    -- nella tabella globale args, così da essere considerati falsi
    -- Nota: args è una variabile globale per il modulo dichiarata al suo inizio
    -- Scandisce i parametri nello stesso ordine in cui lo faceva il vecchio {{infobox}}
    -- così che evemntuali istruzioni ref compariranno in posizione e ordine corretto. Parametri che dipendono da
    -- altri parametri sono processati solo se il parametro è presente, così da evitare
    -- la comparsa di riferimenti fantasma in posti inattesi.
    preprocessSingleArg('StileTabella')
    preprocessArgs({
        {prefix='TitoloEst', depend={'StileTitoloEst'}}
         }, 0)
    preprocessArgs({
        {prefix='TitoloInt', depend={'StileTitoloInt'}}
        }, 0)
    preprocessArgs({
        {prefix='Immagine', depend={'ClasseImmagine', 'StileImmagine',
                        'Didascalia', 'StileDidascalia'}}
        }, 0)
    preprocessSingleArg('StileGruppo')
    preprocessSingleArg('StileNome')
    preprocessSingleArg('StileValore')
    preprocessArgs({
        {prefix = 'Gruppo'},
        {prefix = 'GruppoOpzionale'},
        {prefix = 'Valore', depend={'Nome', 'Classe'}},
    }, 50)
    preprocessSingleArg('Ultima')
    preprocessSingleArg('StileUltima')
    preprocessSingleArg('NomeTemplate')
    preprocessSingleArg('InserisciTestata')
    preprocessSingleArg('InserisciCoda')
    preprocessSingleArg('Summary')
    return _infobox()
end

return p