Vai al contenuto

Modulo:Autore

Da Wikisource.

Questo modulo serve al {{Autore}} per generare l'incipit e le categorie delle pagine in cui è utilizzato, integrando informazioni da Wikidata quando possibile.


-- elemento su Wikidata
local item = mw.wikibase.getEntityObject()
local c = require('Modulo:Common')
local d = require('Modulo:Date')
local controlloAutorita = require('Modulo:Controllo di autorità')
local p = {}

-- lingua predefinita
local lang = mw.language.getContentLanguage()

local attrs = {
	nome = 'Nome',
	cognome = 'Cognome',
	professioneNazionalita = 'Professione e nazionalità'
}

function p.autodetect(frame)
	local aut = frame:getParent().args[1]
	local t = mw.title.getCurrentTitle().text
	if aut == nil or aut == '' then
		local m = string.match(t,'^Libri di (.+)$')
		if m == nil then
			m = string.match(t,'^Testi di (.+)$')
		end
		if m == nil then
			m = string.match(t,'in cui è citato (.+)$')
		end
		if m ~= nil then
			return m
		end
	end
	return aut
end

function p.dato(frame)
	local page = mw.title.new(frame:getParent().args[1], 102)
	local c = string.gsub(page:getContent(), '^(.*%{%{%s*[Aa]utore)(\n*%|.-%}%}).*$', '{{DatoAutore/dato|dato='..frame:getParent().args[2]..'%2')
	return frame:preprocess(c)
end

function p.prendiDato(frame)
	return frame:getParent().args[attrs[frame:getParent().args.dato]]
end

-- controllo di autorita'
function cda()
	if item then return controlloAutorita.box(item) end
end

-- stringa da restituire
local output = ''
local outputCat = '' --le categorie le metto qui, per tenerle separate e metterle poi in fondo al testo generato

function add(str)
	output = output..str
end

-- aggiunge una categoria (solo in ns Autore)
function addCat(name)
	if c.isNSAutore() then
		outputCat = outputCat .. c.category(mw.text.trim(name))
	end
end

-- richiama un template che ha il compito di aggiungere una o più categorie (solo in ns Autore)
function addTmp(title, args)
	if c.isNSAutore() then
		outputCat = outputCat .. c.template(title, args)
	end
end

--ritorna true se autore umano, false altrimenti
function p.isHuman()
	return c.instanceof(5)
end

--data una stringa di solo testo contenente giono e mese, ritorna il link a quel giorno e mese
function linkGiornoMese(giornoMese)
	if giornoMese then return c.template('DataGiorno', {giornoMese} )
	else return '' end
end

--data una stringa di solo testo contenente l'anno, ritorna il link a quell'anno
function linkAnno(anno)
	if anno then return c.template('Autore/Anno', {anno} )
	else return '' end
end

--data una stringa di solo testo contenente il secolo, ritorna il link a quel secolo
function linkSecolo(secolo)
	local stringa = ''
	if secolo then 
		for sec in string.gmatch(secolo, '([^/]+)') do
			if stringa ~= '' then
				stringa = stringa .. '/'
			end
			local catname = 'Autori del '
			if sec == 'Antichità' then
				catname = 'Autori dell\''
			end
			stringa = stringa .. c.category(catname..sec, sec, true)
		end
	end
	return stringa
end

-- crea un collegamento a una categoria (non vuota) relativa all'autore
function catLink(cat, icon)
	local fcat = mw.ustring.format(cat, nomeAutore)
	if c.pagesInCat(fcat) > 0 then
		add('<div>[[File:'..(icon or 'Nuvola filesystems folder open.png')..'|20px|alt=Icona categoria]] \'\''
			..c.category(fcat, mw.ustring.format(cat, (args.Nome or '')..' '..(args.Cognome or '')), true)
			..' ('..c.pagesInCat(fcat)..')\'\'</div>')
	end
end

-- l'autore è maschio o femmina?
function p.sesso()
	return c.getLabelFromValue(c.getClaimValue(c.getSingleClaimByProperty('P21')))
end

-- ritorna l'immagine che rappresenta l'autore (la prima, se ce ne sono più di una)
function p.immagine()
	if p.isHuman() then
		return c.getSingleClaimValueByProperty('P18') -- immagine
		or c.getSingleClaimValueByProperty('P94') -- coat of arms image
		or c.getSingleClaimValueByProperty('P41') -- bandiera 
	else
		return c.getSingleClaimValueByProperty('P41') -- bandiera 
		or c.getSingleClaimValueByProperty('P94') -- coat of arms image
		or c.getSingleClaimValueByProperty('P18') -- immagine
	end
end

function p.attivita(full)
	local list = {}
	for str in mw.text.gsplit(full, '/', true) do
		table.insert(list, lang:lcfirst(str))
	end
	return mw.text.listToText(list)
end

