Die Dokumentation für dieses Modul kann unter Modul:Benutzer:FelixReimann/TB/Doku erstellt werden

local p = {}
local initialitem
local lang
local usereferences = {}
local taxondetails = ''
local code = false
--                                 ICZN               ICNafp              ICNCP            BC/ICNP             ICVCN
local colors = {[false]='#d3d3d3', [13011]='#d3d3a4', [693148]='#9bcd9b', [764]='#a4d3d3', [743780]='#d3a4d3', [10892]='#2f6fab'} -- background colors for each code

function p.taxobox(frame)
    local config = frame.args

    local count = 5  
    lang = 'en'

    if config.references then
        for word in string.gmatch(references, "%w+") do
            table.insert(usereferences, tonumber(string.sub(word, 2)))
        end
    end
    return p.createbox(count)
end

function p.createbox(count)
	local item = mw.wikibase.getEntityObject('Q192056')
	if not item then
		return mw.text.tag( 'b', {}, 'no Wikibase item found')
	end
	
    local content, references = p.iterate(item, count, true, true)

    local header = mw.text.tag( 'tr', {}, mw.text.tag( 'th', { colspan='2', style='text-align: center; background-color: ' .. colors[code] }, 'Vipera berus'))
    
    local image = p.targetStr(initialitem, 'P18')
    if image then
       header = header .. mw.text.tag( 'tr', {}, mw.text.tag( 'td', {colspan='2'}, '[[File:' .. image .. '|220px|.]]'))
    end

    local refstr = p.references(references)
    header = header .. mw.text.tag( 'tr', {}, mw.text.tag( 'th', { colspan='2', style='text-align: center; background-color: ' .. colors[code] }, '[[' .. mw.wikibase.sitelink('Q3516404') .. ']]' .. refstr))
    mw.log('header', header)
    mw.log('hierarchy', content)
    content = header .. content
    
    content = content .. taxondetails
    mw.log('nomenclature', taxondetails)
 
    footer =  p.map(item) -- .. p.iucn(item)
    mw.log('footer', footer)
    content = content .. footer
    
    return mw.text.tag( 'table', { style = "width: 200px; border-width: 1px; border-style: solid; background-color: #f9f9f9; float: right;" }, content )
end

-- performs the loop up the hierarchy using p171 (parent taxon)
function p.iterate(item, count, first, showtaxoname )
    local nextid, references = p.chooseparent(item)
    
    if not code then
		codeid = next(p.targetId(item, 'P944')) -- code of nomenclature
        if codeid and colors[codeid] then
           	code = codeid
        end
    end
    
    local showtaxoname = first or (showtaxoname and next(p.targetId(item, 'P31')) == 'Q310890')
    local content = ' '
    if nextid and count > 0 then
        output, refs = p.iterate(mw.wikibase.getEntity('Q' .. nextid), count - 1 , false, showtaxoname)
        for ref,_ in pairs(refs) do
            references[ref] = true
        end
        content = content .. output
    end
    content = content .. p.itemOutput(item, first, showtaxoname)
    return content, references
end

-- choose target according to the references selected by usereferences
function p.chooseparent(item)
    local nextid = {} -- list of targets from which the first one will be used
    local references = {}
    local candnextid, candreferences
    mw.log(item)
    for i,j in pairs(usereferences) do
		mw.log('usereferences', i, j)
	end
    for id,refs in pairs(p.targetId(item, 'P171')) do
        if refs then
            for i,r in pairs(usereferences) do
            	mw.log('testing',r,'as reference')
                if refs[r] then
                	mw.log('found',r)
                    nextid[i] = id
                    references[i] = refs
                end
            end
            candnextid = id
            candreferences = refs
        end
        if not candnextid then -- if no item had references yet
            candnextid = id -- use this
        end
    end
    if next(nextid) then
        _,candnextid = next(nextid)
    end
    if next(references) then
        _,candreferences = next(references)
    else -- a new reference is used, append it to usereferences for further usage
    	if candreferences then
    		for targetid,_ in pairs(candreferences) do
    			table.insert(usereferences, targetid)
			end
		end
	end
    return candnextid, candreferences or {}
end

