Prijeđi na sadržaj

Modul:Pregled serije

Izvor: Wikipedija
-- Ovaj modul omogućava funkcioniranje predloška {{Pregled serije}} 

-- 1. Local functions (~12)
-- 2. p.glavno (~398)
-- 3. Stvaranje tablice (~463)
---- Zaglavlje (~480)
---- Redovi za sezone s više dijelova (multi part) (~559)
---- Redovi za sezone s jednim dijelom (single part) (~908)   

local p = {}
------ Funckcija koja omogućava parametar sakrijfinale 
local function getSakrijFinale(params)
    local val = params.sakrijfinale
    val = val and mw.ustring.lower(val)
    if val == "prvo" or val == "da" then
        return "prvo"
    elseif val == "drugo" then
        return "drugo"
    elseif val == "sve" then
        return "sve"
    end
    return nil
end

------ Funkcije za izračun raspona redaka (rowspan) u ćelijama zaglavlja
local function getZaglavljeRowspan(params)
    local sakrij = getSakrijFinale(params)
    if sakrij == "sve" then
        return 1
    end
    return tonumber(params.zaglavljerowspans) or 2
end

local function getPrvoPrikazivanjeRowspan(params)
    local sakrij = getSakrijFinale(params)
    if sakrij == "prvo" or sakrij == "da" then
        return 2
    end
    return 1
end

local function getPrikazivanjeHRRowspan(params)
    local sakrij = getSakrijFinale(params)
    if sakrij == "drugo" then
        return 2
    end
    return 1
end

------ Funckija koja utvrđuje jesu li definirane boje (za obojene ćelije)
local function hasBoja(params)
    for k, v in pairs(params) do
        if k:match("^boja%d+S?$") and v ~= "" then
            return true
        end
    end
    return false
end

------ Funkcija koja utvrđuje je li definirana serija (za otvaranje stupca 'Serija')
local function hasSerija(params)
    for k, v in pairs(params) do
        if k:match("^serija%d+S?[A-Z]?$") and v ~= "" then
            return true
        end
    end
    return false
end

------ Funkcija koaj utvrđuje je li definirana barem jedan broj epizoda 
local function hasEpizode(params)
    for k, v in pairs(params) do
        if k:match("^epizode%d+S?$") and v ~= "" then
            return true
        end
    end
    return false
end

------ Funkcija koje utvrđuje jesu li epizode podijeljene na jedan dio (single-part) ili na više dijelova (multi-part)
local function hasEpizodeParts(params)
    for k, v in pairs(params) do
        if k:match("^epizode%d+S?[A-Z]$") and v ~= "" then
            return true
        end
    end
    return false
end

------ Funkcija koja utvrđuje jesu li definirane premijeraHR ili finaleHR
local function hasCroatianAirings(params)
    -- Check mrežaHR1 and mrežaHR0S
    if (params["mrežaHR1"] and params["mrežaHR1"] ~= "") or
       (params["mrežaHR0S"] and params["mrežaHR0S"] ~= "") then
        return true
    end

    -- Check mrežaHR1A-Z
    for i = string.byte("A"), string.byte("Z") do
        local key = "mrežaHR1" .. string.char(i)
        if params[key] and params[key] ~= "" then
            return true
        end
    end

    -- Existing checks for premijeraHR and finaleHR
    for k, v in pairs(params) do
        if (k:match("^premijeraHR%d+S?$") or
            k:match("^finaleHR%d+S?$") or
            k:match("^premijeraHR%d+S?[A-Z]$") or
            k:match("^finaleHR%d+S?[A-Z]$")) and v ~= "" then
            return true
        end
    end

    return false
end

local function getMaxIndex(params)
    local maxIndex = 0
    for k, v in pairs(params) do
        local idx = k:match("^%a+(%d+)[S]?[A-Z]?$")
        if idx then
            idx = tonumber(idx)
            if idx and idx > maxIndex then
                maxIndex = idx
            end
        end
    end
    return maxIndex
end

------ Funkcija koja dohvaća slova (1A, 1B...) u sezonama podijeljenim na dijelove 
local function getPartLetters(params, index)
    local letters = {}
    for i = string.byte("A"), string.byte("Z") do
        local letter = string.char(i)
        if params["premijera" .. index .. letter] or params["finale" .. index .. letter] then
            table.insert(letters, letter)
        else
            break
        end
    end
    return letters
end

------ Funkcije koje utvrđuju jesu li definirane mreža i mrežaHR
local function hasMreza(params)
    if (params["mreža1"] and params["mreža1"] ~= "") or
       (params["mreža0S"] and params["mreža0S"] ~= "") then
        return true
    end
    for i = string.byte("A"), string.byte("Z") do
        local key = "mreža1" .. string.char(i)
        if params[key] and params[key] ~= "" then
            return true
        end
    end
    return false
end

local function hasMrezaHR(params)
    if (params["mrežaHR1"] and params["mrežaHR1"] ~= "") or
       (params["mrežaHR0S"] and params["mrežaHR0S"] ~= "") then
        return true
    end
    for i = string.byte("A"), string.byte("Z") do
        local key = "mrežaHR1" .. string.char(i)
        if params[key] and params[key] ~= "" then
            return true
        end
    end
    return false
end

------ Funkcija za razlikovanje specijala od regularnih sezona 
local function isSpecial(index)
    return tostring(index):match("S$")
end

