Модуль:Wikidata/Places/Custom

З Вікіпедыі, свабоднай энцыклапедыі

Дакументацыю да гэтага модуля можна стварыць у Модуль:Wikidata/Places/Custom/Дакументацыя

local WDS = require( 'Module:WikidataSelectors' );
local WD = require( 'Module:Wikidata' );
local Flags = require( 'Module:Wikidata/Flags' );
local p = {};
local project = 'bewiki';

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 'unknown argument type: ' .. 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; -- ends with Z, Zulu time
		-- matches ±hh:mm, ±hhmm or ±hh; else returns nils
		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('Unsupported precision: ' .. precision );
end

local function getTimeBoundariesFromProperty( context, propertyId )
	mw.log( 'Get time boundaries for ' .. propertyId .. '...');

	local dateClaims = WDS.filter( context.entity.claims, propertyId );
	if ( not dateClaims or #dateClaims == 0 ) then return nil; end
	mw.log( 'Get time boundaries for ' .. propertyId .. '... Got ' .. #dateClaims .. ' date claim(s)');

	-- only support exact date so far, but need improvment
	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

	mw.log( 'Time boundaries for ' .. propertyId .. ' are ' .. left .. ' and ' .. right );
	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 )
	-- only support exact date so far, but need improvment
	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'} ) -- located in
	if not results or #results == 0 then
		results = getParentsInBoundariesSnakImpl( context, entity, boundaries, {'P17'} ) -- country
	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[Q7216840,Q20019082,Q15078955,Q27587491]' );
	if ( filteredClaims and #filteredClaims > 0 ) then 
		return 'Пасёлак гарадскога тыпу'
	else
		filteredClaims = WDS.filter( entity.claims, 'P31[Q106389302,Q7216840,Q12131640,Q5123999,Q515,Q7930989,Q12131624]' );
		if ( filteredClaims and #filteredClaims > 0 ) then 
	    	return 'Горад'
    	else
	    	filteredClaims = WDS.filter( entity.claims, 'P31[Q2514025]' );
		    if ( filteredClaims and #filteredClaims > 0 ) then 
	        	return 'Пасёлак'
        	else
	        	filteredClaims = WDS.filter( entity.claims, 'P31[Q5084, Q21672098]' );
		        if ( filteredClaims and #filteredClaims > 0 ) then 
	            	return 'Вёска'
            	else
	            	filteredClaims = WDS.filter( entity.claims, 'P31[Q532]' );
		            if ( filteredClaims and #filteredClaims > 0 ) then 
	                	return 'Сяло'
                	else
	                	filteredClaims = WDS.filter( entity.claims, 'P31[Q748331]' );
		                if ( filteredClaims and #filteredClaims > 0 ) then 
	                	    return 'Станіца'
                	    else
	                	    filteredClaims = WDS.filter( entity.claims, 'P31[Q771444]' );
		                    if ( filteredClaims and #filteredClaims > 0 ) then 
	                	        return 'Аул'
                	        else
	                	        filteredClaims = WDS.filter( entity.claims, 'P31[Q27517161]' );
		                        if ( filteredClaims and #filteredClaims > 0 ) then 
	                	            return 'Курортны пасёлак'
                	            else
	                	            return 'Населены пункт'
                    	        end
                    	    end
                    	end
                	end
            	end
    	    end
    	end
	end
end
	
function p.getRegion( frame )
    local args = frame.args;
    if not args.regionEntity then
        error( 'regionEntity is absent' )
    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
				-- get parent
				local newParentSnaks = getParentsInBoundariesSnak( context, parent, {nil, nil} );
				if ( not newParentSnaks or #newParentSnaks == 0 ) then
					parent = nil;
				else
				    --if ( #newParentSnaks > 1 ) then
				    --  result = result .. '[[Катэгорыя:Вікіпедыя:Старонкі з неадназначнымі геаланцужкамі]]';
				    --end  
					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
                   	    mw.log( 'snak has needed type');
            			local label = mw.wikibase.label( 'Q' .. parentSnak.datavalue.value['numeric-id'] );
                   	    if (mw.wikibase.sitelink( 'Q' .. parentSnak.datavalue.value['numeric-id'] )) then
                   	      if args.label == '1' then
                   	    	result = label;
                       	  elseif args.plainlink == '1' then
                       	    result = mw.wikibase.sitelink( 'Q' .. parentSnak.datavalue.value['numeric-id'] );
                       	  else
                       	    result = WD.simpleFormatEntityId(parent.id);
                       	  end;	
					    else
					      local title = mw.title.new( label );
	                      if args.label == '1' then
	                 		result = label;
	                 	  else
	                 		result = WD.simpleFormatEntityId(parent.id)
                    	  end
                    	end
					    --if ( #newParentSnaks > 1 ) then
				        --  result = result .. '[[Катэгорыя:Вікіпедыя:Старонкі з неадназначнымі геаланцужкамі]]';
				        --end
                       	return result;
					end
				end
			end
		else
            mw.log( 'snak has needed type');
            result = mw.wikibase.sitelink( mw.wikibase.getEntityIdForCurrentPage()) .. '|' .. mw.wikibase.label( mw.wikibase.getEntityIdForCurrentPage() );
            return result;
		end
    end
	return result;
end

-- атрыманне ланцужка басейнаў для гідраграфічнага аб’екта
function p.getBasin( frame )
    local args = frame.args
    local entity = mw.wikibase.getEntity();      
	local parent = entity;
	local result = ''
	while ( parent ~= nil and parent.claims ) do
		if parent.claims.P403 then
			parent = mw.wikibase.getEntity( 'Q' .. parent.claims.P403[1].mainsnak.datavalue.value['numeric-id'] );
            local label = WD.simpleFormatEntityId(parent.id)
			mw.log(label)
			if (result == '') then
            	result = result .. label
            else
            	result = result .. '&nbsp;→&#32;' .. label
            end
		else
			parent = nil	
		end
    end
	return result;
end
    
return p;