-- formats each item in the taxon hierarchy by using p105 (taxon rank) and p225 (scientific name)
function p.itemOutput(item, first, showtaxonname)
    local rankid
    rankid = next(p.targetId(item, 'P105'))
    
    -- format rank
    local rankstr = mw.text.tag( 'td', {}, 'unknown rank')
    local ranklink = 'taxon'
    if rankid then
    	if rankid == 'novalue' then
    		rankstr = mw.text.tag( 'td', {}, '')
		else
	        if rankid == 713623 then
   				rankstr = mw.text.tag( 'td', {}, '')
   	    	else
   	    	    ranklink = mw.wikibase.sitelink('Q' .. rankid)
           	    rankstr = mw.text.tag( 'td', {}, ranklink)
       	    end 
       end
    end
    
    -- format common and scientific names
    local taxonname = 'taxonname'
    local itemlabel = mw.wikibase.label(item.id) -- common name
    local name, namequalifiers = p.targetStr(item, 'P225') -- scientific name
    local taxonname = name or 'no scientific name'
    if itemlabel == name then -- print only one if common name is same as scientific name
    	if rankid == 7432 or rankid == 34740 then -- italic in case of species (7432) or subspecies (34740) rank
       		taxonname = mw.text.tag( 'i', {}, '[[' .. mw.wikibase.sitelink(item.id) .. '|' .. name .. ']]')
    	end
    	namestr = mw.text.tag( 'td', {}, taxonname)
    else
    	if rankid == 7432 or rankid == 34740 then -- italic in case of species (7432) or subspecies (34740) rank
       		taxonname = mw.text.tag( 'i', {}, name)
    	end
        namestr = mw.text.tag( 'td', {}, '[[' .. mw.wikibase.sitelink(item.id) .. '|' .. itemlabel .. ']] (' .. taxonname .. ')' )
    end

    if first then
       initialname = taxonname
       initialitem = item
    end
    
    if showtaxonname then
        p.taxondetails(item, taxonname, ranklink, namequalifiers)
    end
    return mw.text.tag( 'tr', {}, rankstr .. namestr)
end

-- shows detailed information for current and all next monotypic taxa
function p.taxondetails(item, name, rank, namequalifiers)
    mw.log('show details for', name, rank, code)
    taxondetails = taxondetails .. mw.text.tag( 'tr', {}, mw.text.tag( 'th', { colspan="2", style='text-align: center; background-color: ' .. colors[code] }, 'scientific name of ' .. rank))
    taxondetails = taxondetails .. mw.text.tag( 'td', {colspan="2", style="text-align: center"}, name)
    
    --local year = p.qualifierTargetTime(namequalifiers, 'P574') or p.targetTime(item, 'P574')
    local year = p.targetTime(item, 'P574')
    if year then
       year = string.sub(year, 9, 12)
    else
       year = '????'
    end
    
    -- parentheses needed if instance of recombination
    --local recombination = false
    --for tid in pairs(p.qualifierTargetId(namequalifiers, 31)) do
    --    if tid == 14594740 then
    --        recombination = true
    --    end
    --end
    
    local authors = p.authorString(item, namequalifiers)
    local authorsstr = ''
    if authors or not year == '????' then
            authorsstr = authors .. ', ' .. year
            if recombination then
                authorsstr = '(' .. authorsstr .. ')'
            end
        taxondetails = taxondetails ..  mw.text.tag( 'tr', {}, mw.text.tag( 'td', {colspan="2", style="text-align: center; font-variant:small-caps"}, authorsstr))
    end
end

function p.authorString(item, namequalifiers, pid)
    if not pid then
        pid = 'P405' -- property
    end
    mw.log('pid',pid)
    --local authorids = p.qualifierTargetId(namequalifiers, pid)
    --if not next(authorids) then
        authorids = p.targetId(item, pid)
    --end
    local authors = p.createLinks(authorids, true)
    if next(authors) then
        local concatstr =  ', '
        if #authors == 2 then
            concatstr =  ' & '
        end
        return table.concat(authors, concatstr)
    end
end

-- check if International Code of Nomenclature for algae, fungi, and plants (ICNafp) applies
function p.icnafpApplies()
    return code == 693148
end

