Modul':Категория по годам

Рувики-späi
local p = {}

local function getDecade(y)
    return y - (y % 10)
end

local function toRoman(num)
    local romanNumerals = {
        {1000, "M"}, {900, "CM"}, {500, "D"}, {400, "CD"},
        {100, "C"},  {90,  "XC"}, {50,  "L"}, {40,  "XL"},
        {10,   "X"}, {9,   "IX"}, {5,   "V"}, {4,   "IV"},
        {1,    "I"},
    }
    local res = {}
    for _, rn in ipairs(romanNumerals) do
        while num >= rn[1] do
            table.insert(res, rn[2])
            num = num - rn[1]
        end
    end
    return table.concat(res)
end

local function getCentury(y)
    local c = math.floor((y - 1) / 100) + 1
    return toRoman(c)
end

function p.applyPatterns(patternTable, fullText, year, bcFlag, co)
    if type(patternTable) ~= 'table' then
        return ''
    end
    for patternKey, categoriesString in pairs(patternTable) do
        local candidateName = patternKey
            :gsub("{y}", tostring(year))
            :gsub("{bc}", bcFlag and " до н. э." or "")
        if co then
            candidateName = candidateName:gsub("{co}", co)
        end
        if candidateName == fullText then
            local decade = getDecade(year)
            local century = getCentury(year)
            local result = categoriesString
                :gsub("{y}", tostring(year))
                :gsub("{d}", tostring(decade))
                :gsub("{c}", century)
            if bcFlag then
                result = result:gsub("{bc}", " до н. э.")
            else
                result = result:gsub("{bc}", "")
            end
            if co then
                result = result:gsub("{co}", co)
            end
            return result
        end
    end
    return ''
end

function p.getExtraCategories(fullText, year, bcFlag, co)
    if not fullText or fullText == '' then
        return ''
    end
    local firstLetter = mw.ustring.sub(fullText, 1, 1)
    firstLetter = mw.ustring.upper(firstLetter)
    if firstLetter:match("[%aА-Яа-я]") then
        local subModuleName = 'Modul\':Категория по годам/список/' .. firstLetter
        local ok, subModule = pcall(require, subModuleName)
        if ok and type(subModule) == 'table' then
            local cats = p.applyPatterns(subModule, fullText, year, bcFlag, co)
            if cats and cats ~= '' then
                return cats
            end
        end
    end
    local ok2, generalModule = pcall(require, 'Modul\':Категория по годам/список')
    if not ok2 or type(generalModule) ~= 'table' then
        return ''
    end
    return p.applyPatterns(generalModule, fullText, year, bcFlag, co)
end

local function makeYearLink(baseName, realY, suffix)
    if realY == 0 then
        return nil
    elseif realY < 0 then
        local posY = -realY
        local bcSuffix = suffix
        if not bcSuffix:find("до н%. э") then
            bcSuffix = bcSuffix:gsub("%s*$", "") .. " до н. э."
        end
        return '[[:Kategorii:' .. baseName .. ' ' .. posY .. ' ' .. bcSuffix .. '|−' .. posY .. ']]'
    else
        local adSuffix = suffix:gsub("%s*до н%. э%.?", "")
        return '[[:Kategorii:' .. baseName .. ' ' .. realY .. ' ' .. adSuffix .. '|' .. realY .. ']]'
    end
end

local function generateOlderLinks(baseName, current, suffix, count)
    local older = {}
    local i = current - 1
    while #older < count do
        if i ~= 0 then
            table.insert(older, makeYearLink(baseName, i, suffix))
        end
        i = i - 1
    end
    local reversed = {}
    for j = #older, 1, -1 do
        table.insert(reversed, older[j])
    end
    return reversed
end

local function generateNewerLinks(baseName, current, suffix, count)
    local newer = {}
    local i = current + 1
    while #newer < count do
        if i ~= 0 then
            table.insert(newer, makeYearLink(baseName, i, suffix))
        end
        i = i + 1
    end
    return newer
end

function p._makeNavRow(baseName, year, suffix, bcFlag)
    local realYear = bcFlag and -year or year
    local older = generateOlderLinks(baseName, realYear, suffix, 5)
    local newer = generateNewerLinks(baseName, realYear, suffix, 5)
    local centerLink = makeYearLink(baseName, realYear, suffix)
    local t = {}
    table.insert(t, '{| class="standard" align="center"')
    for _, val in ipairs(older) do
        table.insert(t, '| ' .. val)
    end
    if centerLink then
        if bcFlag then
            table.insert(t, '! −' .. year)
        else
            table.insert(t, '! ' .. year)
        end
    end
    for _, val in ipairs(newer) do
        table.insert(t, '| ' .. val)
    end
    table.insert(t, '|}')
    return table.concat(t, '\n')
end

function p.main(frame)
    local title = mw.title.getCurrentTitle()
    if title.namespace ~= 14 then
        return "Модуль «Категория по годам» вызывается не в пространстве «Категория»."
    end
    local text = title.text
    local baseName, year, suffix, co
    local bcFlag = false

	baseName, year, suffix, co = text:match('^(.-)%s+(%d+)%s+(году)%s+в%s+(.+)$')
	if not (baseName and year) then

	    baseName, year, suffix = text:match('^(.-)%s+(%d+)%s+(года)$')
	end
	if not (baseName and year) then

	    baseName, year, suffix = text:match('^(.-)%s+(%d+)%s+(году)$')
	end
	if not (baseName and year) then

	    baseName, year, suffix = text:match('^(.-)%s+(%d+)%s+(года до н%. э%.)$')
	    if baseName and year then
	        bcFlag = true
	    end
	end
	if not (baseName and year) then

	    baseName, year, suffix = text:match('^(.-)%s+(%d+)%s+(году до н%. э%.)$')
	    if baseName and year then
	        bcFlag = true
	    end
	end
	if not (baseName and year) then

	    local y, after = text:match('^(%d+)%s+год%s+до н%. э%.%s*(.*)$')
	    if y then
	        bcFlag = true
	        year = y
	        if after ~= '' then
	            suffix = 'год до н. э. ' .. after
	        else
	            suffix = 'год до н. э.'
	        end
	        baseName = ''
	    else

	        y, after = text:match('^(%d+)%s+год%s*(.*)$')
	        if y then
	            year = y
	            if after ~= '' then
	                suffix = 'год ' .. after
	            else
	                suffix = 'год'
	            end
	            baseName = ''
	        end
	    end
	end

    if not (baseName and year) then
        return ''
    end
    year = tonumber(year)
    if not year then
        return ''
    end

    if co then
        suffix = suffix .. " в {co}"
    end

    local navRow = p._makeNavRow(baseName, year, suffix, bcFlag)
    local extraCats
    if co then
        extraCats = p.getExtraCategories(text, year, bcFlag, co)
    else
        extraCats = p.getExtraCategories(text, year, bcFlag)
    end

    if co then
        local countryModule = require("Modul':Категория по годам/список/страны")
        local countryData = countryModule[co]
        if countryData then

            navRow = navRow:gsub("в%s+{co}", countryData.prep)
            navRow = navRow:gsub("{co}", countryData.gen)
            extraCats = extraCats:gsub("в%s+{co}", countryData.prep)
            extraCats = extraCats:gsub("{co}", countryData.gen)
        else
            navRow = navRow:gsub("{co}", co)
            extraCats = extraCats:gsub("{co}", co)
        end
    end

    return navRow .. '\n' .. extraCats
end

return p