-- Modulo sperimentale per costruire markup HTML complesso per infobox, navbox e simili usando
-- un'interfaccia fluente

local HtmlBuilder = {} -- Per l'esportazione delle funzioni del modulo

local metatable = {} -- contenitore per le funzioni degli oggetti HtmlBuilder

metatable.__index = function(t, key)
    -- ritorna t[key] se esiste, altrimenti controlla metatable[key], se
    -- è una funzione ritorna il risultato della chiamata, altrimenti ritorna il suo valore
    local ret = rawget(t, key)
    if ret then
        return ret
    end

    ret = metatable[key]
    if type(ret) == 'function' then
        return function(...)
            return ret(t, ...)
        end
    else
        return ret
    end
end

metatable.__tostring = function(t)
    -- Collassa i componenti in una stringa e la restituisce
    local ret = {}
    t._build(ret)
    return table.concat(ret, '')
end

metatable._build = function(t, ret)
    -- Costruisce una lista contentente gli elementi che compongono l'oggetto html
    -- Se tagName non è nullo inserisce il tag
    if t.tagName then
        table.insert(ret, '<' .. t.tagName)
        -- inserisce gli attributi del tag
        for i, attr in ipairs(t.attributes) do
            table.insert(ret, ' ' .. attr.name .. '="' .. attr.val .. '"')
        end
        -- inserisco gli stili
        if #t.styles > 0 then
            table.insert(ret, ' style="')
            for i, prop in ipairs(t.styles) do
                if type(prop) == 'string' then -- added with cssText()
                    table.insert(ret, prop .. ';')
                else -- added with css()
                    table.insert(ret, prop.name .. ':' .. prop.val .. ';')
                end
            end
            table.insert(ret, '"')
        end
        if t.selfClosing then -- chiudo il tag
            table.insert(ret, ' />')
        else
            table.insert(ret, '>') 
        end
    end
    -- aggiunge i nodi figli
    for i, node in ipairs(t.nodes) do
        if node then
            if type(node) == 'table' then
                node._build(ret)
            else
                table.insert(ret, tostring(node))
            end
        end
    end
    if t.tagName and not t.unclosed then
        table.insert(ret, '</' .. t.tagName .. '>')
    end
end

metatable.node = function(t, builder)
    -- add a node
    if builder then
        table.insert(t.nodes, builder)
    end
    return t
end

metatable.wikitext = function(t, ...)
--Aggiunge del markup al nodo. Può includere testo semplice, markup wiki o HTML.
    local vals = {...}
    for i = 1, #vals do
        if vals[i] then
            table.insert(t.nodes, vals[i])
        end
    end
    return t
end

metatable.newline = function(t)
--Aggiunge un carattere di ritorno a capo al nodo.
    table.insert(t.nodes, '\n')
    return t
end

metatable.tag = function(t, tagName, args)
--Appende un nuovo nodo al builder e ritorna un'istanza di HtmlBuilder rappresentante il nuovo nodo.
    args = args or {}
    args.parent = t
    local builder = HtmlBuilder.create(tagName, args)
    table.insert(t.nodes, builder)
    return builder
end

function getAttr(t, name)
    for i, attr in ipairs(t.attributes) do
        if attr.name == name then
            return attr
        end
    end
end

metatable.attr = function(t, name, val)
    -- Imposta un attributo HTML del nodo.
    -- Se viene settato l'attributo "style" rimpiazza tutti gli stili
    -- aggiunti con css() e cssText()
    if name == 'style' then
        t.styles = {val}
        return t
    end
    local attr = getAttr(t, name)
    if attr then
        attr.val = val
    else
        table.insert(t.attributes, {name = name, val = val})
    end
    return t
end

metatable.addClass = function(t, class)
--Aggiunge un nome di classe all'attibuto class del nodo.
-- Ogni nome di classe viene automaticamente delimitato da spazi.
    if class then
        local attr = getAttr(t, 'class')
        if attr then
            attr.val = attr.val .. ' ' .. class
        else
            t.attr('class', class)
        end
    end
    return t
end

metatable.css = function(t, name, val)
    --Imposta una proprietà CSS da aggiungere all'attributo style
    if type(val) == 'string' or type(val) == 'number' then
        for i, prop in ipairs(t.styles) do
            if prop.name == name then
                prop.val = val
                return t
            end
        end
        table.insert(t.styles, {name = name, val = val})
    end
    return t
end

metatable.cssText = function(t, css)
    if css then
        table.insert(t.styles, css)
    end
    return t
end

metatable.done = function(t)
-- Restistuisce il nodo padre del nodo corrente, se nil resistuisce il nodo stesso
    return t.parent or t
end

metatable.allDone = function(t)
-- Restituisce la radice dell'albero
    while t.parent do
        t = t.parent
    end
    return t
end

function HtmlBuilder.create(tagName, args)
    args = args or {}
    local builder = {}
    setmetatable(builder, metatable)
    builder.nodes = {}
    builder.attributes = {}
    builder.styles = {}
    builder.tagName = tagName
    builder.parent = args.parent
    builder.unclosed = args.selfClosing or args.unclosed or false
    builder.selfClosing = args.selfClosing or false
    return builder
end

return HtmlBuilder

-- Versioni
-- 25/04/2013 importazione della revisione 547011303 del 26/03/2013 di en:Module:HtmlBuilder
-- 30/04/2013 aggiunta opzione per tag che si autochiude, come per esempio <br />