# Module:Cite

-- Displays bibliographic metadata from Wikidata  

local p = {}  
local wikidata = require('Module:Wikidata')  
local linguistic = require('Module:Linguistic')  
local fb = require('Module:Fallback')  

local function formatpage(page, lang)  
-- same text for singular and plural, most of the time, they can be distinguished by the presence of a "-" but that does not always work, see Q11927173  
if not page then  
return nil  
end  
return fb._langSwitch({ -- singular  
de = 'S. ' .. page,  
en = 'p. ' .. page,  
fr = 'p. ' .. page,  
nb = 's. ' .. page,  
nn = 's. ' .. page,  
}, lang)  
end  

local function getauthor(item, lang)  
return wikidata.formatStatements{entity=item, property = 'P50', lang=lang}  
end  

local function getauthorstring(item, lang)  
return wikidata.formatStatements{entity=item, property = 'P2093', lang=lang}  
end  

local function getISBN(item, lang)  
local ISBN = wikidata.formatStatements{entity = item, property = 'P212', lang=lang, numval = 1}  
if ISBN then  
return 'ISBN ' ..ISBN  
end  
end  

local function getLink(item, lang)  
local links = wikidata.formatStatements{entity = item, property = 'P854', numval = 1, lang=lang}  
if links then  
return fb._langSwitch({  
de = '[' .. links .. ' online]',  
en = '[' .. links .. ' read online]',  
fr = '[' .. links .. ' lire en ligne]',  
nb = '[' .. links .. ' les online]',  
nn = '[' .. links .. ' les online]',  
}, lang)  
end  
end  

local function getVolume(item, lang)  
local volume = wikidata.formatStatements{entity = item, property = 'P478', numval = 1, lang=lang}  
if volume then  
return fb._langSwitch({  
de = 'Band ' .. volume,  
en = 'vol. ' .. volume,  
}, lang)  
end  
end  

local function getDoi(item, lang)  
local doi = wikidata.formatStatements({entity=item, property = 'P356', numval = 1, lang=lang}) -- what to do if several value  
if not doi then  
return nil  
end  
return '<small>' .. 'doi: .. doi .. ' ' .. doi .. '' .. '</small>' -- needs i18n ?  
end  

local function getPmid(item, lang)  
local pmid = wikidata.formatStatements({entity=item, property = 'P698', numval = 1, lang=lang}) -- what to do if several values  
if not pmid then  
return nil  
end  
return '<small> PubMed ID: .. pmid .. ' ' .. pmid .. ' </small>' -- needs i18n ?  
end  

local function getPmcid(item, lang)  
local pmcid = wikidata.formatStatements({entity=item, property = 'P932', numval = 1, lang=lang}) -- what to do if several values  
if not pmcid then  
return nil  
end  
return '<small> PubMed Central ID: .. pmcid .. ' ' .. pmcid .. ' </small>' -- needs i18n ?  
end  

local function getArXivID(item, lang)  
local arxivid = wikidata.formatStatements({entity=item, property = 'P818', numval = 1, lang=lang}) -- what to do if several values  
if not arxivid then  
return nil  
end  
return '<small> arXiv ID: .. arxivid .. ' ' .. arxivid .. ' </small>' -- needs i18n ?  
end  

local function getEditor(item, lang)  
local editortable = wikidata.getClaims({entity=item, property='P98'})  
if not editortable then  
return nil  
end  
local editor = wikidata.formatStatements({entity=item, property='P98', lang=lang}) -- should have a "formatClaims" function to avoid double work  
if #editortable > 1 then return  
fb._langSwitch({ --plural  
de = editor .. ' (Hrsg.)',  
en = editor .. ' (eds.)',  
nb = editor .. ' (red.)',  
nn = editor .. ' (red.)',  
}, lang)  
else  
return fb._langSwitch({ -- singular  
de = editor .. ' (Hrsg.)',  
en = editor .. ' (ed.)',  
nb = editor .. ' (red.)',  
nn = editor .. ' (red.)',  
}, lang)  
end  

end  

local function getedition(item, lang)  
local ednumber = wikidata.formatStatements({entity=item, property = 'P393', lang=lang, numval = 1})  
if not ednumber then  
return nil  
end  
local ord = require('Module:Ordinal')._ordinal  
return fb._langSwitch({  
de = ednumber .. '. Auflage',  
en = ord{ednumber, lang = 'en'} .. ' edition',  
fr = ord{ednumber, lang = 'fr'} .. ' édition',  
nb = ord{ednumber, lang = 'nb'} .. ' utgave',  
nn = ord{ednumber, lang = 'nn'} .. ' utgave',  
}, lang)  
end  

local function getarticletitle(item, lang)  
local title = wikidata.formatStatements({entity=item, property = 'P1476', lang=lang}) or wikidata.formatStatements({entity=item, property = 'P357', lang=lang})  
if not title then  
return '' .. item.id .. ' (no title property provided!)'  
end  
return fb._langSwitch({  
de = '„' .. * .. title .. * .. '“',  
en = '"' .. * .. title .. * .. '"',  
fr = '«' ..* .. title .. * .. '»',  
nb = '«' ..* .. title .. * .. '»',  
nn = '«' ..* .. title .. * .. '»',  
} , lang)  
end  

local function getbooktitle(item, lang)-- needs i18n some languages do not use this format  
local title = wikidata.formatStatements({entity=item, property = 'P1476', lang=lang}) or wikidata.formatStatements({entity=item, property = 'P357', lang=lang})  
if not title then  
return '' .. item.id .. ' (no title property provided!)'  
end  
return '<i>' .. * .. title .. * .. '</i>'  
end  

