מען קען שאפן דאקומענטאציע פאר דעם מאדול ביי יחידה:LocationAndCountry/דאק

--[[Adapted from ro:Modul:LocationAndCountry with changes:
* Using PropertyLink for linking format
* No use of external modules that exist in rowiki but have different version in yiwiki such as wikidata and date modules
   * findLinkToItem/findDateValues/findClaimForTimestamp is local instead of wikidata module
* disabled capabilities:
	* outputReferences
	* offical/short name
]]

-- will display a wikidata property representing a location, followed by a comma and the name of the country, both with wikilinks
-- the first argument specifies the parameter to be displayed
-- the second argument specifies the entity ID
-- the third argument specifies a timestamp showing the moment in time for which the country is to be identified
-- the fourth argument specifies the maximum number of values to be processed (default 1)
-- the fifth argument specifies the separator to use when displaying multiple values
local getArgs = require('Module:Arguments').getArgs
local HeDateUtils = require('Module:דאטע')
local TableTools = require('Module:TableTools')
local PropertyLink = require('Module:PropertyLink')

local p = {}

function emptyToNil(args)
	local str = args[1]
	if str == '' then return nil end
	return str
end

local function isValueSnak(snak)
	return snak and snak.snaktype == 'value'
end

local function hasValueSnak(claim)
	return claim and claim.type == 'statement' and isValueSnak(claim.mainsnak)
end

local function findDateValues(propertyId, entityId)
	entityId = entityId or mw.wikibase.getEntityIdForCurrentPage()
	
	if entityId then
		local bestclaims = mw.wikibase.getBestStatements(entityId, propertyId)
		local bestdates = {}
		
		if bestclaims then for k, v in pairs(bestclaims) do
			if hasValueSnak(v) and v.mainsnak.datatype == 'time' then
				local d = HeDateUtils.newFromWikidataValue(v.mainsnak.datavalue.value)
				d.claim = v
				table.insert(bestdates, d)
			elseif hasValueSnak(v) then
				local d = {}
				d.claim = v
				table.insert(bestdates, d)
			end
		end end
		return bestdates
	end
end


local timestampComparator = function(p1, p2)
	if p1 and p2 then
		local q1 = p1.qualifiers
		local q2 = p2.qualifiers
		local d1 = nil
		local d2 = nil
		if q1 and q2 then
			if q1['P580'] and q1['P580'][1] and q1['P580'][1].datavalue then
				d1 = HeDateUtils.newFromWikidataValue(q1['P580'][1].datavalue.value)
			end
			if q2['P580'] and q2['P580'][1] and q2['P580'][1].datavalue then
				d2 = HeDateUtils.newFromWikidataValue(q2['P580'][1].datavalue.value)
			end
			
			if d1 and d2 then return not HeDateUtils.le(d2, d1, true)
			elseif d1 then return true
			elseif d2 then return false end
		elseif q1 then return true
		elseif q2 then return false
		end
	else
		if p1 then return true end
		if p2 then return false end
	end
	return false
end

local function findSortedClaimsForProperty(entity, propertyId)
	if entity == nil then entity = mw.wikibase.getEntityIdForCurrentPage() end
	local rawClaims = mw.wikibase.getAllStatements(entity, propertyId)
	if rawClaims == nil then return {} end
	
	table.sort(rawClaims, timestampComparator)
	return rawClaims
end