--ritorna una lista di note <ref>testo</ref> leggendo P854 (Reference URL) e P248 (stated in)
function getRefList(references)
	refList = ''
	local n = 0;
	for i, r in pairs(references or {}) do
		if n < 5 and r.snaks then
			local refURL = r.snaks.P854
			local refStatedIn = r.snaks.P248
			local refLink, refText, refLabel

			if refStatedIn and not c.empty(refStatedIn) then
				source = 'Q'..refStatedIn[1].datavalue.value["numeric-id"]
				refLabel = mw.wikibase.label(source)
				if refLabel ~= '0' then
					refText = refLabel
				end
				if source == 'Q1128537' then
					dbiLink = c.getSingleClaimValueByProperty('P1986')
					if dbiLink then
						refText = '[http://www.treccani.it/enciclopedia/' .. dbiLink .. '_(Dizionario-Biografico) ' .. mw.wikibase.label(source) .. ']'
					end
				elseif source == 'Q30237471' then
					dbfLink = c.getSingleClaimValueByProperty('P7203')
					if dbfLink then
						refText = '[http://www.dizionariobiograficodeifriulani.it/' .. dbfLink .. ' ' .. mw.wikibase.label(source) .. ']'
					end
				elseif source == 'Q36578' then
					gndLink = c.getSingleClaimValueByProperty('P227')
					if gndLink then
						refText = '[http://d-nb.info/gnd/' .. gndLink .. ' ' .. mw.wikibase.label(source) .. ']'
					end
				elseif source == 'Q19938912' then
					bnfLink = c.getSingleClaimValueByProperty('P268')
					if bnfLink then
						refText = '[http://catalogue.bnf.fr/ark:/12148/cb' .. bnfLink .. ' Bibliothèque nationale de France]'
					end
				elseif source == 'Q576951' then
					sbnLink = c.getSingleClaimValueByProperty('P396')
					if sbnLink then
						refText = '[https://opac.sbn.it/nome/' .. sbnLink .. ' Servizio Bibliotecario Nazionale]'
					end
				elseif source == 'Q1201876' then
					olLink = c.getSingleClaimValueByProperty('P648')
					if olLink then
						refText = '[https://openlibrary.org/works/' .. olLink .. ' OpenLibrary]'
					end
				elseif source == 'Q5375741' then
					britLink = c.getSingleClaimValueByProperty('P1417')
					if britLink then
						refText = '[https://www.britannica.com/' .. britLink .. ' Encyclopædia Britannica]'
					end
				elseif source == 'Q237227' then
					brockLink = c.getSingleClaimValueByProperty('P5019')
					if brockLink then
						refText = '[https://brockhaus.de/ecs/enzy/article/' .. brockLink .. ' Brockhaus Enzyklopädie]'
					end
				elseif source == 'Q2629164' then
					isfdbLink = c.getSingleClaimValueByProperty('P1233')
					if isfdbLink then
						refText = '[http://www.isfdb.org/cgi-bin/ea.cgi?' .. isfdbLink .. ' Internet Speculative Fiction Database]'
					end
				elseif source == 'Q23023088' then
					vegeLink = c.getSingleClaimValueByProperty('P2191')
					if vegeLink then
						refText = '[https://www.fantascienza.com/catalogo/NILF' .. vegeLink .. ' Catalogo Vegetti della letteratura fantastica]'
					end
				end

				--cerco l'url della fonte in "described by source" (P1343)
				describedBySource = c.getClaimByPropertyAndValue('P1343', source)
				if describedBySource and describedBySource.qualifiers then
					sourceURL = describedBySource.qualifiers.P854
					if sourceURL and not c.empty(sourceURL) then
						refURL = sourceURL
					end
				end
			end

			if refURL and not c.empty(refURL) then
				if refLabel == nil then
					refLabel = 'Fonte'
				end
				refLink =  refURL[1].datavalue.value
				refText = '['..refLink..' '..refLabel..']'
			end
			
			if refText then
				n = n + 1
				refList = refList .. mw.getCurrentFrame():extensionTag( 'ref', refText, { name = refText } )
			end
		end
	end
	return refList
end

--ritorna le 4 componenti della data formattate, più la stringa finale con i link e l'eventuale "circa"
local function getFormattedDate(value, prima, dopo, isEsatta, refList)
	local data = {
		dayMonth = '',
		decade = '',
		year = '',
		century = '',
		stringa = '',
		esatta = isEsatta,
		calendar = nil,
		precision = nil
	}
 
 	date = d.getDate(value)
 	if date then
 		data.calendar = date.calendar
 		data.precision = date.precision
 		
		if date.precision >= 9 and date.precision <= 11 then
			data.year = d.formatYear(date)
		end
        
		--precision: 7 - century, 8 - decade, 9 - year, 10 - month, 11 - day
		if date.precision == 7 then
			data.stringa = linkSecolo(d.formatCentury(date))									-- "XVI secolo"
		elseif date.precision == 8 then
			data.decade = d.formatDecade(date)
			data.stringa = data.decade .. ' del ' .. linkSecolo(d.formatCentury(date))			-- "anni 50 del XVI secolo"
		elseif date.precision == 9 then
			data.stringa = linkAnno(d.formatYear(date))											-- "1556"; "24 a.C."
		elseif date.precision == 10 then
			data.dayMonth = d.formatMonth(date)
			data.stringa = linkGiornoMese(data.dayMonth) .. ' ' .. linkAnno(d.formatYear(date))		-- agosto 1556
        elseif date.precision == 11 then
			data.dayMonth = d.formatDayMonth(date)
			data.stringa = linkGiornoMese(data.dayMonth) .. ' ' .. linkAnno(d.formatYear(date))		-- 1° agosto 1556
		end

		--mostra il tipo di calendario (solo per precisioni almeno di mese, e solo per il periodo in cui alcuni usavano ancora il giuliano)
		if date.precision >= 10 and date.year and date.year >= 1582 and date.year <= 1924 then
			data.stringa = data.stringa .. '<sup>' .. d.linkCalendar(value.calendarmodel) .. '</sup>'
		end
		
		--la frasetta prima e dopo la data
		if prima then data.stringa = prima .. ' ' .. data.stringa end
		if dopo  then data.stringa = data.stringa .. ' ' .. dopo end
		
		--aggiungo le note (TODO: per il momento escludo il ns Opera per evitare le note "inutili", da vedere come sistemare meglio)
		if c.notEmpty(data.stringa) and c.isNSAutore() then
			data.stringa = data.stringa .. getRefList(refList)
		end
		
		--categoria di controllo per date < 15 Oct 1582 ma segnate come GREGORIANE
		if date.precision >= 10 and date.year and date.year <= 1582 and date.calendar == 'gregoriano' then
			if date.year < 1582 or tonumber(date.month) < 10 or 
				(date.precision == 11 and tonumber(date.month) == 10 and tonumber(date.day) < 15) then
				addCat('Autori con date fino al 1582 segnate come gregoriane')
			end
		end
	end
    return data
end