------ Funkcija za izračun broja redaka kroz koje se proteže mreža 
local function calculateNetworkRowspans(params, orderedSeasons, prefix)
    local spans = {}
    local keys = {}

    for _, index in ipairs(orderedSeasons) do
        local partLetters = getPartLetters(params, index)
        if #partLetters > 0 then
            for _, letter in ipairs(partLetters) do
                table.insert(keys, tostring(index) .. letter)
            end
        else
            table.insert(keys, tostring(index))
        end
    end

    local currentValue    = nil
    local currentStartKey = nil
    local spanCount       = 0

    for i, key in ipairs(keys) do
        local seasonNum = key:match("^(%d+S?)")
        local value     = params[prefix .. key] or params[prefix .. seasonNum]

        -- Check for odjeljak break
        if params["odjeljak" .. seasonNum] and params["odjeljak" .. seasonNum] ~= "" then
            if currentValue and currentStartKey then
                spans[currentStartKey] = { value = currentValue, span = spanCount }
            end
            currentValue    = nil
            currentStartKey = nil
            spanCount       = 0
        end

        if not value or value == "" then
            value = currentValue
        end

        if value and value ~= "" then
            if currentValue == nil then
                currentValue    = value
                currentStartKey = key
                spanCount       = 1
            elseif value == currentValue then
                spanCount = spanCount + 1
            else
                spans[currentStartKey] = { value = currentValue, span = spanCount }
                currentValue    = value
                currentStartKey = key
                spanCount       = 1
            end
        elseif currentValue then
            spanCount = spanCount + 1
        end
    end

    if currentValue and currentStartKey then
        spans[currentStartKey] = { value = currentValue, span = spanCount }
    end

    return spans
end

------ Funkcija za izračun redaka kroz koje se proteže serija
local function calculateSerijaRowspans(params, orderedSeasons)
    local spans = {}
    local keys  = {}

    for _, index in ipairs(orderedSeasons) do
        local partLetters = getPartLetters(params, index)
        if #partLetters > 0 then
            for _, letter in ipairs(partLetters) do
                table.insert(keys, tostring(index) .. letter)
            end
        else
            table.insert(keys, tostring(index))
        end
    end

    local currentKey = nil
    local spanCount  = 0

    for _, key in ipairs(keys) do
        local seasonNum = key:match("^(%d+S?)")
        local value = params["serija" .. key] or params["serija" .. seasonNum]

        -- Check for odjeljak break
        if params["odjeljak" .. seasonNum] and params["odjeljak" .. seasonNum] ~= "" then
            if currentKey then
                spans[currentKey] = spanCount
            end
            currentKey = nil
            spanCount  = 0
        end

        if value and value ~= "" then
            if currentKey then
                spans[currentKey] = spanCount
            end
            currentKey = key
            spanCount  = 1
        elseif currentKey then
            spanCount = spanCount + 1
        end
    end

    if currentKey then
        spans[currentKey] = spanCount
    end

    return spans
end

------ Funkcija koja omogućuje dodatno i info stupce 
local function getDodatnoHeaders(params)
    local headers   = {}
    local seenKeys  = {}

    for i = string.byte("A"), string.byte("Z") do
        local key = "dodatno" .. string.char(i)
        if params[key] and params[key] ~= "" then
            table.insert(headers, { key = string.char(i), label = params[key] })
            seenKeys[key] = true
        end
    end

    for k, v in pairs(params) do
        local match = k:match("^dodatno([A-Z])%d+")
        if match and not seenKeys["dodatno" .. match] then
            table.insert(headers, { key = match, label = "Dodatno " .. match })
            seenKeys["dodatno" .. match] = true
        end
    end

    return headers
end

local function getInfoHeaders(params)
    local headers   = {}
    local seenKeys  = {}

    -- First: explicitly defined headers
    for i = string.byte("A"), string.byte("Z") do
        local key = "info" .. string.char(i)
        if params[key] and params[key] ~= "" then
            table.insert(headers, { key = string.char(i), label = params[key] })
            seenKeys[key] = true
        end
    end

    -- Second: detect implicit headers from row data
    for k, v in pairs(params) do
        local match = k:match("^info([A-Z])%d+")
        if match and not seenKeys["info" .. match] then
            table.insert(headers, { key = match, label = "Info " .. match })
            seenKeys["info" .. match] = true
        end
    end

    return headers
end
------ Generic rowspan extractor for any prefix (e.g., "premijera", "premijeraHR")
local function getRowspans(params, prefix)
    local spans = {}
    for k, v in pairs(params) do
        local index = k:match("^" .. prefix .. "(%d+S?)row$")
        if index and v ~= "" then
            spans[index] = tonumber(v)
        end
    end
    return spans
end

------ Generic skip set builder for any rowspan table
local function getSkipSet(rowspans)
    local skipSet = {}
    for startIndex, span in pairs(rowspans) do
        local base   = tonumber(startIndex:match("^%d+"))
        local suffix = startIndex:match("S?$")
        for i = 1, span - 1 do
            local nextIndex = tostring(base + i) .. suffix
            skipSet[nextIndex] = true
        end
    end
    return skipSet
end

------ Omogućava korištenje predložaka (TBA, N/D i N/A) u ćelijama 
local function pipesearch(input)
    input = input or ''
    local pipePos = string.find(input, "|", 1, true)
    if not pipePos then
        return false
    end

    local searchPos = 1
    while true do
        local linkStart = string.find(input, "%[%[", searchPos)
        if not linkStart then break

        end
        local linkEnd = string.find(input, "%]%]", linkStart)
        if not linkEnd then break

        end

        if pipePos > linkStart and pipePos < linkEnd then
            return false 
        end

        searchPos = linkEnd + 1
    end

    return true 
