Модуль:Вікізьвесткі/месца/Беларусь

Дакумэнтацыю да гэтага модуля можна стварыць у Модуль:Вікізьвесткі/месца/Беларусь/Дакумэнтацыя

local WDS = require('Модуль:Сьцьверджаньні Вікізьвестак');
local p = {};

local function min(prev, next)
    if (prev == nil) then
        return next;
    elseif (prev > next) then
        return next;
    else
        return prev;
    end
end

local function max(prev, next)
    if (prev == nil) then
        return next;
    elseif (prev < next) then
        return next;
    else
        return prev;
    end
end

local function splitISO8601(str)
    if 'table' == type(str) then
        if str.args and str.args[1] then
            str = '' .. str.args[1]
        else
            return 'невядомы тып аргумэнту: ' .. type(str) .. ': ' .. table.tostring(str)
        end
    end
    local Y, M, D = (function(str)
        local pattern = "(%-?%d+)%-(%d+)%-(%d+)T"
        local Y, M, D = mw.ustring.match(str, pattern)
        return tonumber(Y), tonumber(M), tonumber(D)
    end)(str);
    local h, m, s = (function(str)
        local pattern = "T(%d+):(%d+):(%d+)%Z";
        local H, M, S = mw.ustring.match(str, pattern);
        return tonumber(H), tonumber(M), tonumber(S);
    end)(str);
    local oh, om = (function(str)
        if str:sub(-1) == "Z" then
            return 0, 0
        end ;
        local pattern = "([-+])(%d%d):?(%d?%d?)$";
        local sign, oh, om = mw.ustring.match(str, pattern);
        sign, oh, om = sign or "+", oh or "00", om or "00";
        return tonumber(sign .. oh), tonumber(sign .. om);
    end)(str)
    return { year = Y, month = M, day = D, hour = (h + oh), min = (m + om), sec = s };
end