local function getissue(item, lang)  
local issue = wikidata.formatStatements({entity=item, property = 'P433', numval = 1, lang=lang}) -- what to do if several values  
if not issue then  
return nil  
end  
return 'iss. ' .. issue -- needs i18n  
end  

local function getArticleID(item, lang)  
local articleid = wikidata.formatStatements({entity=item, property = 'P2322', numval = 1, lang=lang}) -- what to do if several values  
if not articleid then  
return nil  
end  
return '<small> article ID: ' .. articleid .. '</small>' -- needs i18n  
end  

local function getpublisher(item, lang)  
return wikidata.formatStatements({entity=item, property = 'P123', lang=lang})  
end  

local function getpublishdate(item, lang)  
return wikidata.formatStatements({entity=item, property = 'P577', lang=lang})  
end  

local function geturl(item, lang)  
return wikidata.formatStatements({entity=item, property = 'P854', lang=lang})  
end  

local function getlicense(item, lang)  
return wikidata.formatStatements{entity=item, property = 'P275', lang=lang}  
end  

local function getjournal(item, lang) -- get the title property rather than the label  
local journal = wikidata.getClaims({entity = item, property = 'P1433', exlcudespecial = true})  
if not journal then  
return nil  
end  
if #journal > 1 then  
return "error, source has too much publishing info"  
end  
local journaltitle  
local journalid = 'Q' .. journal[1].mainsnak.datavalue.value["numeric-id"]  
-- find higher work (if any; for example Q19302303)  
local journallink = wikidata.formatStatements({item = journalid , property = 'P1433', lang=lang})  
if journallink then  
return journallink  
else  
journaltitle = wikidata._getLabel(journalid)  
return '<i>' .. journaltitle .. '</i>'  
end  
end  

local function citebook(item, lang, page)  
local publishdate = getpublishdate(item, lang)  
local author = getauthor(item, lang)  
local authorstring = getauthorstring(item, lang)  
local editor = getEditor(item, lang)  
local title = getbooktitle(item, lang)  
local publisher = getpublisher(item, lang)  
local edition = getedition(item, lang)  
local isbn = getISBN(item, lang)  
local doi = getDoi(item, lang)  
local pmid = getPmid(item, lang)  
local pmcid = getPmcid(item, lang)  
local arxivid = getArXivID(item, lang)  
local link = getLink(item, lang)  
local volume = getVolume(item, lang)  
local pagenumber = formatpage(page, lang)  
local license = getlicense(item, lang)  

local fields = {}  
table.insert(fields, author)  
table.insert(fields, authorstring)  
table.insert(fields, editor)  
table.insert(fields, title)  
table.insert(fields, edition)  
table.insert(fields, volume)  
table.insert(fields, publisher)  
table.insert(fields, publishdate)  
table.insert(fields, pagenumber)  
table.insert(fields, isbn)  
table.insert(fields, doi)  
table.insert(fields, pmid)  
table.insert(fields, pmcid)  
table.insert(fields, arxivd)  
table.insert(fields, link)  
table.insert(fields, license)  
return linguistic.conj(fields, lang, "citation_comma")  
end  

local function citearticle(item, lang, page)  
local author = getauthor(item, lang)  
local authorstring = getauthorstring(item, lang)  
local title = getarticletitle(item, lang)  
local publisher = getpublisher(item, lang)  
local publishdate = getpublishdate(item, lang)  
local pagenumber = formatpage(page, lang)  
local journal = getjournal(item, lang)  
local issue = getissue(item, lang)  
local articleid = getArticleID(item, lang)  
local publishdate = getpublishdate(item, lang)  
local doi = getDoi(item, lang)  
local pmid = getPmid(item, lang)  
local pmcid = getPmcid(item, lang)  
local arxivid = getArXivID(item, lang)  
local link = getLink(item, lang)  
local volume = getVolume(item, lang)  
local pagenumber = formatpage(page, lang)  
local license = getlicense(item, lang)  

local fields = {}  
table.insert(fields, author)  
table.insert(fields, authorstring)  
table.insert(fields, title)  
table.insert(fields, publisher)  
table.insert(fields, journal)  
table.insert(fields, volume)  
table.insert(fields, issue)  
table.insert(fields, articleid)  
table.insert(fields, publishdate)  
table.insert(fields, pagenumber)  
table.insert(fields, doi)  
table.insert(fields, pmid)  
table.insert(fields, pmcid)  
table.insert(fields, arxivid)  
table.insert(fields, link)  
table.insert(fields, license)  
return linguistic.conj(fields, lang, "citation_comma")  
end  

function p.citeitem(item, lang, page)  
if not item then return nil end  
if type(item) == 'string' then  
item = mw.wikibase.getEntityObject(item)  
end  
if not item then  
return "invalid item id"  
end  
if wikidata.getClaims({entity = item, property = 'P1433'}) then -- if item has "edition of" is a book, else an article, needs a better solution  
return citearticle(item, lang, page)  
else  
mw.log('Citing as book')  
return citebook(item, lang, page)  
end  
end  

function p.cite  
local lang = .args.lang  
if not lang or lang == '' then  
lang = :preprocess('')  
end  
local page = .args.page  
if page == '' then  
page = nil  
end  
return p.citeitem(.args.item, lang, page)  
end  

function p.reflist  
local list = mw.text.split( .args[1], ' ')  
local lang = .args.lang  
if not lang or lang == '' then  
lang = :preprocess('')  
end  
local str = ''  
for i, j in pairs(list) do  
str = str .. '<li> ' .. p.citeitem(mw.text.trim(j),lang) .. '</li>'  
end  
return str  
end  

return p