end

------ P.MAIN
function p.glavno(frame)
    local args                     = frame:getParent().args
    local zaglavlje               = args["zaglavlje"]
    local sakrijFinale            = getSakrijFinale(args)
    local zaglavljeRowspan        = getZaglavljeRowspan(args)
    local prikazivanjeHRRowspan   = getPrikazivanjeHRRowspan(args)
    local prvoPrikazivanjeRowspan = getPrvoPrikazivanjeRowspan(args)
    local hideSezona              = args.sezona == "ne" and hasSerija(args)
    local nowrap                  = args["nowrap"]
    local output                  = {}
    local bojaFlag                = hasBoja(args)
    local epizodeFlag             = hasEpizode(args)
    local epizodePartsFlag        = hasEpizodeParts(args)
    local croatiaFlag             = hasCroatianAirings(args)
    local sezonaT                 = args.sezonaT or "Sezona"
    local epizodeT                = args.epizodeT or "Epizode"
    local colspan                 = bojaFlag and 2 or 1
    local epizodeColspan          = epizodePartsFlag and 2 or 1
    local mrezaFlag               = hasMreza(args)
    local mrezaFlagHR             = hasMrezaHR(args)
    local sezonaRowspan           = zaglavljeRowspan
    local epizodeRowspan          = zaglavljeRowspan
    local seasonNumbers = {}
    for k, _ in pairs(args) do
        local num = k:match("^poveznica(%d+S?)$") or
                    k:match("^epizode(%d+S?)$") or
                    k:match("^premijera(%d+S?)$") or
                    k:match("^mreža(%d+S?)$") or
                    k:match("^mrežaHR(%d+S?)$")
        if num then
            seasonNumbers[num] = true
        end
    end

    ------ Sortiranje sezona i specijala 
    local function sortSeasons(seasonKeys)
        table.sort(seasonKeys, function(a, b)
            local na, sa = a:match("^(%d+)(S?)$")
            local nb, sb = b:match("^(%d+)(S?)$")
            na, nb = tonumber(na), tonumber(nb)
            if na == nb then
                return sa < sb  -- regular before special
            else
                return na < nb
            end
        end)
    end

    local orderedSeasons = {}
    for num in pairs(seasonNumbers) do
        table.insert(orderedSeasons, num)
    end
    sortSeasons(orderedSeasons)

    ------ Izračun redaka 
    local mrezaSpans            = calculateNetworkRowspans(args, orderedSeasons, "mreža")
    local mrezaSpansHR          = calculateNetworkRowspans(args, orderedSeasons, "mrežaHR")
    local dodatnoHeaders        = getDodatnoHeaders(args)
    local infoHeaders           = getInfoHeaders(args)
    local premijeraRowspans     = getRowspans(args, "premijera")
    local premijeraSkipSet      = getSkipSet(premijeraRowspans)
    local premijeraHRRowspans   = getRowspans(args, "premijeraHR")
    local premijeraHRSkipSet    = getSkipSet(premijeraHRRowspans)
    local serijaRowspans        = calculateSerijaRowspans(args, orderedSeasons)
    
    --------------- STVARANJE TABLICE ---------------
    --- NOWRAP za cijelu tablicu
    local tableStyle = 'text-align:center;'
    if nowrap == "yes" or nowrap == "da" then
        tableStyle = tableStyle .. ' white-space:nowrap;'
    end
        table.insert(output, '{| class="wikitable" style="' .. tableStyle .. '"')
        
    -- OPIS (caption)
        local opis = args["opis"]
        if opis and opis ~= "" then
        table.insert(output, '|+ ' .. opis)
        end

        ------ Zaglavna ćelija SERIJA
        local serijaFlag = hasSerija(args)
        local serijaT    = args.serijaT or "Serija"
        if serijaFlag then
            table.insert(output, string.format('! rowspan="%d" | %s', zaglavljeRowspan, serijaT))
        end

        ------ Zaglavna ćelija SEZONA
        if not hideSezona then
            table.insert(output, string.format('! colspan="%d" rowspan="%d" | %s', colspan, zaglavljeRowspan, sezonaT))
        end

        ------ Zaglavne ćelije DODATNO 
        for _, h in ipairs(dodatnoHeaders) do
            table.insert(output, string.format('! rowspan="%d" | %s', zaglavljeRowspan, h.label))
        end

        ------ Zaglavna ćelije EPIZODE
        if epizodeFlag or epizodePartsFlag then
            table.insert(output, string.format('! colspan="%d" rowspan="%d" | %s', epizodeColspan, zaglavljeRowspan, epizodeT))
        end
        ------ Zaglavna ćelija PRVO PRIKAZIVANJE
        local drzavaText       = args["država1"] or args["zagrada1"]
        local prikazivanjeLabel

        if sakrijFinale == "prvo" or sakrijFinale == "da" or sakrijFinale == "sve" then
            prikazivanjeLabel = "Prva objava" .. (drzavaText and drzavaText ~= "" and (" (" .. drzavaText .. ")") or "")
            table.insert(output, string.format('! rowspan="%d" colspan="%d" | %s', prvoPrikazivanjeRowspan, mrezaFlag and 3 or 2, prikazivanjeLabel))
        else
            prikazivanjeLabel = "Prvo prikazivanje" .. (drzavaText and drzavaText ~= "" and (" (" .. drzavaText .. ")") or "")
            table.insert(output, string.format('! colspan="%d" | %s', mrezaFlag and 3 or 2, prikazivanjeLabel))
        end

        ------ Zaglavna ćelija PRIKAZIVANJE U HRVATSKOJ
        if croatiaFlag then
            local drzava2       = args["država2"]
            local zagrada2      = args["zagrada2"]
            local prikazivanjeHR

            if sakrijFinale == "drugo" or sakrijFinale == "sve" then
                prikazivanjeHR = "Objava u " .. (drzava2 and drzava2 ~= "" and drzava2 or "Hrvatskoj")
                if zagrada2 and zagrada2 ~= "" then
                    prikazivanjeHR = prikazivanjeHR .. " (" .. zagrada2 .. ")"
                end
                table.insert(output, string.format('! rowspan="%d" colspan="%d" | %s', prikazivanjeHRRowspan, mrezaFlagHR and 3 or 2, prikazivanjeHR))
            else
                prikazivanjeHR = "Prikazivanje u " .. (drzava2 and drzava2 ~= "" and drzava2 or "Hrvatskoj")
                if zagrada2 and zagrada2 ~= "" then
                    prikazivanjeHR = prikazivanjeHR .. " (" .. zagrada2 .. ")"
                end
                table.insert(output, string.format('! colspan="%d" | %s', mrezaFlagHR and 3 or 2, prikazivanjeHR))
            end
        end

        ------ Zaglavne ćelije INFO 
        for _, h in ipairs(infoHeaders) do
            table.insert(output, string.format('! rowspan="%d" | %s', zaglavljeRowspan, h.label))
        end
        ----- Zaglavne ćelije PREMIJERA i FINALE
        if sakrijFinale ~= "sve" then
            table.insert(output, '|-')

            -- Premijera i Finale za Prvo prikazivanje 
            if sakrijFinale ~= "prvo" and sakrijFinale ~= "da" then
                table.insert(output, '! Premijera')
                table.insert(output, '! Finale')
            end
            if mrezaFlag and sakrijFinale ~= "prvo" and sakrijFinale ~= "da" and sakrijFinale ~= "sve" then
                table.insert(output, '! Mreža')
            end

            -- Premijera i Finale za Prikazivanje u Hrvatskoj 
            if croatiaFlag and sakrijFinale ~= "drugo" then
                table.insert(output, '! Premijera')
                table.insert(output, '! Finale')
            end
            if croatiaFlag and mrezaFlagHR and sakrijFinale ~= "drugo" and sakrijFinale ~= "da" and sakrijFinale ~= "sve" then
                table.insert(output, '! Mreža')
            end
        end
    
   --------------- REDOVI ZA SEZONE ---------------
   ------ REDOVI ZA PODIJELJENE SEZONE (MULTI PART) ------
    table.insert(output, '|-')
    for _, index in ipairs(orderedSeasons) do
    	
    --- ODJELJAK 
    local odjeljakKey = "odjeljak" .. index
    local odjeljakText = args[odjeljakKey]

    if odjeljakText and odjeljakText ~= "" then
        local backgroundColor = args["odjeljakboja" .. index] or "#ccccff"
        local textColor = frame:expandTemplate{
            title = "Jači kontrast boja",
            args  = { backgroundColor, "white", "black" }
        }

        table.insert(output, '|-')
        table.insert(output, string.format(
            '! colspan="50" style="background:%s; color:%s;" | %s',
            backgroundColor, textColor, odjeljakText
        ))
        table.insert(output, '|-')
    end
    
     -- CRTA
    local crtaKey = "crta" .. index
    if args[crtaKey] == "da" then
        table.insert(output, '|-')
        table.insert(output, '! colspan="50" style="background:#aaa; height:1px; padding:0;" |')
        table.insert(output, '|-')
    end


        local partLetters = getPartLetters(args, index)
        local partCount   = #partLetters

        if partCount > 0 then
            local rowspan = partCount
            for i = 1, partCount do
                local letter = partLetters[i]
                local row    = ""

                ------ SERIJA (MULTI-PART)
                local serijaKey   = tostring(index) .. letter
                local serijaValue = args["serija" .. serijaKey] or args["serija" .. index] or ""

                if serijaRowspans[serijaKey] then
                    row = row .. string.format('\n! rowspan="%d" style="font-weight:normal; font-style:italic;" | %s', serijaRowspans[serijaKey], serijaValue)
                elseif serijaValue ~= "" then
                    row = row .. string.format('\n! style="font-weight:normal; font-style:italic;" | %s', serijaValue)
                end

                ------ BOJA (MULTI-PART)
                if bojaFlag and not hideSezona and i == 1 then
                    local boja     = args["boja" .. index]
                    local bojaCell = ""
                    if boja and boja ~= "" then
                        bojaCell = string.format('| style="background:%s; width:1px;" rowspan="%d" |', boja, rowspan)
                    else
                        bojaCell = string.format('| rowspan="%d" |', rowspan)
                    end
                    row = row .. '\n' .. bojaCell
                end

                ------ SEZONA (MULTI-PART)
                if not hideSezona and i == 1 then
                    local link        = args["poveznica" .. index]
                    local linkText    = args["poveznicaT" .. index] or args["poveznica" .. index .. "T"]
                    local seasonLabel = linkText and linkText ~= "" and linkText or tostring(index):gsub("S$", "") .. (isSpecial(index) and "S" or "") .. "."
                    local styleAttr   = ""

                    if link and link ~= "" then
                        row = row .. string.format('\n! %srowspan="%d" | [[%s|%s]]',
                            (linkText and linkText ~= "" and 'style="font-weight:normal;" ' or ''),
                            rowspan, link, seasonLabel)
                    else
                        row = row .. string.format('\n! rowspan="%d" | %s', rowspan, seasonLabel)
                    end
                end

                ------ DODATNO (MULTI-PART)
                for _, h in ipairs(dodatnoHeaders) do
                    if i == 1 then
                        local value = args["dodatno" .. h.key .. index] or ""
                        if value == "" then
                            row = row .. string.format('\n| rowspan="%d" style="background:#ececec; color:#2C2C2C; text-align:center;" | n.p.', rowspan)
                        else
                            if not pipesearch(value) then
                                value = "| " .. value
                            end
                            row = row .. string.format('\n| rowspan="%d" %s', rowspan, value)
                        end
                    end
                end

                ------ EPIZODE (MULTI-PART)
                if i == 1 and epizodeFlag then
                    local epizode = args["epizode" .. index] or ""
                    if epizode == "sakrij" then
                        -- skip rendering this cell entirely
                    elseif epizode ~= "" then
                        row = row .. string.format('\n| rowspan="%d" | %s', rowspan, epizode)
                    else
                        row = row .. string.format('\n| rowspan="%d" style="background:#ececec; color:#2C2C2C; text-align:center;" | n.p.', rowspan)
                    end
                end

                ------ DIJELOVI EPIZODA / EPISODE PART (MULTI-PART)
                local epizode = args["epizode" .. index]
                local epPart  = args["epizode" .. index .. letter] or ""

                if epizode == "sakrij" and epizodePartsFlag then
                    if epPart == "" then
                        row = row .. '\n| colspan="2" style="background:#ececec; color:#2C2C2C; text-align:center;" | n.p.'
                    else
                        row = row .. '\n| colspan="2" | ' .. epPart
                    end
                else
                    if epPart == "" then
                        row = row .. '\n| style="background:#ececec; color:#2C2C2C; text-align:center;" | n.p.'
                    else
                        row = row .. '\n| ' .. epPart
                    end
                end

                ------ PREMIJERA I FINALE (MULTI-PART)
                local premijera = ""
                local finale    = ""
                local key       = index .. letter

                if not premijeraSkipSet[key] then
                    premijera = args["premijera" .. key] or ""
                    finale    = args["finale" .. key] or ""
                end

                local sakrijfinale = args["sakrijfinale"] or ""
                local premijerapipe = pipesearch(premijera)
                local finalepipe    = pipesearch(finale)

                local function renderCell(value, rowspan)
                    if value == "" then
                        return string.format('\n|%s style="background:#ececec; color:#2C2C2C; text-align:center;" | n.p.', rowspan and (' rowspan="' .. rowspan .. '"') or "")
                    end
                    if not pipesearch(value) then
                        value = "| " .. value
                    end
                    return string.format('\n|%s style="white-space:nowrap;" %s', rowspan and (' rowspan="' .. rowspan .. '"') or "", value)
                end
                if premijeraRowspans[key] then
                    if finale == "premijera"
                        or sakrijfinale == "da"
                        or sakrijfinale == "sve"
                        or sakrijfinale == "prvo"
                        or (isSpecial(index) and (not finale or finale == "")) then

                        local cellContent = premijera
                        if cellContent == "" then
                            row = row .. string.format('\n| colspan="2" rowspan="%d" style="background:#ececec; color:#2C2C2C; text-align:center;" | n.p.', premijeraRowspans[key])
                        else
                            if not pipesearch(cellContent) then
                                cellContent = "| " .. cellContent
                            end
                            row = row .. string.format('\n| colspan="2" rowspan="%d" style="white-space:nowrap;" %s', premijeraRowspans[key], cellContent)
                        end
                    else
                        row = row .. renderCell(premijera, premijeraRowspans[key])
                        row = row .. renderCell(finale)
                    end
                elseif not premijeraSkipSet[key] then
                    if finale == "premijera"
                        or sakrijfinale == "da"
                        or sakrijfinale == "sve"
                        or sakrijfinale == "prvo"
                        or (isSpecial(index) and (not finale or finale == "")) then

                        local cellContent = premijera
                        if cellContent == "" then
                            row = row .. '\n| colspan="2" style="background:#ececec; color:#2C2C2C; text-align:center;" | n.p.'
                        else
                            if not pipesearch(cellContent) then
                                cellContent = "| " .. cellContent
                            end
                            row = row .. '\n| colspan="2" style="white-space:nowrap;" ' .. cellContent
                        end
                    else
                        row = row .. renderCell(premijera)
                        row = row .. renderCell(finale)
                    end
                end
                ------ MREŽA (MULTI-PART)
                local key = tostring(index)
                if letter then
                    key = key .. letter
                end

                -- Check if mreža1, mreža1A-Z, or mreža0S is defined
                local mrezaTrigger = false
                if (args["mreža1"] and args["mreža1"] ~= "") or
                   (args["mreža0S"] and args["mreža0S"] ~= "") then
                    mrezaTrigger = true
                else
                    for i = string.byte("A"), string.byte("Z") do
                        local checkKey = "mreža1" .. string.char(i)
                        if args[checkKey] and args[checkKey] ~= "" then
                            mrezaTrigger = true
                            break
                        end
                    end
                end

                -- Only render mreža cell if trigger is true
                if mrezaTrigger then
                    if mrezaSpans[key] then
                        local value = mrezaSpans[key].value or ""
                        if value ~= "" then
                            if not pipesearch(value) then
                                value = "| " .. value
                            end
                            row = row .. string.format('\n| rowspan="%d" %s', mrezaSpans[key].span, value)
                        else
                            row = row .. string.format('\n| rowspan="%d" |', mrezaSpans[key].span)
                        end
                    elseif args["mreža" .. key] and args["mreža" .. key] ~= "" then
                        local value = args["mreža" .. key]
                        if not pipesearch(value) then
                            value = "| " .. value
                        end
                        row = row .. string.format('\n%s', value)
                    elseif args["mreža" .. key] == nil or args["mreža" .. key] == "" then
                        if i == 1 and args["mreža" .. index] and args["mreža" .. index] ~= "" then
                            local value = args["mreža" .. index]
                            if not pipesearch(value) then
                                value = "| " .. value
                            end
                            row = row .. string.format('\n| rowspan="%d" %s', partCount, value)
                        end
                    end
                end


                ------ PREMIJERAHR I FINALEHR / Croatian airings (MULTI-PART)
                if croatiaFlag then
                    local hrKey = index .. letter
                    if not premijeraHRSkipSet[hrKey] then
                        local premHR = args["premijeraHR" .. hrKey] or ""
                        local finHR  = args["finaleHR" .. hrKey] or ""

                        local sakrijfinale = args["sakrijfinale"] or ""

                        local premHRpipe = pipesearch(premHR)
                        local finHRpipe  = pipesearch(finHR)

                        local function renderHRCell(value, rowspan)
                            if value == "" then
                                return string.format('\n|%s style="background:#ececec; color:#2C2C2C; text-align:center;" | n.p.', rowspan and (' rowspan="' .. rowspan .. '"') or "")
                            end
                            if not pipesearch(value) then
                                value = "| " .. value
                            end
                            return string.format('\n|%s style="white-space:nowrap;" %s', rowspan and (' rowspan="' .. rowspan .. '"') or "", value)
                        end
                        if premijeraHRRowspans[hrKey] then
                            if finHR == "premijera"
                                or sakrijfinale == "drugo"
                                or sakrijfinale == "sve"
                                or (isSpecial(index) and (not finHR or finHR == "")) then

                                local cellContent = premHR
                                if cellContent == "" then
                                    row = row .. string.format('\n| colspan="2" rowspan="%d" style="background:#ececec; color:#2C2C2C; text-align:center;" | n.p.', premijeraHRRowspans[hrKey])
                                else
                                    if not pipesearch(cellContent) then
                                        cellContent = "| " .. cellContent
                                    end
                                    row = row .. string.format('\n| colspan="2" rowspan="%d" style="white-space:nowrap;" %s', premijeraHRRowspans[hrKey], cellContent)
                                end
                            else
                                row = row .. renderHRCell(premHR, premijeraHRRowspans[hrKey])
                                row = row .. renderHRCell(finHR)
                            end
                        else
                            if finHR == "premijera"
                                or sakrijfinale == "drugo"
                                or sakrijfinale == "sve"
                                or (isSpecial(index) and (not finHR or finHR == "")) then

                                local cellContent = premHR
                                if cellContent == "" then
                                    row = row .. '\n| colspan="2" style="background:#ececec; color:#2C2C2C; text-align:center;" | n.p.'
                                else
                                    if not pipesearch(cellContent) then
                                        cellContent = "| " .. cellContent
                                    end
                                    row = row .. '\n| colspan="2" style="white-space:nowrap;" ' .. cellContent
                                end
                            else
                                row = row .. renderHRCell(premHR)
                                row = row .. renderHRCell(finHR)
                            end
                        end
                    end
                end
                ------ MREŽAHR / Croatian network (MULTI-PART)
                local mrezaHRTrigger = false
                if (args["mrežaHR1"] and args["mrežaHR1"] ~= "") or
                   (args["mrežaHR0S"] and args["mrežaHR0S"] ~= "") then
                    mrezaHRTrigger = true
                else
                    for i = string.byte("A"), string.byte("Z") do
                        local checkKey = "mrežaHR1" .. string.char(i)
                        if args[checkKey] and args[checkKey] ~= "" then
                            mrezaHRTrigger = true
                            break
                        end
                    end
                end

                if croatiaFlag and mrezaHRTrigger and mrezaSpansHR[tostring(index .. letter)] then
                    local spanData = mrezaSpansHR[tostring(index .. letter)]
                    local value = spanData.value or ""
                    if value ~= "" then
                        if not pipesearch(value) then
                            value = "| " .. value
                        end
                        row = row .. string.format('\n| rowspan="%d" %s', spanData.span, value)
                    else
                        row = row .. string.format('\n| rowspan="%d" |', spanData.span)
                    end
                end

                ------ INFO CELLS (MULTI-PART)
                for _, h in ipairs(infoHeaders) do
                    if i == 1 then
                        local value = args["info" .. h.key .. index] or ""
                        if value == "" then
                            row = row .. string.format('\n| rowspan="%d" style="background:#ececec; color:#2C2C2C; text-align:center;" | n.p.', rowspan)
                        else
                            if not pipesearch(value) then
                                value = "| " .. value
                            end
                            row = row .. string.format('\n| rowspan="%d" %s', rowspan, value)
                        end
                    end
                end

                table.insert(output, row)
                table.insert(output, '|-')
            end
        else
        	
            ------ REDOVI ZA SEZONE S JEDNIM DIJELOM (SINGLE-PART) ------
            local row = ""

            -- SERIJA (SINGLE PART) 
            local serijaValue = args["serija" .. index] or ""
            if serijaRowspans[index] then
                row = row .. string.format('\n! rowspan="%d" style="font-weight:normal; font-style:italic;" | %s', serijaRowspans[index], serijaValue)
            elseif serijaValue ~= "" then
                row = row .. string.format('\n! style="font-weight:normal; font-style:italic;" | %s', serijaValue)
            end

            ------ BOJA (SINGLE PART)
            if bojaFlag and not hideSezona then
                local boja = args["boja" .. index]
                if boja and boja ~= "" then
                    row = row .. string.format('\n| style="background:%s; width:1px;" |', boja)
                else
                    row = row .. '\n| '
                end
            end

            ------ SEZONA (SINGLE-PART) - POČETAK 
            local link        = args["poveznica" .. index]
            local linkText    = args["poveznicaT" .. index] or args["poveznica" .. index .. "T"]
            local seasonLabel = linkText and linkText ~= "" and linkText or tostring(index):gsub("S$", "") .. (isSpecial(index) and "S" or "") .. "."

            ------ Izračunaj colspan za specijale bez epizoda
            local epizode      = args["epizode" .. index]
            local seasonColspan = 1
            if isSpecial(index) and (not epizode or epizode == "") then
                seasonColspan = 1 + epizodeColspan + #dodatnoHeaders
            end

            ------ SEZONA CELL (SINGLE PART)
            if not hideSezona then
                if link and link ~= "" then
                    row = row .. string.format('\n! colspan="%d" | [[%s|%s]]', seasonColspan, link, seasonLabel)
                else
                    row = row .. string.format('\n! colspan="%d" | %s', seasonColspan, seasonLabel)
                end
            end

            ------ DODATNO CELLS (SINGLE PART)
            if not (isSpecial(index) and (not epizode or epizode == "")) then
                for _, h in ipairs(dodatnoHeaders) do
                    local value = args["dodatno" .. h.key .. index] or ""
                    if value == "" then
                        row = row .. '\n| rowspan="1" style="background:#ececec; color:#2C2C2C; text-align:center;" | n.p.'
                    else
                        if not pipesearch(value) then
                            value = "| " .. value
                        end
                        row = row .. string.format('\n| rowspan="1" %s', value)
                    end
                end
            end

            ------ EPIZODE CELL (SINGLE PART) 
            local epizode = args["epizode" .. index]
            if epizodeFlag then
                if isSpecial(index) and (not epizode or epizode == "") then
                    -- Skip episode cell, merge season and episode columns
                else
                    if epizode and epizode ~= "" then
                        if epizodeColspan == 2 then
                            row = row .. '\n| colspan="2" | ' .. epizode
                        else
                            row = row .. '\n| ' .. epizode
                        end
                    else
                        if epizodeColspan == 2 then
                            row = row .. '\n| colspan="2" style="background:#ececec; color:#2C2C2C; text-align:center;" | n.p.'
                        else
                            row = row .. '\n| style="background:#ececec; color:#2C2C2C; text-align:center;" | n.p.'
                        end
                    end
                end
            end

            ------ PREMIJERA AND FINALE (SINGLE PART)
            local premijera = ""
            local finale    = ""

            if not premijeraSkipSet[index] then
                premijera = args["premijera" .. index] or ""
                finale    = args["finale" .. index] or ""
            end

            local sakrijfinale   = args["sakrijfinale"] or ""
            local premijerapipe  = pipesearch(premijera)
            local finalepipe     = pipesearch(finale)

            local function renderCell(value, rowspan)
                if value == "" then
                    return string.format('\n|%s style="background:#ececec; color:#2C2C2C; text-align:center;" | n.p.', rowspan and (' rowspan="' .. rowspan .. '"') or "")
                end
                if not pipesearch(value) then
                    value = "| " .. value
                end
                return string.format('\n|%s style="white-space:nowrap;" %s', rowspan and (' rowspan="' .. rowspan .. '"') or "", value)
            end
            if premijeraRowspans[index] then
                if finale == "premijera"
                    or sakrijfinale == "da"
                    or sakrijfinale == "sve"
                    or sakrijfinale == "prvo"
                    or (isSpecial(index) and (not finale or finale == "")) then

                    local cellContent = premijera
                    if cellContent == "" then
                        row = row .. string.format('\n| colspan="2" rowspan="%d" style="background:#ececec; color:#2C2C2C; text-align:center;" | n.p.', premijeraRowspans[index])
                    else
                        if not pipesearch(cellContent) then
                            cellContent = "| " .. cellContent
                        end
                        row = row .. string.format('\n| colspan="2" rowspan="%d" style="white-space:nowrap;" %s', premijeraRowspans[index], cellContent)
                    end
                else
                    row = row .. renderCell(premijera, premijeraRowspans[index])
                    row = row .. renderCell(finale)
                end
            elseif not premijeraSkipSet[index] then
                if finale == "premijera"
                    or sakrijfinale == "da"
                    or sakrijfinale == "sve"
                    or sakrijfinale == "prvo"
                    or (isSpecial(index) and (not finale or finale == "")) then

                    local cellContent = premijera
                    if cellContent == "" then
                        row = row .. '\n| colspan="2" style="background:#ececec; color:#2C2C2C; text-align:center;" | n.p.'
                    else
                        if not pipesearch(cellContent) then
                            cellContent = "| " .. cellContent
                        end
                        row = row .. '\n| colspan="2" style="white-space:nowrap;" ' .. cellContent
                    end
                else
                    row = row .. renderCell(premijera)
                    row = row .. renderCell(finale)
                end
            end
            -- MREŽA (SINGLE PART)
            local key = tostring(index)

            -- Check if mreža1, mreža1A-Z, or mreža0S is defined
            local mrezaTrigger = false
            if (args["mreža1"] and args["mreža1"] ~= "") or
               (args["mreža0S"] and args["mreža0S"] ~= "") then
                mrezaTrigger = true
            else
                for i = string.byte("A"), string.byte("Z") do
                    local checkKey = "mreža1" .. string.char(i)
                    if args[checkKey] and args[checkKey] ~= "" then
                        mrezaTrigger = true
                        break
                    end
                end
            end

            -- Only render mreža cell if trigger is true
            if mrezaTrigger and mrezaSpans[key] then
                local value = mrezaSpans[key].value or ""
                if value ~= "" then
                    if not pipesearch(value) then
                        value = "| " .. value
                    end
                    row = row .. string.format('\n| rowspan="%d" %s', mrezaSpans[key].span, value)
                else
                    row = row .. string.format('\n| rowspan="%d" |', mrezaSpans[key].span)
                end
            end

            ------ PREMIJERAHR AND FINALEHR (SINGLE PART) 
            if croatiaFlag and not premijeraHRSkipSet[index] then
                local premHR = args["premijeraHR" .. index] or ""
                local finHR  = args["finaleHR" .. index] or ""

                local sakrijfinale = args["sakrijfinale"] or ""

                local premHRpipe = pipesearch(premHR)
                local finHRpipe  = pipesearch(finHR)

                local function renderHRCell(value, rowspan)
                    if value == "" then
                        return string.format('\n|%s style="background:#ececec; color:#2C2C2C; text-align:center;" | n.p.', rowspan and (' rowspan="' .. rowspan .. '"') or "")
                    end
                    if not pipesearch(value) then
                        value = "| " .. value
                    end
                    return string.format('\n|%s style="white-space:nowrap;" %s', rowspan and (' rowspan="' .. rowspan .. '"') or "", value)
                end

                if premijeraHRRowspans[index] then
                    if finHR == "premijera"
                        or sakrijfinale == "drugo"
                        or sakrijfinale == "sve"
                        or (isSpecial(index) and (not finHR or finHR == "")) then

                        local cellContent = premHR
                        if cellContent == "" then
                            row = row .. string.format('\n| colspan="2" rowspan="%d" style="background:#ececec; color:#2C2C2C; text-align:center;" | n.p.', premijeraHRRowspans[index])
                        else
                            if not pipesearch(cellContent) then
                                cellContent = "| " .. cellContent
                            end
                            row = row .. string.format('\n| colspan="2" rowspan="%d" style="white-space:nowrap;" %s', premijeraHRRowspans[index], cellContent)
                        end
                    else
                        row = row .. renderHRCell(premHR, premijeraHRRowspans[index])
                        row = row .. renderHRCell(finHR)
                    end
                else
                    if finHR == "premijera"
                        or sakrijfinale == "drugo"
                        or sakrijfinale == "sve"
                        or (isSpecial(index) and (not finHR or finHR == "")) then

                        local cellContent = premHR
                        if cellContent == "" then
                            row = row .. '\n| colspan="2" style="background:#ececec; color:#2C2C2C; text-align:center;" | n.p.'
                        else
                            if not pipesearch(cellContent) then
                                cellContent = "| " .. cellContent
                            end
                            row = row .. '\n| colspan="2" style="white-space:nowrap;" ' .. cellContent
                        end
                    else
                        row = row .. renderHRCell(premHR)
                        row = row .. renderHRCell(finHR)
                    end
                end
            end

            ------ MREŽAHR (SINGLE PART)
            local mrezaHRTrigger = false
            if (args["mrežaHR1"] and args["mrežaHR1"] ~= "") or
               (args["mrežaHR0S"] and args["mrežaHR0S"] ~= "") then
                mrezaHRTrigger = true
            else
                for i = string.byte("A"), string.byte("Z") do
                    local checkKey = "mrežaHR1" .. string.char(i)
                    if args[checkKey] and args[checkKey] ~= "" then
                        mrezaHRTrigger = true
                        break
                    end
                end
            end

            -- Only render mrežaHR cell if trigger is true
            if croatiaFlag and mrezaHRTrigger and mrezaSpansHR[tostring(index)] then
                local spanData = mrezaSpansHR[tostring(index)]
                local value = spanData.value or ""
                if value ~= "" then
                    if not pipesearch(value) then
                        value = "| " .. value
                    end
                    row = row .. string.format('\n| rowspan="%d" %s', spanData.span, value)
                else
                    row = row .. string.format('\n| rowspan="%d" |', spanData.span)
                end
            end

            ------ INFO CELLS (SINGLE PART) 
            for _, h in ipairs(infoHeaders) do
                local value = args["info" .. h.key .. index] or ""
                if value == "" then
                    row = row .. '\n| rowspan="1" style="background:#ececec; color:#2C2C2C; text-align:center;" | n.p.'
                else
                    if not pipesearch(value) then
                        value = "| " .. value
                    end
                    row = row .. string.format('\n| rowspan="1" %s', value)
                end
            end

            table.insert(output, row)
            table.insert(output, '|-')
        end
    end
    ------ PARAMETAR TABLICA za uključivanje sljedeće tablice 
    local tablica = args["tablica"]
    if tablica and tablica ~= "" then
        table.insert(output, tablica)
    end
    
    ------ ZATVARANJE TABLICE 
        table.insert(output, '|}')

    return table.concat(output, "\n")
end

return p