--ritorna la lista di tutte le date per la proprietà indicata (P569=nascita, P570=morte), con la stringa finale
function getAllDates(property)
	local list = {}		--lista di tutte le date
	local stringa		--stringa con il testo finale con i link, e concatenato da "o" oppure "tra il e il"
	
	claims = c.sortClaimsByDate(c.getClaimsByProperty(property) or {})
	for index, claim in pairs(claims) do
		local val = c.getClaimValue(claim)
		local preStringa = ''
		
		local sourceAccuracy = c.getQualifierValueFromClaim(claim, 'P1480')
		local circa
		-- non mostrare l'inutile "calendario non specificato, si presume gregoriano" e altre amenità simili
		if sourceAccuracy and sourceAccuracy.id ~= 'Q26877139' and sourceAccuracy.id ~= 'Q26877143' and sourceAccuracy.id ~= 'Q27055388' and sourceAccuracy.id ~= 'Q18195782' then
			circa = c.getLabelFromValue(sourceAccuracy);
		end
		local ante = c.getQualifierValueFromClaim(claim, 'P1326')
		local post = c.getQualifierValueFromClaim(claim, 'P1319')
		
		if val then
			preStringa = getFormattedDate(val, nil, circa, (circa == nil), nil).stringa .. ', '
		end
		
		if ante and post then
			--caso "tra il"
			local list = {}
			table.insert(list, getFormattedDate(post, nil, nil, true, nil))
			table.insert(list, getFormattedDate(ante, nil, nil, true, claim.references))
			stringa = preStringa .. 'tra il ' .. list[1].stringa .. ' e il ' .. list[2].stringa

			--in questo caso ritorniamo direttamente questa coppia di date con la stringa "tra il"
			return list, stringa
		elseif ante ~= nil and post == nil then
			--caso ante
			table.insert(list, getFormattedDate(ante, preStringa .. 'prima del', nil, false, claim.references))
		elseif ante == nil and post ~= nil then
			--caso post
			table.insert(list, getFormattedDate(post, preStringa .. 'dopo il', nil, false, claim.references))
		elseif val then
			--caso normale
			table.insert(list, getFormattedDate(val, nil, circa, (circa == nil), claim.references))
		end
	end

	--se ci sono 2 date con stesso anno ma una più precisa dell'altra (cioè anche giorno/mese), allora nella stringa mostriamo solo quella più precisa
	if c.size(list) == 2 and
		list[1].precision >= 9 and list[2].precision >= 9 and list[1].year == list[2].year and list[1].calendar == list[2].calendar and list[1].precision ~= list[2].precision then
			if list[1].precision > list[2].precision then
				stringa = list[1].stringa
			else
				stringa = list[2].stringa
			end
	else
		--a questo punto va costruita la stringa finale con gli "o" tra le varie date
		local stringaList = {}
		for i, e in pairs(list) do 
			if c.notEmpty(e.stringa) then table.insert(stringaList, e.stringa) end
		end
		stringa = mw.text.listToText(stringaList, ' o ', ' o ')
	end
	
	--default se non ci sono valori
	if stringa == '' then stringa = '...' end
	
	return list, stringa
end

--ritorna tutte le date di nascita (o di fondazione/creazione)
function getBirthDates()
	local dates, stringa = getAllDates('P569') --data di nascita
	if c.empty(dates) then
		dates, stringa = getAllDates('P571') --data di fondazione
	end
	return dates, stringa
end

--ritorna tutte le date di morte (o di scioglimento/chiusura)
function getDeathDates()
	local dates, stringa = getAllDates('P570') --data di morte
	if c.empty(dates) then
		dates, stringa = getAllDates('P576') --data di scioglimento
	end
	return dates, stringa
end

--ritorna le date del floruit
function getFloruitDates()
	--property floruit
	local dates, stringa = getAllDates('P1317')
	if c.size(dates) == 2 then
		stringa = 'tra il '..dates[1].stringa..' e il '..dates[2].stringa
	else
		--properties work period start/end
		dateStart, stringaStart = getAllDates('P2031')
		dateEnd, stringaEnd = getAllDates('P2032')
		if c.size(dateStart) == 1 and c.size(dateEnd) == 1 then
			dates = {}
			table.insert(dates, dateStart[1])
			table.insert(dates, dateEnd[1])
			stringa = 'tra il '..stringaStart..' e il '..stringaEnd
		end
	end
	return dates, '\'\'[[:w:Floruit|floruit]]\'\' '..stringa
end

--data una lista di date, ritorna la data più precisa possibile che si possa individuare con certezza, oppure nil
--es: se abbiamo una sola data, senza "circa", ritorna quella
--se abbiamo 2 date, senza "circa", con stesso anno e giorno diverso: ritorna la data col solo anno
function getDataCerta(dates)
	--se c'è una data incerta ritorna nil
	for i, d in pairs(dates) do
		if not d.esatta then return nil	end
	end
	
	--se c'è una sola data che arriva almeno all'anno, ritorna quella
	if c.size(dates) == 1 and dates[1].year ~= '' then
		--se la precisione è inferiore al giorno, ritorna solo l'anno
		if dates[1].precision < 11 then dates[1].dayMonth = nil end
		return dates[1]
	elseif c.size(dates) > 1 then
		--se le diverse date non concordano almeno sull'anno, non c'è una data certa
		local anno = dates[1].year
		for i, d in pairs(dates) do
			if anno ~= d.year then return nil end
		end
		
		local dataCerta = dates[1]
		
		--se le date sono 2, una gregoriana e l'altra giuliana, ritorna la gregoriana
		if c.size(dates) == 2 and dates[1].calendar ~= dates[2].calendar then
			if dates[2].calendar == 'gregoriano' then dataCerta = dates[2] end
			--se la precisione è inferiore al giorno, ritorna solo l'anno
			if dataCerta.precision < 11 then dataCerta.dayMonth = nil end
			return dataCerta
		end
		
		--se ho più date, ritorna solo l'anno
		dataCerta.dayMonth = nil
		return dataCerta
	end
end