local function parseTimeBoundaries(time, precision)
    local s = splitISO8601(time);
    if (not s) then
        return nil;
    end

    if (precision >= 0 and precision <= 8) then
        local powers = { 1000000000, 100000000, 10000000, 1000000, 100000, 10000, 1000, 100, 10 }
        local power = powers[precision + 1];
        local left = s.year - (s.year % power);
        return { tonumber(os.time({ year = left, month = 1, day = 1, hour = 0, min = 0, sec = 0 })) * 1000,
                 tonumber(os.time({ year = left + power - 1, month = 12, day = 31, hour = 29, min = 59, sec = 58 })) * 1000 + 1999 };
    end

    if (precision == 9) then
        return { tonumber(os.time({ year = s.year, month = 1, day = 1, hour = 0, min = 0, sec = 0 })) * 1000,
                 tonumber(os.time({ year = s.year, month = 12, day = 31, hour = 23, min = 59, sec = 58 })) * 1000 + 1999 };
    end

    if (precision == 10) then
        local lastDays = { 31, 28.25, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
        local lastDay = lastDays[s.month];
        return { tonumber(os.time({ year = s.year, month = s.month, day = 1, hour = 0, min = 0, sec = 0 })) * 1000,
                 tonumber(os.time({ year = s.year, month = s.month, day = lastDay, hour = 23, min = 59, sec = 58 })) * 1000 + 1999 };
    end

    if (precision == 11) then
        return { tonumber(os.time({ year = s.year, month = s.month, day = s.day, hour = 0, min = 0, sec = 0 })) * 1000,
                 tonumber(os.time({ year = s.year, month = s.month, day = s.day, hour = 23, min = 59, sec = 58 })) * 1000 + 1999 };
    end

    if (precision == 12) then
        return { tonumber(os.time({ year = s.year, month = s.month, day = s.day, hour = s.hour, min = 0, sec = 0 })) * 1000,
                 tonumber(os.time({ year = s.year, month = s.month, day = s.day, hour = s.hour, min = 59, sec = 58 })) * 1000 + 19991999 };
    end

    if (precision == 13) then
        return { tonumber(os.time({ year = s.year, month = s.month, day = s.day, hour = s.hour, min = s.min, sec = 0 })) * 1000,
                 tonumber(os.time({ year = s.year, month = s.month, day = s.day, hour = s.hour, min = s.min, sec = 58 })) * 1000 + 1999 };
    end

    if (precision == 14) then
        local t = tonumber(os.time({ year = s.year, month = s.month, day = s.day, hour = s.hour, min = s.min, sec = 0 }));
        return { t * 1000, t * 1000 + 999 };
    end

    error('Дакладнасьць не падтрымліваецца: ' .. precision);
end

local function getTimeBoundariesFromProperty(context, propertyId)
    local dateClaims = WDS.filter(context.entity.claims, propertyId);
    if (not dateClaims or #dateClaims == 0) then
        return nil;
    end

    local left = nil;
    local right = nil;
    for _, claim in pairs(dateClaims) do
        if (not claim.mainsnak) then
            return nil;
        end
        local boundaries = context.parseTimeBoundariesFromSnak(claim.mainsnak);
        if (not boundaries) then
            return nil;
        end
        left = min(left, boundaries[1]);
        right = max(right, boundaries[2]);
    end

    if (not left or not right) then
        return nil;
    end

    return { left, right };
end

local function getTimeBoundariesFromProperties(context, propertyIds)
    for _, propertyId in ipairs(propertyIds) do
        local result = getTimeBoundariesFromProperty(context, propertyId);
        if result then
            return result;
        end
    end

    return nil;
end

local function getTimeBoundariesFromQualifiers(context, statement, qualifierId)
    local left = nil;
    local right = nil;
    if (statement.qualifiers and statement.qualifiers[qualifierId]) then
        for _, qualifier in pairs(statement.qualifiers[qualifierId]) do
            local boundaries = context.parseTimeBoundariesFromSnak(qualifier);
            if (not boundaries) then
                return nil;
            end
            left = min(left, boundaries[1]);
            right = max(right, boundaries[2]);
        end
    end

    if (not left or not right) then
        return nil;
    end

    return { left, right };
end

local function getParentsInBoundariesSnakImpl(context, entity, boundaries, propertyIds)
    local results = {};

    if not propertyIds or #propertyIds == 0 then
        return results;
    end

    if entity.claims then
        for _, propertyId in ipairs(propertyIds) do
            local filteredClaims = WDS.filter(entity.claims, propertyId .. '[rank:preferred, rank:normal]');
            if filteredClaims then
                for _, claim in pairs(filteredClaims) do
                    if not boundaries or not propertyIds or #propertyIds == 0 then
                        table.insert(results, claim.mainsnak);
                    else
                        local endBoundaries = getTimeBoundariesFromQualifiers(context, claim, 'P582');

                        if (endBoundaries == nil) then
                            table.insert(results, claim.mainsnak);
                        end
                    end
                end
            end

            if #results > 0 then
                break ;
            end
        end
    end

    return results;
end

local function getParentsInBoundariesSnak(context, entity, boundaries)
    if (not entity) then
        error('entity must be specified');
    end
    if (type(entity) ~= 'table') then
        error('entity must be table');
    end
    if (not boundaries) then
        error('boundaries must be specified');
    end
    if (type(boundaries) ~= 'table') then
        error('boundaries must be table');
    end

    local results = getParentsInBoundariesSnakImpl(context, entity, boundaries, { 'P131' }) -- адміністрацыйная адзінка
    if not results or #results == 0 then
        results = getParentsInBoundariesSnakImpl(context, entity, boundaries, { 'P17' }) -- краіна
    end
    for r, result in pairs(results) do
        if result.snaktype ~= 'value' then
            return nil;
        end
        local resultId = 'Q' .. result.datavalue.value['numeric-id'];
        if (resultId == entity.id) then
            return nil;
        end
    end
    return results;
end

function p.getStatus(frame)
    local args = frame.args;
    local entity = mw.wikibase.getEntityObject();
    if (not entity) then
        return 'Населены пункт'
    end
    local filteredClaims = WDS.filter(entity.claims, 'P31[Q91733160]');
    if (filteredClaims and #filteredClaims > 0) then
        return 'Пасёлак гарадзкога тыпу'
    else
        filteredClaims = WDS.filter(entity.claims, 'P31[Q7930989,Q79323854,Q79324274,Q515]');
        if (filteredClaims and #filteredClaims > 0) then
            return 'Горад'
        else
            filteredClaims = WDS.filter(entity.claims, 'P31[Q65665664,Q2514025]');
            if (filteredClaims and #filteredClaims > 0) then
                return 'Пасёлак'
            else
                filteredClaims = WDS.filter(entity.claims, 'P31[Q65661087,Q5084,Q532,Q1989945]');
                if (filteredClaims and #filteredClaims > 0) then
                    return 'Вёска'
                else
                    filteredClaims = WDS.filter(entity.claims, 'P31[Q65660829,Q2023000]');
                    if (filteredClaims and #filteredClaims > 0) then
                        return 'Хутар'
                    else
                        filteredClaims = WDS.filter(entity.claims, 'P31[Q91733790]');
                        if (filteredClaims and #filteredClaims > 0) then
                            return 'Рабочы пасёлак'
                        else
                            filteredClaims = WDS.filter(entity.claims, 'P31[Q91733598]');
                            if (filteredClaims and #filteredClaims > 0) then
                                return 'Курортны пасёлак'
                            else
                                return 'Населены пункт'
                            end
                        end
                    end
                end
            end
        end
    end
end

function p.getRegion(frame)
    local args = frame.args;
    if not args.regionEntity then
        error('адсутнічае regionEntity')
    end

    local statement = mw.wikibase.getEntityObject();

    local context = {
        entity = statement }
    context.parseTimeBoundariesFromSnak = function(snak)
        if (snak and snak.datavalue and snak.datavalue.value and snak.datavalue.value.time and snak.datavalue.value.precision) then
            return parseTimeBoundaries(snak.datavalue.value.time, snak.datavalue.value.precision);
        end
        return nil;
    end

    local result = '';

    local entity = statement;
    if (not entity) then
        return ''
    else
        local filteredClaims = WDS.filter(entity.claims, 'P31[' .. args.regionEntity .. ']');
        if (not filteredClaims or #filteredClaims == 0) then
            local parent = entity;
            while (parent ~= nil) do
                local newParentSnaks = getParentsInBoundariesSnak(context, parent, { nil, nil });
                if (not newParentSnaks or #newParentSnaks == 0) then
                    parent = nil;
                else
                    local parentSnak = newParentSnaks[1];
                    mw.log('snak found (' .. parentSnak.datavalue.value['numeric-id'] .. ')');
                    parent = mw.wikibase.getEntity('Q' .. parentSnak.datavalue.value['numeric-id']);
                    local regionSnaks = WDS.filter(parent.claims, 'P31[' .. args.regionEntity .. ']')
                    if (not regionSnaks or #regionSnaks == 0) then
                        mw.log('snak has not needed type. Continue search');
                    else
                        local label = mw.wikibase.label('Q' .. parentSnak.datavalue.value['numeric-id']);
                        mw.log(args.label);
                        if (mw.wikibase.sitelink('Q' .. parentSnak.datavalue.value['numeric-id'])) then
                            if args.phone == '1' then
                                result = string.sub(label, 0, -10);
                            else
                            	if args.label == '1' then
                                	result = label;
                            	else
                                	result = '[[' .. mw.wikibase.sitelink('Q' .. parentSnak.datavalue.value['numeric-id']) .. '|' .. label .. ']]';
                            	end
                            end
                        else
                            local title = mw.title.new(label);
                            if args.label == '1' or (title and not title.exists) then
                                result = label;
                            else
                                result = '[[d:Q' .. parentSnak.datavalue.value['numeric-id'] .. '|' .. label .. ']]';
                            end
                        end
                        return result;
                    end
                end
            end
        else
            result = mw.wikibase.sitelink(mw.wikibase.getEntityIdForCurrentPage()) .. '|' .. mw.wikibase.label(mw.wikibase.getEntityIdForCurrentPage());
            return result;
        end
    end
    return result;
end

return p;