-- returns the target value of the property with the given integer id
-- use only if the data type of the property is item
function p.targetId(item, propertyid)
    local claims = {}
    if item and item.claims and item.claims[propertyid] then
    	for i = 0, #item.claims[propertyid] do
    		claim = item.claims[propertyid][i]
    		if claim.mainsnak and claim.mainsnak.datavalue then
    			if claim.mainsnak.datavalue.value then
    				local valueid = claim.mainsnak.datavalue.value['numeric-id']    			
    				local refids = {}
               		if claim.references then
                    	for _,ref in pairs(claim.references) do
                        	if ref.snaks and ref.snaks['P248'] then
                               	refids[ref.snaks['P248'][0].datavalue.value['numeric-id']] = true
                        	end
                    	end
                	end
                	claims[valueid] = refids
            	else
            		claims['novalue'] = true -- snaktype not value
        		end
    		end
		end
	end   
    return claims
end

-- Use only if the data type of the property is string
function p.targetStr(item, propertyid)
	choosenclaim = {}
	choosenqualifiers = {}
    if item and item.claims and item.claims[propertyid] then
    	for i = 0, #item.claims[propertyid] do
    		claim = item.claims[propertyid][i]
    		if claim.mainsnak and claim.mainsnak.datavalue and claim.mainsnak.datavalue.value then
    			local valueid = claim.mainsnak.datavalue.value
    			return valueid, nil
    		end
		end
	end
end

-- Use only if the data type of the property is time
function p.targetTime(item, propertyid )
    if item and item.claims and item.claims[propertyid] then
    	for i = 0, #item.claims[propertyid] do
     		claim = item.claims[propertyid][i]
    		if claim.mainsnak and claim.mainsnak.datavalue and claim.mainsnak.datavalue.value and claim.mainsnak.datavalue.value.time then
        		return claim.mainsnak.datavalue.value.time
    		end
     	end
    end
end

-- same as targetId but for qualifiers
-- TODO merge
function p.qualifierTargetId( qualifiers, propertyid )
    local claims = {}
    
    if qualifiers then
        for _,claim in pairs( qualifiers ) do
            if claim[2] == propertyid then
                local valueid = claim[4]['numeric-id']           
                claims[valueid] = true
            end  
        end
    end
    return claims
end

-- same as targetTime but for qualifiers
-- TODO merge
function p.qualifierTargetTime(qualifiers, propertyid )
    local claims = {}
    if qualifiers then
     for _,claim in pairs( qualifiers ) do
       if claim[2] == propertyid then
          local value = claim[4]
          return value.time
       end
     end
    end
end

-- returns html for the given refids set
function p.references(refids)
    local frame = mw.getCurrentFrame()
    local refstr = ''
    if refids then
        for id,_ in pairs(refids) do
            local ref = p.reference(id, last)
            if not ref then
            	ref = 'reference [[d:Q' .. id .. ']]'
        	end
            refstr = refstr .. frame:extensionTag('ref', ref, {name='Q'.. id})
        end
    end
    return refstr
end

function p.reference(id, last)
	return mw.wikibase.sitelink('Q' .. id)
end

-- takes a set of item ids (the keys of the given table) and creates wikilinks based on their labels
function p.createLinks(set, authorAbbreviation)
    local authors = {}
    for authorid,_ in pairs(set) do
        if authorid then
        	local label = mw.wikibase.label('Q' .. authorid)
            if authorAbbreviation then
            	if label ~= 'no label' then
                	for word in mw.ustring.gmatch(label, "%w+") do
                    	label = word
                    end
                end
            end
            table.insert(authors, '[[' .. mw.wikibase.sitelink('Q' .. authorid) .. '|' .. label .. ']]')
        end
    end
    return authors
end

function p.map(item)
	local map = p.targetStr(item, 'P181')
    if map then
    	return mw.text.tag( 'tr', {}, mw.text.tag( 'th', { colspan='2', style='text-align: center; background-color: ' .. colors[code] }, 'range map')) .. mw.text.tag( 'tr', {}, mw.text.tag( 'td', {colspan='2'}, '[[File:' .. map .. '|220px|.]]'))
    end
 
    return ''
end

return p