--cerca di calcolare i secoli in cui l'autore era attivo, sulla base delle date di nascita/morte o del floruit
function p.getSecoloAttivita()
	--cerca le date di nascita e morte esatte
	local startDates = d.getDatesFromProperty('P569', 'asc')
	local endDates = d.getDatesFromProperty('P570', 'desc')
	
	--oppure cerca le date di fondazione / cessazione
	if c.empty(startDates) then startDates = d.getDatesFromProperty('P571', 'asc') end
	if c.empty(endDates) then endDates = d.getDatesFromProperty('P576', 'desc') end
	local floruitDates = d.getDatesFromProperty('P1317')
	
	--se non ci sono cerca "ante" e "post"
	if c.empty(startDates) then
		ap = d.getAnteOrPostFromProperty('P569')
		if ap then table.insert(startDates, ap) end
	end
	if c.empty(endDates) then
		ap = d.getAnteOrPostFromProperty('P570')
		if ap then table.insert(endDates, ap) end
	end
	if c.empty(startDates) then
		ap = d.getAnteOrPostFromProperty('P571')
		if ap then table.insert(startDates, ap) end
	end
	if c.empty(endDates) then
		ap = d.getAnteOrPostFromProperty('P576')
		if ap then table.insert(endDates, ap) end
	end
	
	--se ancora non trovi nulla cerca work period start/end
	if c.empty(startDates) then startDates = d.getDatesFromProperty('P2031', 'asc') end
	if c.empty(endDates) then endDates = d.getDatesFromProperty('P2032', 'desc') end
	
	mw.log('calcolo il secolo di attivita...')
	mw.log('start: ' .. c.printElement(startDates))
	mw.log('end: ' .. c.printElement(endDates))
	mw.log('floruit: ' .. c.printElement(floruitDates))
	
	local startDate = c.first(startDates)
	local endDate = c.first(endDates)
	if not startDate and endDate then
		startDate = c.deepcopy(endDate)
		startDate = d.addYears(startDate, -25) --ipotizziamo che sia vissuto almeno 25 anni 
	elseif not endDate and startDate then
		endDate = c.deepcopy(startDate)
		--gli autori senza data di morte e nati nel XX secolo si suppongono viventi nel XXI
		if not p.isHuman() or (startDate and startDate.century and startDate.century == 20) then 
			endDate.century = 21
			endDate.year = 2050
		else
			endDate = d.addYears(endDate, 25) --ipotizziamo che sia vissuto almeno 25 anni 
		end
	end
	
	if c.empty(startDate) and not c.empty(floruitDates) then 
		startDate = floruitDates[1]
	else
		if p.isHuman() and startDate and startDate.precision and startDate.precision >= 9 and startDate.year then 
			--supponiamo che un autore non sia "attivo" prima dei 15 anni di eta' + 5 anni di "tolleranza". 
			--(Es. se ha pubblicato dal 1896 al 1950 lo consideriamo solo nel XX secolo)
			startDate = d.addYears(startDate, 20)
		end
	end
	
	if c.empty(endDate) and not c.empty(floruitDates) then
		if #floruitDates > 1 then endDate = floruitDates[2]
		else endDate = floruitDates[1] end
	else
		if p.isHuman() and endDate and endDate.precision and endDate.precision >= 9 and endDate.year then 
			--5 anni di "tolleranza" (se un autore è morto nel 1901 non ha senso considerarlo "del XX secolo")
			endDate = d.addYears(endDate, -5)
		end
	end
	
	local centuries = {}
	if not c.empty(startDate) and not c.empty(endDate) and endDate.century and startDate.century then
		mw.log('start common: ' .. c.printElement(startDate))
		mw.log('end common: ' .. c.printElement(endDate))
		mw.log('secoli: ' .. tostring(startDate.century) .. '-' .. tostring(endDate.century))
		mw.log('secolo di attivita: ' .. tostring(startDate.century))
		
		-- se aggiungendo la tolleranza alla nascita siamo finiti nel secolo successivo alla morte, lo scartiamo
		if startDate.century > endDate.century then
			startDate = endDate
		end
		
		table.insert(centuries, d.formatCentury(startDate))
			
		while #centuries < 10 and (endDate.century ~= startDate.century or endDate.ac ~= startDate.ac) do
			if startDate.ac then
				startDate.century = startDate.century - 1
				if startDate.century == 0 then 
					startDate.ac = false
					startDate.century = 1
				end
			else
				startDate.century = startDate.century + 1
			end
			mw.log('secolo di attivita: ' .. tostring(startDate.century))
			table.insert(centuries, d.formatCentury(startDate))
		end
	end
	return centuries
end

function getSitelinksOrLabelsFromPropertyValues(propertyId, siteId, langCode)
	local claims = c.getClaimsByProperty(propertyId) or {}
	local sitelinksOrLabels = {}
	local found = false
	for _, claim in ipairs(claims) do
		if not found and claim and claim.mainsnak and claim.mainsnak.datavalue then
			local qid = 'Q'..claim.mainsnak.datavalue.value['numeric-id']
			local entity = mw.wikibase.getEntity(qid)
			
			-- check if entity is a "birth house", "museum", "arrondissement", i.e. something which is not a "town"
		local s = c.set{ 'Q19979289', 'Q33506', 'Q1307276', 'Q3947', 'Q16560', 'Q3950', 'Q2087181', 'Q702842', 'Q27686', 'Q23413', 'Q79007', 'Q751876', 'Q2116450', 'Q615980', 'Q2026833', 'Q211690', 'Q1907114', 'Q46124', 'Q21752084', 'Q879050', 'Q16917', 'Q15848826', 'Q7543083', 'Q2845944' }
			if entity.claims then
				local instOf = entity.claims["P31"]
				if instOf then
					for i, cl in pairs(instOf) do
						local pl = 'Q'..cl.mainsnak.datavalue.value['numeric-id']
						if s[pl] then
							local cla = c.first(entity.claims["P276"])					-- location
							if not cla then cla = c.first(entity.claims["P131"]) end	-- located in the administrative territorial entity
							if not cla then cla = c.first(entity.claims["P3842"]) end	-- located in present-day administrative territorial entity
							if cla then
								local value = c.getClaimValue(cla)
								if value and value["numeric-id"] then
									entity = mw.wikibase.getEntity('Q'..value["numeric-id"])
									found = true;
									break;
								end
							end
						end
					end
				end
			end
			
			local sitelinkOrLabel = entity:getSitelink(siteId)
			if not sitelinkOrLabel then
				local itLabel = entity:getLabel(langCode)
				if itLabel then
					langCode = 'it'
					sitelinkOrLabel = itLabel
					isLink = false
				end
			end
			if not sitelinkOrLabel then
				sitelinkOrLabel = entity:getSitelink('enwiki')
				langCode = 'en'
			end
			if not sitelinkOrLabel then
				sitelinkOrLabel = entity:getSitelink('frwiki')
				langCode = 'fr'
			end
			if not sitelinkOrLabel then
				sitelinkOrLabel = entity:getSitelink('eswiki')
				langCode = 'es'
			end
			if not sitelinkOrLabel then
				sitelinkOrLabel = entity:getSitelink('dewiki')
				langCode = 'de'
			end
			local isLink = true
			if not sitelinkOrLabel then
				langCode = 'it'
				sitelinkOrLabel = entity:getLabel(langCode) or entity:getLabel('mul') or entity:getLabel('en') or entity:getLabel('fr') or entity:getLabel('de')
				isLink = false
				if not entity:getLabel(langCode) then
					addCat('Etichetta mancante su Wikidata')
				end
			end
			if sitelinkOrLabel then
				table.insert(sitelinksOrLabels, {text = sitelinkOrLabel, isSitelink = isLink, lang = langCode})
			end
		end
	end
	return sitelinksOrLabels
