Přeskočit na obsah

Modul:Wikidata/Sorters

Tato stránka je zamčena
Z Wikipedie, otevřené encyklopedie

require "Modul:No globals"

local p = {}

local lib = require 'Modul:Wikidata/lib'
local inverted = false
local sorters = {}
local current_sorter = 1

local function checkInvert(value)
	if inverted then
		return not value
	end
	return value and true
end

local function sortSame(first, second)
	current_sorter = current_sorter + 1
	if sorters[current_sorter] then
		return sorters[current_sorter](first, second)
	end
	current_sorter = 1
	return checkInvert(false)
end

local function sortAlphabetically(first, second)
	if not (first and second) then
		return checkInvert(second)
	end
	if not (first.mainsnak.snaktype == "value" and second.mainsnak.snaktype == "value") then
		return checkInvert(second.mainsnak.snaktype == "value")
	end
	local first_label = mw.wikibase.label(lib.getEntityIdFromValue(first.mainsnak.datavalue.value))
	local second_label = mw.wikibase.label(lib.getEntityIdFromValue(second.mainsnak.datavalue.value))
	if not (first_label and second_label) then
		return checkInvert(second_label)
	end
	if first_label == second_label then
		return sortSame(first, second)
	end
	local min_length = mw.ustring.len(first_label)
	if mw.ustring.len(second_label) < mw.ustring.len(first_label) then
		min_length = mw.ustring.len(second_label)
	end
	local chars = " .,:-/'0123456789aábcčdďeéěfghiíjklmnňoópqrřsštťuúůvwxyýzž"
	local function charValue(char)
		return mw.ustring.match(chars, '()' .. char) or (mw.ustring.len(chars) + 1)
	end
	local i = 1
	while i <= min_length do
		local first_char = mw.ustring.sub(mw.ustring.lower(first_label), i, i)
		local second_char = mw.ustring.sub(mw.ustring.lower(second_label), i, i)
		if charValue(first_char) ~= charValue(second_char) then
			return checkInvert(charValue(first_char) < charValue(second_char))
		end
		i = i + 1
	end
	return checkInvert(mw.ustring.len(second_label) == min_length)
end

local function sortByDate(first, second)
	local Date = require 'Modul:Wikidata/datum'
	local FirstValues, SecondValues
	if first and first.qualifiers then
		FirstValues = {}
		local Time = require 'Modul:Time'
		for key, array in pairs(lib.props) do
			for _, prop in pairs(array) do
				if first.qualifiers[prop] then
					for _, qualData in pairs(first.qualifiers[prop]) do
						if qualData.snaktype == "value" then
							FirstValues[key] = Time.newFromWikidataValue(qualData.datavalue.value)
							break
						end
					end
				end
			end
		end
	end
	if second and second.qualifiers then
		SecondValues = {}
		local Time = require 'Modul:Time'
		for key, array in pairs(lib.props) do
			for _, prop in pairs(array) do
				if second.qualifiers[prop] then
					for _, qualData in pairs(second.qualifiers[prop]) do
						if qualData.snaktype == "value" then
							SecondValues[key] = Time.newFromWikidataValue(qualData.datavalue.value)
							break
						end
					end
				end
			end
		end
	end
	if not FirstValues or not SecondValues then
		if not FirstValues and not SecondValues then
			return checkInvert(false)
		else
			return checkInvert(not SecondValues)
		end
	end
	if FirstValues.point or SecondValues.point then
		if FirstValues.point and SecondValues.point then
			if Date.AreDatesSame(FirstValues.point, SecondValues.point) then
				return sortSame(first, second)
			else
				return checkInvert(Date.IsSecondLaterThanFirst(FirstValues.point, SecondValues.point))
			end
		else
			return checkInvert(not FirstValues.point)
		end
	else
		if FirstValues.begin or SecondValues.begin then
			if FirstValues.begin and SecondValues.begin then
				return checkInvert(Date.IsSecondLaterThanFirst(FirstValues.begin, SecondValues.begin))
			else
				return checkInvert(not FirstValues.begin)
			end
		elseif FirstValues.ending or SecondValues.ending then
			if FirstValues.ending and SecondValues.ending then
				return checkInvert(Date.IsSecondLaterThanFirst(FirstValues.ending, SecondValues.ending))
			else
				return checkInvert(not FirstValues.ending)
			end
		end
	end
	return checkInvert(false)
end

local function sortByRank(first, second)
	if not (first and second) then
		return checkInvert(false)
	end
	if first.rank == second.rank then
		return sortSame(first, second)
	end
	if first.rank == 'preferred' and second.rank ~= 'preferred' then
		return checkInvert(true)
	elseif first.rank == 'normal' and second.rank == 'deprecated' then
		return checkInvert(true)
	end
	return checkInvert(false)
end

local function sortByQuantity(first, second)
	if not (first and second) then
		return checkInvert(second)
	end
	if not (first.mainsnak.snaktype == "value" and second.mainsnak.snaktype == "value") then
		return checkInvert(second.mainsnak.snaktype == "value")
	end
	local first_quantity = tonumber(first.mainsnak.datavalue.value.amount)
	local second_quantity = tonumber(second.mainsnak.datavalue.value.amount)
	if first_quantity == second_quantity then
		return sortSame(first, second)
	end
	return checkInvert(first_quantity > second_quantity)
end

local Methods = {
	alpha = {
		datatypes = { 'wikibase-item', 'wikibase-property' },
		sorter = sortAlphabetically,
	},
	date = {
		sorter = sortByDate
	},
	number = {
		datatypes = { 'quantity' },
		sorter = sortByQuantity,
	},
	rank = {
		sorter = sortByRank
	},
}

local function getSorter(method, curr_datatype)
	if Methods[method] then
		if Methods[method].datatypes then
			for _, datatype in pairs(Methods[method].datatypes) do
				if curr_datatype == datatype then
					return Methods[method].sorter
				end
			end
			return error(lib.formatError('invalid-datatype', method))
		end
		return Methods[method].sorter
	end
	return error(lib.formatError('invalid-sort', method))
end

function p.sortStatements(statements, options)
	if lib.isOptionTrue(options, 'invert') then
		inverted = true
	end

	local datatype = statements[math.random(1, #statements)].mainsnak.datatype
	local methods = lib.textToTable(options.sort)
	for key, method in pairs(methods) do
		table.insert(sorters, getSorter(method, datatype))
	end

	table.sort(statements, sorters[1])
	return statements
end

function p.test()
	local Module = require 'Modul:Wikidata'
	local entity = mw.wikibase.getEntity('Q183')
	local Statements = Module.filterStatementsFromLua(entity, { property = 'P1082' })
	return p.sortStatements(Statements, { sort = 'rank,number,date' }) and true
end

return p