local function findClaimForTimestamp(entityId, propertyId, timestamp)
	local propClaims = findSortedClaimsForProperty(entityId, propertyId)
	local bestClaims = {}
	local bestNoTimeClaim
	
	if propClaims then for _,eachPropClaim in ipairs(propClaims) do
		if hasValueSnak(eachPropClaim)
			and mw.wikibase.entity.claimRanks['RANK_' .. mw.ustring.upper(eachPropClaim.rank)] >= mw.wikibase.entity.claimRanks.RANK_NORMAL then
			
			if eachPropClaim.mainsnak.datavalue.type ~= 'monolingualtext' or eachPropClaim.mainsnak.datavalue.value.language == 'he' then
				local before = nil
				local after = nil
				if eachPropClaim.qualifiers then
					if eachPropClaim.qualifiers['P580'] and eachPropClaim.qualifiers['P580'][1] and isValueSnak(eachPropClaim.qualifiers['P580'][1]) then
						before = HeDateUtils.julianToGregorian(HeDateUtils.newFromWikidataValue(eachPropClaim.qualifiers['P580'][1].datavalue.value))
						--after = GregorianDate.convertToGregorianIfInInterval(DateUtils.extractDateFromWikidataSnak(eachPropClaim.qualifiers['P580'][1]))
					end
					if eachPropClaim.qualifiers['P582'] and eachPropClaim.qualifiers['P582'][1] and isValueSnak(eachPropClaim.qualifiers['P582'][1]) then
						after = HeDateUtils.julianToGregorian(HeDateUtils.newFromWikidataValue(eachPropClaim.qualifiers['P582'][1].datavalue.value))
						--before = GregorianDate.convertToGregorianIfInInterval(DateUtils.extractDateFromWikidataSnak(eachPropClaim.qualifiers['P582'][1]))
					end
				end

				if timestamp then
					if after == nil and before and not HeDateUtils.le(timestamp, before) then
						table.insert(bestClaims, eachPropClaim)
					elseif after and before and not HeDateUtils.le(timestamp, before) and HeDateUtils.le(timestamp, after)  then 
						table.insert(bestClaims, eachPropClaim) 
					elseif after and before == nil and HeDateUtils.le(timestamp, after) then
						table.insert(bestClaims, eachPropClaim) 
					end
				end
				if not bestNoTimeClaim or mw.wikibase.entity.claimRanks['RANK_' .. mw.ustring.upper(bestNoTimeClaim.rank)] < mw.wikibase.entity.claimRanks['RANK_' .. mw.ustring.upper(eachPropClaim.rank)] 
						or (mw.wikibase.entity.claimRanks['RANK_' .. mw.ustring.upper(bestNoTimeClaim.rank)] < mw.wikibase.entity.claimRanks['RANK_' .. mw.ustring.upper(eachPropClaim.rank)] and not after) then
					
					bestNoTimeClaim = eachPropClaim
				end
			end
		end
	end end

	if #bestClaims==0 and bestNoTimeClaim then
		return bestNoTimeClaim
	end
	if #bestClaims==1 then
		return bestClaims[1]
	elseif (#bestClaims>1) and timestamp then
		-- disambig: return null and log it
		mw.log('לא ניתן לשייך מיקום ליישות '..entityId .. ' כיוון שקיימות מספר טענות מתאימות שנכונות ל'..timestamp:toString()..'. ניתן לציין מבחין להגדרה חד ערכית.')
		return nil
	else
		return nil
	end
end

local function missingLabelCategory(propertyName)
	return '[[קאטעגאריע:וויקידאטן עטיקעט פעלט אין יידיש: ' .. (mw.wikibase.label( propertyName) or propertyName) .. ']][[קאטעגאריע:וויקידאטן עטיקעט פעלט אין יידיש]]'
end

p.displayFromParams = function(param, entity, timestamp, maxvalues, separator)
	if param == nil then return '' end
	local claims = nil
	local workingEntityId = nil
	if type(entity) == 'table' then
		workingEntityId = entity.id
		claims = entity:getBestStatements(param)
	else
		workingEntityId = entity
		if not workingEntityId then workingEntityId = mw.wikibase.getEntityIdForCurrentPage() end
		if type(entity) == 'number' then workingEntityId = 'Q' .. tostring(entity) end
		if workingEntityId == nil then return '' end
		claims = mw.wikibase.getBestStatements(workingEntityId, param)
	end
	
	local valueList = {}
	local valueCount = 0
	local missingLabel = false
	if claims and 0 < #claims then
		for claimIdx, actualClaim in pairs(claims) do
			valueCount = valueCount + 1
			local locationEntitiesIds = {}
			local locationNames = {} 
			if actualClaim.mainsnak and actualClaim.mainsnak.snaktype == 'value' and actualClaim.mainsnak.datavalue.type == 'wikibase-entityid' then
				local locationEntityId =actualClaim.mainsnak.datavalue.value.id
				table.insert(locationEntitiesIds, locationEntityId)
				
				--attempt to also load administrative unit, but only if present as a qualifier
				local unitQualifier = actualClaim.qualifiers and actualClaim.qualifiers['P131'] and actualClaim.qualifiers['P131'][1]
				if unitQualifier and unitQualifier.snaktype == 'value' then
					table.insert(locationEntitiesIds, unitQualifier.datavalue.value.id)
					locationNames[unitQualifier.datavalue.value.id] = PropertyLink.formatEntity(unitQualifier.datavalue.value.id)
				end
				
				-- attempt to identify country in the qualifier first, but if it's not, go to the entity
				local countryQualifier = actualClaim.qualifiers and actualClaim.qualifiers['P17'] and actualClaim.qualifiers['P17'][1]
				local countryId = nil
				local ts = nil
				if countryQualifier and countryQualifier.snaktype == 'value' then
					table.insert(locationEntitiesIds, countryQualifier.datavalue.value.id)
					locationNames[countryQualifier.datavalue.value.id] = PropertyLink.formatEntity(countryQualifier.datavalue.value.id)
				else
					local countryClaim = nil
					if timestamp then
						if type(timestamp) == 'string' and mw.ustring.gmatch(timestamp, 'P%d+') then
							local wdDates = findDateValues(timestamp, workingEntityId)
							if wdDates and 0 < #wdDates then
								local wdDateIdx = 1
								while wdDateIdx <= #wdDates and (wdDates[wdDateIdx].claim.type ~= 'statement' or wdDates[wdDateIdx].claim.mainsnak.snaktype ~= 'value') do
									wdDateIdx = wdDateIdx + 1
								end
								if wdDateIdx <= #wdDates and (wdDates[wdDateIdx].claim.type == 'statement' and wdDates[wdDateIdx].claim.mainsnak.snaktype == 'value') then
									--wdDates[wdDateIdx] = GregorianDate.convertToGregorianIfInInterval(wdDates[wdDateIdx])
									wdDates[wdDateIdx] = HeDateUtils.julianToGregorian(wdDates[wdDateIdx])
									ts = wdDates[wdDateIdx]
								end
							end
						end
						if ts == nil and type(timestamp) == 'string' then
							ts = HeDateUtils.parseYear(timestamp)
						elseif ts == nil and type(timestamp) == 'table' and timestamp.year then
							ts = timestamp
						end
					end
					
					countryClaim = findClaimForTimestamp(locationEntityId, 'P17', ts)
					if countryClaim and countryClaim.mainsnak and countryClaim.mainsnak.snaktype == 'value' then
						countryId = countryClaim.mainsnak.datavalue.value.id
						table.insert(locationEntitiesIds, countryId)
					end
				end
				locationEntitiesIds = TableTools.removeDuplicates(locationEntitiesIds)
				local locationNamesList = {}
				
				for _,eachLocationId in ipairs(locationEntitiesIds) do
					local missingEntityLabel = false
					if not locationNames[eachLocationId] then
						locationNames[eachLocationId], missingEntityLabel = PropertyLink.formatEntity(eachLocationId)
						missingLabel = missingLabel or missingEntityLabel
						
						--[[ Disabled feature from ro wiki: show the offical name/short name in that timestamp
						local correspindingShortNameClaim = findClaimForTimestamp(eachLocationId, 'P1813', ts)
						if correspindingShortNameClaim then
							locationNames[eachLocationId]= correspindingShortNameClaim.mainsnak.datavalue.value.text
						else
							local correspondingOfficialNameClaim = findClaimForTimestamp(eachLocationId, 'P1448', ts)
							if correspondingOfficialNameClaim then 
								locationNames[eachLocationId] = correspondingOfficialNameClaim.mainsnak.datavalue.value.text
							end
						end
						]]
					end
					
					if not missingEntityLabel then
						table.insert(locationNamesList, locationNames[eachLocationId])
					end
				end
				if 0 < #locationNamesList then
					table.insert(
						valueList,
						--appendToString({
							emptyToNil({table.concat(locationNamesList, ', ')})
							-- wikidata.outputReferences(actualClaim)
						--})
					)
				end
			end
		end	
	end
	if #valueList == 0 then return '' end
	if separator == nil then separator = '; ' end
	if maxvalues > #valueList then maxvalues = #valueList end
	if missingLabel then
		return table.concat(valueList, separator, 1, maxvalues) .. missingLabelCategory(param)
	else
		return table.concat(valueList, separator, 1, maxvalues)
	end
end

p.displayFromArgs = function(args)
	local param = nil
	local entity = nil
	local timestamp = nil
	local maxvalues = 1
	local separator = '; '
	if args[1] or args['param'] then
		param = args[1] or args['param']
	end
	if args[2] or args['entityId'] then
		entity = args[2] or args['entityId']
	end
	if args[3] or args['timestamp'] then
		timestamp = args[3] or args['timestamp']
	end
	if args[4] or args['maxvalues'] then
		maxvalues = tonumber(args[4] or args['maxvalues'])
	end
	if args[5] or args['separator'] then
		separator = args[5] or args['separator']
	end
	return p.displayFromParams(param, entity, timestamp, maxvalues, separator)
end

p.displayFromFrame = function(frame)
	local args = getArgs(frame, { frameOnly = true })
	return p.displayFromArgs(args)
end

p.displayFromParentFrame = function(frame)
	local args = getArgs(frame, { parentOnly = true})
	return p.displayFromArgs(args)
end

return p