end

function getPlaceOfBirth()
	local places = getSitelinksOrLabelsFromPropertyValues('P19', 'itwiki', 'it')
	if c.size(places) > 1 then
		addCat('Autori con luogo di nascita incerto')
	elseif c.size(places) == 1 and places[1].isSitelink then
		addCat('Nati a '..places[1].text)
	end
	for k, v in pairs(places) do
		if v.isSitelink then
			places[k] = c.link(v.text, v.text:gsub(' %(%D+%)', ''), v.lang .. ':w')
		else
			places[k] = v.text
			addCat('Autori con luogo di nascita o morte non presente in Wikipedia')
		end
	end
	return c.concat(places, ' o ')
end

function getPlaceOfDeath()
	places = getSitelinksOrLabelsFromPropertyValues('P20', 'itwiki', 'it')
	mw.log('luogo morte: '..c.printElement(places))
	if c.size(places) > 1 then
		addCat('Autori con luogo di morte incerto')
	elseif c.size(places) == 1 and places[1].isSitelink then
		addCat('Morti a '..places[1].text)
	end
	for k, v in pairs(places) do
		if v.isSitelink then
			places[k] = c.link(v.text, v.text:gsub(' %(%D+%)', ''), v.lang .. ':w')
		else
			places[k] = v.text
			addCat('Autori con luogo di nascita o morte non presente in Wikipedia')
		end
	end
	return c.concat(places, ' o ')
end

--funzione che recupera i dati dell'autore, richiamabile anche con un item qualunque
function p.getDatiAutore(autoreItem)
	item = autoreItem or item
	c.setItem(item)
	local dati = {}
	
	--DATI ANAGRAFICI da Wikidata
	dati.nomeCognome = c.getLabel()
	dati.isHuman = p.isHuman()
	dati.gender = p.sesso()
	dati.immagine = p.immagine()
	dati.birthDates, dati.birthStringa = getBirthDates()
	dati.deathDates, dati.deathStringa = getDeathDates()
	dati.birthPlaceList = c.getLabelsFromPropertyValues('P19')
	dati.deathPlaceList = c.getLabelsFromPropertyValues('P20')
	dati.birthPlace = c.concat(dati.birthPlaceList, ' o ')
	dati.deathPlace = c.concat(dati.deathPlaceList, ' o ')
	dati.floruitDates, dati.floruitStringa = getFloruitDates()
	
	--pseudonimo P742
	dati.pseudonimi = c.sublist(c.getClaimValuesByProperty('P742'), 1, 5)
	table.sort(dati.pseudonimi)
	dati.numeroPseudonimi = c.size(dati.pseudonimi)
	dati.stringaPseudonimo = c.concat(dati.pseudonimi, "''', '''", "''' e '''")
	
	--nome reale (birth name) P1477
	dati.nomiReali = c.getClaimValuesByProperty('P1477')
	table.sort(dati.nomiReali)
	dati.stringaNomeReale = c.concat(dati.nomiReali, "''' o '''")
	
	--alias (da cui vanno esclusi i precedenti campi e il nome "principale")
	dati.alias = c.sublist(c.getLabelAndAliases(), 1, 5) --max 5 alias
	c.subtractTable(dati.alias, dati.pseudonimi)
	c.subtractTable(dati.alias, dati.nomiReali)
	c.subtractTable(dati.alias, {dati.nomeCognome})
	table.sort(dati.alias)
	dati.stringaAlias = c.concat(dati.alias, "''', '''", "''' e '''")
	
	--anni di nascita e morte esatti
	dataNascitaCerta = getDataCerta(dati.birthDates)
	dataMorteCerta = getDataCerta(dati.deathDates)
	if dataNascitaCerta then
		dati.annoNascita = dataNascitaCerta.year
		dati.ricorrenzaNascita = dataNascitaCerta.dayMonth
	end
	if dataMorteCerta then
		dati.annoMorte = dataMorteCerta.year
		dati.ricorrenzaMorte = dataMorteCerta.dayMonth
	end
	
	--link al Diz. Biogr. degli Italiani
	dati.dbiLink = c.getSingleClaimValueByProperty('P1986')

	--link a LiberLiber
	dati.liberLiber = c.getSingleClaimValueByProperty('P7208')
	
	return dati
end

