# Module:Wikidata2

local fallback = {'en', 'nb', 'da', 'nn', 'de', 'fr', 'es', 'it', 'pt'}  
local formatera = require('Module:Math')  
local i18n = {  
["errors"] = {  
["property-param-not-provided"] = "Property parameter not provided.",  
["entity-not-found"] = "Entity not found.",  
["unknown-claim-type"] = "Unknown claim type.",  
["unknown-snak-type"] = "Unknown snak type.",  
["unknown-datatype"] = "Unknown datatype.",  
["unknown-entity-type"] = "Unknown entity type.",  
["unknown-value-module"] = "You must set both value-module and value-function parameters.",  
["value-module-not-found"] = "The module pointed by value-module not found.",  
["value-function-not-found"] = "The function pointed by value-function not found."  
},  
["somevalue"] = "*unknown value*",  
["novalue"] = "*no value*"  
}  
local sortingproperties = {'P585','P571','P580','P569','P582','P570'}  

function versalisering(label, options)  
local versalisering = options.versalisering  
if options.firstversalisering and options.num == 1 then  
versalisering = options.firstversalisering  
end  
if not versalisering or versalisering == '' then  
return label  
end  
if versalisering == 'lcfirst' then  
return mw.getCurrentFrame:preprocess("")  
elseif versalisering == 'ucfirst' then  
return mw.language.getContentLanguage:ucfirst( label )  
elseif versalisering == 'lc' then  
return mw.getCurrentFrame:preprocess("")  
elseif versalisering == 'uc' then  
return mw.getCurrentFrame:preprocess("")  
end  
return label  
end  
function getqualifierbysortingproperty(claim, sortingproperty)  
for k, v in pairs(sortingproperty) do  
if claim.qualifiers and claim.qualifiers[v] and claim.qualifiers[v][1].snaktype == 'value' then  
return claim.qualifiers[v][1].datavalue.value.time  
end  
end  
return nil  
end  

function getDate(claim, options)  
local sortingproperty = sortingproperties  
if type(options.sortingproperty) == 'table' then  
sortingproperty = options.sortingproperty  
elseif type(options.sortingproperty) == 'string' then  
sortingproperty = {options.sortingproperty}  
end  
return getqualifierbysortingproperty(claim, sortingproperty)  
end  

function getDateArb(claim, options)  
local sortingproperty = options.sortingproperty or 'P569'  
if claim.mainsnak.snaktype == 'value' then  
local item = claim.mainsnak.datavalue.value['numeric-id']  
if claim.mainsnak.datavalue.value['entity-type'] == 'item' then  
item = 'Q' .. item  
elseif claim.mainsnak.datavalue.value['entity-type'] == 'property' then  
item = 'P' .. item  
end  
return formatStatements({property = sortingproperty, entityId = item, enbarten = 'ja', sortbytime = 'chronological', noref = 'ja'})  
end  
end  

function comparedates(a, b)  
if a and b then  
return a > b  
elseif a then  
return true  
end  
end  

function sortbyqualifier(claims, options)  

table.sort(claims, function(a,b)  
local timeA = getDate(a, options)  
local timeB = getDate(b, options)  
if options.sortbytime == 'inverted' then  
return comparedates(timeB, timeA)  
else  
return comparedates(timeA, timeB)  
end  
end  
return claims  
end  

function sortbyarb(claims, options)  

table.sort(claims, function(a,b)  
local timeA = getDateArb(a, options)  
local timeB = getDateArb(b, options)  
if options.sortbyarbitrary == 'inverted' then  
return comparedates(timeB, timeA)  
else  
return comparedates(timeA, timeB)  
end  
end  
return claims  
end  

function getLabelFromFallBack( id )  
local entity = getEntityFromId( id )  
for k, v in pairs(fallback) do  
if entity.labels[v] then  
return {value = entity.labels[v].value, language = entity.labels[v].language}  
end  
end  
-- Om inget fallback-språk finns av de i variabeln ovan, så används det först definierade i objektet  
if entity.labels then  
for v, k in pairs(entity.labels) do  
return {value = k.value, language = k.language}  
end  
end  
return {value = '-', language = ''}  
end  

function getEntityFromId( id )  
if id then  
return mw.wikibase.getEntityObject( id )  
else  
return mw.wikibase.getEntityObject  
end  
end  

function getEntityIdFromValue( value )  
if value['entity-type'] == 'item' then  
return 'Q' .. value['numeric-id']  
elseif value['entity-type'] == 'property' then  
return 'P' .. value['numeric-id']  
else  
return formatError( 'unknown-entity-type' )  
end  
end  

function formatError( key )  
return '<span>' .. i18n.errors[key] .. '</span>'  
end  

function formatStatements( options, ref )  
local formattedStatements = {}  
local claims = {}  
if not options.property then  
return formatError( 'property-param-not-provided' )  
end  

if type(ref) == 'table' then -- för de fall där funktionen anropas och alla claims redan finns i en tabell  
claims = ref[options.property] or {}  
else  

--Get entity  
local entity = nil  
if options.entity and type( options.entity ) == "table" then  
entity = options.entity  
else  
entity = getEntityFromId( options.entityId )  
end  

if not entity then  
return '' --TODO error?  
end  

if not entity.claims or not entity.claims[options.property:upper] then  
return '' --TODO error?  
end  

--Format statement and concat them cleanly  
if options.rank == 'best' or not options.rank then  
claims = entity:getBestStatements( options.property:upper )  
elseif options.rank == 'valid' then  
for i, statement in pairs( entity.claims[options.property:upper] ) do  
if statement.rank == 'preferred' or statement.rank == 'normal' then  
table.insert( claims, statement )  
end  
end  
elseif options.rank == 'all' then  
for i, statement in pairs( entity.claims[options.property:upper] ) do  
table.insert( claims, statement )  
end  
else  
for i, statement in pairs( entity.claims[options.property:upper] ) do  
if statement.rank == options.rank then  
table.insert( claims, statement )  
end  
end  
end  
if options.avoidqualifier then  
local claims2 = {}  
for i, statement in pairs( claims ) do  
if not statement.qualifiers or not statement.qualifiers[options.avoidqualifier:upper] then  
table.insert( claims2, statement)  
end  
end  
claims = claims2  
end  
--om det finns vissa statements som har en qualifier som säger "språk = svenska", ta bara med dessa  
--alternativt om det finns statements som har en qualifier som säger "skriptsystem == latinska alfabetet"  
if not options.langpref or options.langpref == '' then  
local claims2 = {}  
for i, statement in pairs( claims ) do  
if statement.qualifiers and statement.qualifiers.P407 then  
for k, v in pairs( statement.qualifiers.P407 ) do  
if v.snaktype == 'value' and v.datavalue.value['numeric-id'] == 9027 then -- Q9027 = 'svenska'  
table.insert( claims2, statement )  
end  
end  
elseif statement.qualifiers and statement.qualifiers.P282 then  
for k, v in pairs( statement.qualifiers.P282 ) do  
if v.snaktype == 'value' and v.datavalue.value['numeric-id'] == 8229 then -- Q8229 = 'latinska alfabetet'  
table.insert( claims2, statement )  
end  
end  
end  
end  
if #claims2 > 0 then  
claims = claims2  
end  
end  
if options.sortbytime == 'chronological' or options.sortbytime == 'inverted' then  
claims = sortbyqualifier(claims, options)  
elseif options.sortbyarbitrary == 'chronological' or options.sortbyarbitrary == 'inverted' then  
claims = sortbyarb(claims, options)  
end  
end  
if options.enbarten and options.enbarten ~= '' and #claims > 1 then  
claims = {claims[1]}  
end  
local statementsraw = {}  
if claims then  
for i, statement in pairs( claims ) do  
options.num = i  
local stat = formatStatement( statement, options )  
local s = stat.value  
local d = stat.datum  
local tf = stat.tifr  
local pr = stat.pr  
if s == '' then s = nil end  
if s then  
if d and options.withdate and options.withdate ~= '' then  
s = s .. mw.text.tag('small', {}, ' (' .. d .. ')')  
end  
if tf and options.withintervall and options.withintervall ~= '' then  
if options.withintervall == 'gift' then  
s = s .. mw.text.tag('br') .. mw.text.tag('small', {}, '(g. ' .. tf .. ')')  
else  
s = s .. mw.text.tag('small', {}, ' (' .. tf .. ')')  
end  
end  

if options.getsimpleproperty == 'född' and pr and pr ~= '' then  
s = s .. ' ' .. mw.text.tag('small', {}, '(f. ' .. pr .. ')')  
end  
if type(ref) == 'table' or (options.noref and options.noref ~='') then --Inte leta efter referenser om själva anropet görs från en referens  
table.insert( formattedStatements, s )  
else  
local t = formatReferences( statement, options )  
stat.ref = t  
table.insert( formattedStatements, s .. t )  
end  
end  
table.insert(statementsraw, stat)  
end  
end  
local tot = mw.text.listToText( formattedStatements, options.separator, options.conjunction )  
if tot == '' then tot = nil end  
if options.raw and options.raw ~= '' then  
return statementsraw  
end  
return tot  
end  
function formatReferences( statement, options )  
local reference = {}  
if statement.references then  
local cite = require('Modul:Cite')  
for i, ref in pairs(statement.references) do  
local items, s = {}, nil  
if ref.snaks then  
if ref.snaks.P248 then  
for j, prop in pairs(ref.snaks.P248) do  
table.insert(items, 'Q' .. prop.datavalue.value['numeric-id'])  
end  
end  
s = cite.citeitem( items, ref.snaks, options )  
if s == '' or not s then  
s = 'Källangivelsen på Wikidata använder propertys som inte känns igen av Modul:Cite'  
end  
end  
table.insert(reference, mw.getCurrentFrame:extensionTag( 'ref', s, {name = ref.hash} ) )  
end  
end  
return table.concat(reference)  
end  
function formatStatement( statement, options )  
if statement.type == 'statement' then  
local s = formatSnak( statement.mainsnak, options )  
if statement.qualifiers then  
if statement.qualifiers.P585 then  
s.datum = formatStatements({property = "P585", enbarten = 'true', noref = 'true', modifytime = options.modifyqualifiertime}, statement.qualifiers)  
end  
if statement.qualifiers.P574 then  
s.dateoftaxpub = formatStatements({property = "P574", enbarten = 'true', noref = 'true', modifytime = options.modifyqualifiertime}, statement.qualifiers)  
end  
if statement.qualifiers.P405 then  
local auktorer = {}  
for i, j in pairs(statement.qualifiers.P405) do  
if j.snaktype == 'value' then  
local item = 'Q' .. j.datavalue.value['numeric-id']  
local auktorsnamn = formatStatements({property = "P428", entityId = item, noref = 'ja', enbarten = 'ja'})  
if auktorsnamn and auktorsnamn ~= '' then  
table.insert(auktorer, formatEntityId(item, {label = auktorsnamn}).value)  
else  
table.insert(auktorer, formatEntityId(item, {}).value)  
end  
end  
end  
s.auktor = mw.text.listToText(auktorer, ', ', ' & ')  
end  
if statement.qualifiers.P580 or statement.qualifiers.P582 then  
local f = formatStatements({property = "P580", enbarten = 'true', noref = 'true', modifytime = options.modifyqualifiertime}, statement.qualifiers) or ''  
local t = formatStatements({property = "P582", enbarten = 'true', noref = 'true', modifytime = options.modifyqualifiertime}, statement.qualifiers) or ''  
s.tifr = f .. '–' .. t  
end  
end  
return s  
elseif not statement.type then  
return formatSnak( statement, options )  
end  
return {value = formatError( 'unknown-claim-type' )}  
end  

function formatSnak( snak, options )  
if snak.snaktype == 'somevalue' then  
if options.somevalue then  
if options.somevalue == '' then  
return nil  
else  
return {value = options.somevalue}  
end  
end  
return {value = i18n['somevalue']}  
elseif snak.snaktype == 'novalue' then  
if options.novalue then  
if options.novalue == '' then  
return nil  
else  
return {value = options.novalue}  
end  
end  
return {value = i18n['novalue']}  
elseif snak.snaktype == 'value' then  
local s = formatDatavalue( snak.datavalue, options, snak.datatype )  
if s.item and options.getsimpleproperty and options.getsimpleproperty ~= * and options.getproperty and options.getproperty ~= * then  
local pr = formatStatements({property = options.getproperty, entityId = s.item, enbarten = options.getenbarten, noref = 'ja', modifytime = options.getmodifytime, raw = options.getraw})  
if pr then s.pr = pr end  
end  
return s  
else  
return {value = formatError( 'unknown-snak-type' )}  
end  
end  

function formatDatavalue( datavalue, options, datatype )  
--Use the customize handler if provided  
if options['value-module'] or options['value-function'] then  
if not options['value-module'] or not options['value-function'] then  
return {value = formatError( 'unknown-value-module' )}  
end  
local formatter = require ('Module:' .. options['value-module'])  
if not formatter then  
return {value = formatError( 'value-module-not-found' )}  
end  
local fun = formatter[options['value-function']]  
if not fun then  
return {value = formatError( 'value-function-not-found' )}  
end  
return {value = fun( datavalue.value, options )}  
end  

--Default formatters  
if datatype == 'wikibase-item' then  
local s = formatEntityId( getEntityIdFromValue( datavalue.value ), options )  
s.item = getEntityIdFromValue( datavalue.value )  
return s  

elseif datatype == 'string' or datatype == 'commonsMedia' then  
if options.pattern and options.pattern ~= '' then  
if options.pattern == "auktoritetsdata" then  
local patter = formatStatements( {property = "P1630", entityId = options.property, enbarten = 'true', noref = 'true' })  
return {value = formatFromPattern( datavalue.value, {pattern = patter} )}  
elseif options.pattern == "auktoritetsdata2" then  
local patter = formatStatements( {property = "P1630", entityId = options.property, enbarten = 'true', noref = 'true' })  
return {value = '[' .. formatFromPattern( datavalue.value, {pattern = patter} ) .. ' ' .. datavalue.value .. ']' }  
else  
return {value = formatFromPattern( versalisering(datavalue.value, options), options )}  
end  
else  
return {value = versalisering(datavalue.value, options), label = datavalue.value}  
end  

elseif datatype == 'time' then  
local Time = require 'Module:Time'  
local tid = Time.newFromWikidataValue( datavalue.value ):toHtml  
if options.modifytime == 'longdate' then  
local mall = ''  
if datavalue.value.precision >= 11 then  
mall = ''  
tid = mw.getCurrentFrame:preprocess(mall)  
elseif datavalue.value.precision == 10 then  
mall = ''  
tid = mw.getCurrentFrame:preprocess(mall)  
elseif datavalue.value.precision == 9 then  
mall = ''  
tid = mw.getCurrentFrame:preprocess(mall)  
end  
elseif options.modifytime == 'Y' then  
local mall = ''  
tid = mw.getCurrentFrame:preprocess(mall)  
end  
return {value = tid}  

elseif datatype == 'globecoordinate' then  
local GlobeCoordinate = require 'Module:GlobeCoordinate'  
return {value = GlobeCoordinate.newFromWikidataValue( datavalue.value ):toHtml}  

elseif datatype == 'quantity' then  
local amount, unit, cat = datavalue.value.amount, datavalue.value.unit, nil  
if unit then  
unit = unit:match('Q%d+')  
end  

local number = formatera.newFromWikidataValue(datavalue.value)  

local unitraw = unit  
if unit then  
-- Kontrollerar om det finns någon förkortning för denna 'unit'  
local lab = options.label or formatStatements({property = 'P558', entityId = unit, enbarten = 'true', langpref = options.langpref, noref = 'true'})  
if lab and ( not options.nounitshort or options.nounitshort == '' ) then  
local s = formatEntityId( unit, {label = lab, nolink = (options.nounitlink or options.nolink) })  
unit = s.value  
cat = s.cat  
else -- om det inte finns en förkortning  
local s = formatEntityId( unit, {nolink = options.nounitlink})  
unit = s.value  
cat = s.cat  
end  
end  
return {value = number .. ' ' .. (unit or ''), amount = amount, unit = unit, unitraw = unitraw, cat = cat}  

elseif datatype == 'url' then  
if options.label and options.label ~= '' then  
return {value = '[' .. datavalue.value .. ' ' .. options.label .. ']'}  
else  
return {value = datavalue.value}  
end  

elseif datavalue.type == 'monolingualtext' then  
return {value = mw.text.tag('span', {title = mw.language.fetchLanguageName(datavalue.value.language, 'sv')}, datavalue.value.text)}  

else  
return {value = formatError( 'unknown-datatype' )}  
end  
end  

function formatEntityId( entityId, options )  
local label = options.label or mw.wikibase.label( entityId )  
if label == '' then  
label = mw.wikibase.label( entityId ) or nil  
end  

local link = mw.wikibase.sitelink( entityId )  

if link and (not options.nolink or options.nolink == '') then  
if label and label ~= '' then  
return {value = * .. versalisering(label, options) .. *, label = label }  
else  
return {value = ':' .. versalisering(link, options) .. '', label = link }  
end  
else  
if label then  
return {value = versalisering(label, options), label = label}  
else  
local s = getLabelFromFallBack( entityId )  
local l = mw.language.fetchLanguageName(s.language, 'sv')  
if not l or l == '' then  
l = 'okänt språk'  
end  
if s then  
return {value = mw.text.tag('span', {title = l}, versalisering(s.value, options) ), cat = 'med labels på ' .. l, label = s.value }  
end  
end  
return {value = entityId, cat = 'som har labels med Qid', label = entityId}  
end  
end  

function formatFromPattern( str, options )  
return mw.ustring.gsub( options.pattern, '$1', str ) .. '' --Hack to get only the first result of the function  
end  

local p = {}  

function p.formatEntityId( entityId, options )  
return formatEntityId( entityId, (options or {}) )  
end  

function p.formatStatements( , key )  
local args = .args  

--If a value if already set, use it  
if args.value and args.value ~= '' then  
return args.value  
end  
return formatStatements( .args, key )  
end  

function p.formatStatementsFromLua( options, key )  
--If a value if already set, use it  
if options.value and options.value ~= '' then  
return options.value  
end  
local s = formatStatements( options, key )  
if s == '' then  
s = nil  
end  
return s  
end  

-- Return the site link (for the current site) for a given data item.  
function p.getSiteLink  
if .args[1] == nil then  
entity = mw.wikibase.getEntityObject  
if not entity then  
entity = mw.wikibase.getEntityObject(.args[1])  
end  
id = entity.id  
else  
id = .args[1]  
end  

return mw.wikibase.sitelink( id )  
end  

-- This is used to get the TA98 (Terminologia Anatomica first edition 1998) values like 'A01.1.00.005' (property P1323)  
-- which are then linked to http://www.unifr.ch/ifaa/Public/EntryPage/TA98%20Tree/Entity%20TA98%20EN/01.1.00.005%20Entity%20TA98%20EN.htm  
-- uses the newer mw.wikibase calls instead of directly using the snaks  
-- formatPropertyValues returns a table with the P1323 values concatenated with ", " so we have to split them out into a table in order to construct the return string  
p.getTAValue = function  
local ent = mw.wikibase.getEntityObject  
local props = ent:formatPropertyValues('P1323')  
local out = {}  
local t = {}  
for k, v in pairs(props) do  
if k == 'value' then  
t = mw.text.split( v, ", ")  
for k2, v2 in pairs(t) do  
out[#out + 1] = ".. string.sub(v2, 2) .. "%20Entity%20TA98%20EN.htm " .. v2 .. ""  
end  
end  
end  
ret = table.concat(out, "  
")  
if #ret == 0 then  
ret = "Invalid TA"  
end  
return ret  
end  

return p