function p.autore(frame)
	if frame == nil or frame:getParent() == nil then
		error('Nessun frame rilevato')
	end

	-- parametri passati al template Autore
	args = c.getParameters(frame)

	if args.Wikidata then
		item = mw.wikibase.getEntityObject(args.Wikidata)
		c.setItem(item)
	end
	
	naz = (args['Nazionalità'] or ''):gsub(" naturalizzato ", "/"):gsub(" naturalizzata ", "/"):gsub(",", ""):gsub("-", "/")

	-- nome dell'autore: Nome, Cognome e Disambigua
	local nomeCognome = mw.text.trim((args.Nome or '')..' '..(args.Cognome or ''))
	if nomeCognome == '' then error('Nome autore non valido') end
	
	-- nome UNIVOCO dell'autore: Nome, Cognome e Disambigua
	nomeAutore = mw.text.trim(nomeCognome..' '..(args.Disambigua or ''))

	--cognome, nome (per ordinamenti)
	local cognonome = args.Cognome or ''
	if cognonome ~= '' then cognonome = cognonome ..' , ' end
	cognonome = c.stripAccents( cognonome .. (args.Nome or '') )
	add(c.template('DEFAULTSORT', {cognonome} ))

	local spanDati = mw.html.create('span'):attr('id', 'dati')
	for k, v in pairs(attrs) do
		spanDati:attr('data-'..k, (args[v] or ''))
	end
	add(tostring(spanDati))

	-- DATI ANAGRAFICI
	local secoloAttivita = p.getSecoloAttivita()
	local secolo = c.concat(secoloAttivita, '/')
	mw.log('Secolo di attivita da wikidata: ' .. secolo)
	
	dati = p.getDatiAutore()
	mw.log(c.printElement(dati))
	
	--DATI ANAGRAFICI da Wikidata
	local birthPlace = getPlaceOfBirth()
	local deathPlace = getPlaceOfDeath()
	
	--pseudonimo P742
	local pseudonimi = c.getClaimValuesByProperty('P742')
	c.subtractTable(pseudonimi, {nomeCognome})
	pseudonimi = c.sublist(pseudonimi, 1, 5)
	table.sort(pseudonimi)
	local numeroPseudonimi = c.size(pseudonimi)
	local stringaPseudonimo = c.concat(pseudonimi, "''', '''", "''' e '''")
	
	--nome reale (birth name) P1477
	local nomiReali = c.getClaimValuesByProperty('P1477')
	table.sort(nomiReali)
	local stringaNomeReale = c.concat(nomiReali, "''' o '''")
	
	--alias (da cui vanno esclusi i precedenti campi e il nome "principale")
	local alias = dati.alias
	if (dati.nomeCognome ~= nomeCognome) then
		table.insert(alias, dati.nomeCognome)
	end
	c.subtractTable(alias, pseudonimi)
	c.subtractTable(alias, nomiReali)
	c.subtractTable(alias, {nomeCognome})
	table.sort(alias)
	local stringaAlias = c.concat(alias, "''', '''", "''' e '''")
	
	--inizio CATEGORIE
	
	-- CAT: AUTORI NATI/MORTI NELL'ANNO
	if dati.annoNascita and dati.annoNascita ~= '' then 
		addCat('Nati nel '..dati.annoNascita)
	end
	if c.size(dati.birthDates) > 1 then
		local data1 = dati.birthDates[1]
		local data2 = dati.birthDates[2]
		if c.size(dati.birthDates) > 2 or data1.calendar == data2.calendar then
			if data1.precision >= 9 and data2.precision >= 9 and data1.year == data2.year and data1.precision ~= data2.precision then
				addCat('Autori con date di nascita aventi diversa precisione')
			else
				addCat('Autori con data di nascita incerta')
			end
		end
	end
	if dati.annoMorte and dati.annoMorte ~= '' then 
		addCat('Morti nel '..dati.annoMorte) 
	end
	if c.size(dati.deathDates) > 1 then
		local data1 = dati.deathDates[1]
		local data2 = dati.deathDates[2]
		if c.size(dati.deathDates) > 2 or dati.deathDates[1].calendar == dati.deathDates[2].calendar then
			if data1.precision >= 9 and data2.precision >= 9 and data1.year == data2.year and data1.precision ~= data2.precision then
				addCat('Autori con date di morte aventi diversa precisione')
			else
				addCat('Autori con data di morte incerta')
			end
		end
	end

	if p.isHuman() and dati.ricorrenzaNascita and dati.ricorrenzaNascita ~= '' then
		if dati.ricorrenzaNascita:sub(1, 2) == '8 ' or dati.ricorrenzaNascita:sub(1, 3) == '11 ' then
			addCat("Nati l'"..dati.ricorrenzaNascita)
		else
			addCat('Nati il '..dati.ricorrenzaNascita)
		end
	end
	if p.isHuman() and dati.ricorrenzaMorte and dati.ricorrenzaMorte ~= '' then
		if dati.ricorrenzaMorte:sub(1, 2) == '8 ' or dati.ricorrenzaMorte:sub(1, 3) == '11 ' then
			addCat("Morti l'"..dati.ricorrenzaMorte)
		else
			addCat('Morti il '..dati.ricorrenzaMorte)
		end
	end
		
	-- CAT: AUTORI-INIZIALE
	addCat('Autori')
	local primaLettera = mw.ustring.upper(c.template('Prima lettera', { (args.Cognome or '')..(args.Nome or '') } ))
	addCat('Autori-'..primaLettera)
	
	if dati.gender and dati.gender == 'femmina' then
		addCat('Autrici')
	end
			
	-- CAT: AUTORI OMONIMI (cioè che usano il campo Disambigua per distinguersi da omonimi)
	if args.Disambigua then addCat('Autori omonimi') end

	-- CAT: AUTORI DEL SECOLO
	if secolo == '' then addCat('Autori senza secolo indicato')
	else
		if lang:ucfirst(secolo) == 'Antichità' then addCat('Autori dell\'Antichità')
		else addTmp('Autore/CategorieSecolo', { secolo, cognonome }) end

		-- CAT: AUTORI PER NAZIONALITÀ E SECOLO
		for n in string.gmatch(naz, "([^/]*)") do
			local plur = c.template('Autore/PluraleNazionalità', { n } )
			if plur and plur ~= '' then
				if lang:ucfirst(secolo) == 'Antichità' then
					addCat('Autori '..plur.." dell'Antichità")
				else
					addTmp('Autore/CategorieSecolo', { secolo, cognonome, plur })
				end
			end
		end
	end

	-- CAT: AUTORI PER ATTIVITÀ
	local att = args['Attività']
	if att then
		addTmp('Autore/CategorieAttività', { att, cognonome }) 

		-- CAT: AUTORI PER ATTIVITÀ E SECOLO
		if lang:ucfirst(secolo) == 'Antichità' then
			addTmp('Autore/CategorieAttività', { att, cognonome, 'dell\'Antichità' })
		else
			addTmp('Autore/CategorieAttivitàSecolo', { att, secolo, cognonome })
		end
	else
		addCat('Autori senza attività')
	end 

	-- CAT: AUTORI PER NAZIONALITÀ
	if naz and naz ~= '' then
		mw.log("nazionalità: "..naz)
		for n in string.gmatch(naz, "([^/]*)") do
			if n and n ~= '' then
				local plur = c.template('Autore/PluraleNazionalità', { mw.text.trim(n) } )
				mw.log("plurale nazionalità: "..plur)
				if plur and plur ~= '' then
					addCat('Autori '..plur)
					-- AUTORI PER ATTIVITÀ + NAZIONALITÀ
					if att then addTmp('Autore/CategorieAttività', { att, cognonome, plur }) end
				else
					addCat('Autori di nazionalità non censita')
				end
			end
		end
	else
		addCat('Autori senza nazionalità')
	end

	-- CAT: AUTORI CON/SENZA OPERE
	if (c.pagesInCat('Testi di '..nomeAutore) + c.pagesInCat('Traduzioni di '..nomeAutore)) > 0 then
		addCat('Autori con opere su Wikisource')
	else
		addCat('Autori senza opere su Wikisource')
	end
	
	-- CAT: AUTORI DI TESTI MUSICALI
	if c.pagesInCat('Testi musicati da '..nomeAutore) > 0 then
		addCat('Autori di testi musicali')
	end

	-- CAT: AUTORI CITATI IN OPERE PUBBLICATE
	if c.pagesInCat('Testi in cui è citato '..nomeAutore) > 0 then
		addCat('Autori citati in opere pubblicate')
	elseif c.pagesInCat('Pagine in cui è citato '..nomeAutore) > 0 then
		addCat('Autori citati in pagine non transcluse')
	end

	-- CAT: AUTORI SENZA DATI BIOGRAFICI 
	if ((args['Professione e nazionalità'] or '')..
	    (args['Attività'] or '')..
	    (args['Nazionalità'] or '') ) == '' then
		addCat('Autori senza dati biografici')
	end

	-- CAT: AUTORI VIVENTI
	if dati.annoMorte == nil and tonumber(dati.annoNascita) ~= nil and tonumber(dati.annoNascita) >= 1900 then
		addCat('Autori viventi')
	end

	local wp = c.wikipedia()
	local com = c.commons()
	local wq = c.wikiquote()

	-- CAT: AUTORI SENZA VOCE SUI VARI PROGETTI
	if (wp or '') == '' then 
		addCat('Autori senza voce su Wikipedia')
		if (naz and (naz:lower() == 'italiano' or naz:lower() == 'italiana')) then
			addCat('Autori italiani senza voce su Wikipedia')
		end
	elseif (wp and wp ~= 'it') then
		addCat('Autori con voce su Wikipedia non in italiano')
		if (naz and (naz:lower() == 'italiano' or naz:lower() == 'italiana')) then
			addCat('Autori italiani con voce su Wikipedia non in italiano')
		end
	end
	if (wq or '') == '' then addCat('Autori senza voce su Wikiquote') end
	if (com or '') == '' then addCat('Autori senza voce su Commons') end

	if c.sitelink('vecwikisource') then
		addCat('Autori presenti sul Wikisource veneto')
	end

	-- AUTORI SENZA ELEMENTO SU WIKIDATA
	if not item then
		add(c.template('Pagina non collegata a Wikidata', {}))
		addCat('Autori non collegati a Wikidata')
	end

	if not dati.gender and p.isHuman() then
		addCat('Autori senza proprietà sesso su Wikidata')
	end
	
	if nomeAutore ~= mw.title.getCurrentTitle().text then
		addCat('Nome autore non corretto')
	end
	--FINE CATEGORIE
	
	-- INIZIO BOX	
	add('<div class="boxAutore">');
	
	-- IMMAGINE AUTORE con CATEGORIE
	if dati.immagine then
		add('[[File:'..dati.immagine..'|140px|right|alt=Immagine di '..(args.Nome or '')..' '..(args.Cognome or '')..']]')
		addCat('Autori con immagine')
	else
		addCat('Autori senza immagine')
	end
	
	--INIZIO TESTO "Nome Cognome (1900-2000), scrittore italiano"

	-- NOME E COGNOME
	add(tostring(mw.html.create('b'):css('white-space', 'nowrap'):wikitext(nomeCognome)))

	--date di nascita e morte
	local datiAnagraficiMancanti = false
    if dati.birthStringa == '...' and dati.deathStringa == '...' then
		-- CAT: AUTORI SENZA DATI ANAGRAFICI 
		addCat('Autori senza dati anagrafici')
		datiAnagraficiMancanti = true
		
		if secolo and secolo ~= '' and c.empty(dati.floruitDates) then
			if not dati.gender or secolo == 'Antichità' then
				add('&nbsp;('..linkSecolo(secolo)..')')
			end
		end
		if (birthPlace and birthPlace ~= '') or (deathPlace and deathPlace ~= '') then
			if birthPlace and birthPlace ~= ''  then dati.birthStringa = birthPlace .. ', ' .. dati.birthStringa end
			if deathPlace and deathPlace ~= '' then dati.deathStringa = deathPlace .. ', ' .. dati.deathStringa end
			add('&nbsp;('..dati.birthStringa..'&nbsp;–&nbsp;'..dati.deathStringa..')')
		end
	elseif dati.birthStringa == dati.deathStringa and (not birthPlace or birthPlace == '') and (not deathPlace or deathPlace == '') then
		add('&nbsp;('..dati.birthStringa..')')
	else
		if birthPlace and birthPlace ~= ''  then dati.birthStringa = birthPlace .. ', ' .. dati.birthStringa end
		if deathPlace and deathPlace ~= '' then dati.deathStringa = deathPlace .. ', ' .. dati.deathStringa end
		add('&nbsp;('..dati.birthStringa..'&nbsp;–&nbsp;'..dati.deathStringa..')')
    end
	
	--floruit (solo in mancanza di date certe)
	if not c.empty(dati.floruitDates) and ((not dati.ricorrenzaNascita or dati.ricorrenzaNascita == '') or (not dati.ricorrenzaMorte or dati.ricorrenzaMorte == '')) then
		add(', '..dati.floruitStringa)
	elseif datiAnagraficiMancanti and secolo and secolo ~= '' then
		if dati.gender and secolo ~= 'Antichità' then
			add(', '..'\'\'[[:w:Floruit|floruit]]\'\' '..linkSecolo(secolo))
		end
	end

	local oa = 'o/a'
	if dati.gender then
		if dati.gender == 'maschio' then oa = 'o'
		elseif dati.gender == 'femmina' then oa = 'a' end
	end

	-- EVENTUALE ALTRO NOME
	if stringaAlias ~= '' then
		add(', not'..oa..' anche come \'\'\''..stringaAlias..'\'\'\'')
	end
	
	-- EVENTUALE PSEUDONIMO
	if stringaPseudonimo ~= '' then
		add(', not'..oa..' anche con ')
		if numeroPseudonimi > 1 then add('gli pseudonimi')
		else add('lo pseudonimo') end
		add(' di \'\'\''..stringaPseudonimo..'\'\'\'')
		addCat('Autori conosciuti con uno pseudonimo')
	end

	-- EVENTUALE NOME REALE
	if stringaNomeReale ~= '' and stringaNomeReale ~= nomeCognome then
		add(', nat'..oa..' \'\'\''..stringaNomeReale..'\'\'\'')
	end

	-- DATI BIOGRAFICI
	if args['Professione e nazionalità'] then
		add(', '..lang:lcfirst(args['Professione e nazionalità']))
	elseif args['Attività'] then
		add(', '..p.attivita(args['Attività']))
		if args['Nazionalità'] then add(' '..args['Nazionalità']) end
	end
	add('.')
	--fine della frase iniziale

	-- INTERPROGETTO
	add(tostring(mw.html.create('div'):css('margin-top', '15px'):wikitext(c.template('Interprogetto'))))

	if args.Nome ~= 'Anonimo' then
		-- LINK ALLA CATEGORIA TESTI DI ...
		catLink('Testi di %s')
		catLink('Testi curati da %s')

		-- LINK ALLA CATEGORIA TESTI MUSICATI DA...
		catLink('Testi musicati da %s', 'Nuvola filesystems folder sound.png')
	end

	-- LINK ALLA CATEGORIA TRADUZIONI DI ...
	catLink('Traduzioni di %s')

	-- LINK ALLA CATEGORIA TESTI IN CUI È CITATO ...
	catLink('Testi in cui è citato %s')

	-- LINK ALLA CATEGORIA PAGINE IN CUI È CITATO ...
	if c.pagesInCat('Testi in cui è citato '..nomeAutore) == 0 then
		catLink('Pagine in cui è citato %s')
	end

	--link a ricerca (per cercare altre citazioni)
	add('<div>[[File:Nuvola_apps_xmag.png|24px|alt=Icona cerca citazioni]][[Speciale:Ricerca/'..nomeAutore..'|Cerca citazioni su '..nomeAutore..'...]]</div>')
	
	-- CHIUSURA BOX
	add('</div>')

	-- SCHEDE DI AUTORITÀ
	local authcon = cda()
	if authcon == nil or authcon == '' then
		addCat('Autori senza schede di autorità')
	else
		add(authcon)
	end
	
	if dati.dbiLink then
		addCat('Autori presenti sul Dizionario Biografico degli Italiani')
	end
	if dati.liberLiber then
		addCat('Autori presenti su LiberLiber')
	end

	if dati.dbiLink or dati.liberLiber then
		local text = ''
		if dati.dbiLink then text = text .. '<div>[http://www.treccani.it/enciclopedia/' .. dati.dbiLink .. '_(Dizionario-Biografico) Dizionario Biografico degli Italiani]</div>' end
		if dati.liberLiber then text = text .. '<div>[https://liberliber.it/autori/autori-' .. dati.liberLiber .. ' LiberLiber]</div>' end
		add(tostring(mw.html.create('div')
			:addClass('controlloAutorita')
			:tag('div')
				:addClass('controlloAutoritaTitle')
				:wikitext('Collegamenti esterni')
				:done()
			:tag('div')
				:wikitext(text)
			:allDone()))
	end

	if c.wikinews() then addCat('Autori con pagina su Wikinews') end
	if c.wikispecies() then addCat('Autori con pagina su Wikispecies') end

	mw.log(output..outputCat)
	return output..outputCat
end

p['attività'] = function(frame)
	return p.attivita(frame.args[1])
end

function p.autoreLinkDBI(frame)
	local page = frame.args[1]
	mw.log('Pagina: '..page)
	
	item = mw.wikibase.getEntity(mw.wikibase.getEntityIdForTitle(page))
	c.setItem(item)
	
	local name = c.getLabel()
	mw.log('Nome: '..name)
	local output = "[["..page..'|'..name.."]]"

	lang, sitelink = c.wikipedia()
	mw.log('WP Link: '..lang..':'..sitelink)
	if lang and sitelink then
		output = output .. ' [[:'..lang..':'..sitelink..']]'
	end
	
	dbiLink = c.getSingleClaimValueByProperty('P1986')
	mw.log('DBI: '..c.printElement(dbiLink))
	if dbiLink then
		output = output .. ' ([http://www.treccani.it/enciclopedia/' .. dbiLink .. '_(Dizionario-Biografico) DBI])'
	end
	return output .. ' &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; '..frame:extensionTag('nowiki', output)
end

return p