Module:MathModDBHelperMethods: Difference between revisions

From MaRDI portal
No edit summary
No edit summary
 
(19 intermediate revisions by 2 users not shown)
Line 20: Line 20:


-- Function to generate a table listing a type of individuals
-- Function to generate a table listing a type of individuals
-- test with =p.getList{args={'Model'}}
function p.getList(frame)
function p.getList(frame)
Line 46: Line 47:
     -- Q6534265 refers to MathModDB community
     -- Q6534265 refers to MathModDB community
     local sparqlQuery = [[
     local sparqlQuery = [[
SELECT ?itemLabel ?modelURL
SELECT ?itemLabel ?modelURL ?item
     WHERE {
     WHERE {
       ?item wdt:P31 wd:]] .. config.qid .. [[;
       ?item wdt:P31 wd:]] .. config.qid .. [[;
Line 74: Line 75:
-- Convert the JSON results into a Lua table
-- Convert the JSON results into a Lua table
     local fieldOrder = {"modelURL", "itemLabel"}
     local fieldOrder = {"modelURL", "itemLabel", "item"}
local dataTable = helper.convertJsonToTableOrdered(jsonResults, fieldOrder)
local dataTable = helper.convertJsonToTableOrdered(jsonResults, fieldOrder)
-- Create and return HTML table from the data
-- Create and return HTML table from the data
     local headers = {entityType}
     local headers = {entityType}
     local htmlTable =  helper.createHtmlTableWithMergedCols(dataTable, headers, {{1, 2}})
     local htmlTable =  helper.createHtmlTableWithMergedCols(dataTable, headers, {{3}})
-- Create a parent container for the table
-- Create a parent container for the table
Line 96: Line 97:
     return tostring(parentContainer)
     return tostring(parentContainer)
end
end


-- Function to get linked items
-- Function to get linked items
Line 152: Line 152:
-- Validate results
-- Validate results
if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       return " "
       return ""
     end
     end
Line 255: Line 255:




-- Function to get subclass of items
-- Function to get described by source
function p.getDescribedBySource(frame)
function p.getDescribedBySource(frame)
local entityId = frame.args[1]
local entityId = frame.args[1]
Line 335: Line 335:
     -- Loop through the image claims
     -- Loop through the image claims
-- for index = 1, numClaims  do
-- for index = 1, numClaims  do
local index = 1
for _, claim in ipairs(imageClaims) do
for _, claim in ipairs(imageClaims) do
-- Extract the image filename
-- Extract the image filename
     -- local imageFilename = imageClaims[index].mainsnak.datavalue.value
     -- local imageFilename = imageClaims[index].mainsnak.datavalue.value
     local imageFilename = claim.mainsnak.datavalue.value
     local imageFilename = claim.mainsnak.datavalue.value
    -- Default legend (empty string)
        local imageLegend = ""
     -- Check if the media legend qualifier exists
     -- Check if the media legend qualifier exists
         if claim.qualifiers and claim.qualifiers[pidMediaLegend]  
         if claim.qualifiers and claim.qualifiers[pidMediaLegend]  
Line 350: Line 353:
-- local imageLegend = imageClaims[index].qualifiers[pidMediaLegend][1].datavalue.value.text
-- local imageLegend = imageClaims[index].qualifiers[pidMediaLegend][1].datavalue.value.text
-- Add this image line to the list
-- Add this image line to the list
        table.insert(imageStrings, string.format("[[File:%s|thumb|380px|%s]]", imageFilename, imageLegend))
-- table.insert(imageStrings, {filename = imageFilename, legend = imageLegend})
        table.insert(imageStrings, string.format("[[File:%s|thumb|380px|%s]]", imageFilename, imageLegend))
          
          
         if index < numClaims then
         if index < numClaims then
         -- spacer column
         -- spacer column
         table.insert(imageStrings, '&nbsp;')   
         table.insert(imageStrings, '&nbsp;')   
    end
        end
index = index + 1
end     
end     
-- Combine all image cells into one row of a wikitable
-- Combine all image cells into one row of a wikitable
Line 361: Line 366:
return imageTable .. "\n\n"
return imageTable .. "\n\n"
else
else
     return " "  
     return ""  
end
end


Line 435: Line 440:
-- Extract the image filename
-- Extract the image filename
     local imageFilename = imageClaims[index].mainsnak.datavalue.value
     local imageFilename = imageClaims[index].mainsnak.datavalue.value
local imageLegend = imageClaims[index].qualifiers[pidMediaLegend][1].datavalue.value.text
    -- Default legend (empty string)
        local imageLegend = ""
    -- Check if the media legend qualifier exists
        if imageClaims[index].qualifiers and imageClaims[index].qualifiers[pidMediaLegend]
        and #imageClaims[index].qualifiers[pidMediaLegend] > 0
        and imageClaims[index].qualifiers[pidMediaLegend][1].datavalue
        and imageClaims[index].qualifiers[pidMediaLegend][1].datavalue.value
        and imageClaims[index].qualifiers[pidMediaLegend][1].datavalue.value.text then
 
            imageLegend = imageClaims[index].qualifiers[pidMediaLegend][1].datavalue.value.text
        end
-- Add this image line to the list
-- Add this image line to the list
         table.insert(imageStrings, string.format("[[File:%s|thumb|380px|%s]]", imageFilename, imageLegend))
         table.insert(imageStrings, string.format("[[File:%s|thumb|380px|%s]]", imageFilename, imageLegend))
Line 576: Line 591:
return wikitextTable
return wikitextTable
end
end
-- Function to get list with qualifier values and qualifier labels
function p.getListWithQualifierValuesLabels(frame)
local entityId = frame.args[1]
    local propertyId = frame.args[2]
   
    -- Validate input parameter
    if not entityId or entityId == '' then
        return " "
    end
 
    -- Constructing the SPARQL query with dynamic entity entityId
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
SELECT ?URL ?Label ?qualPropEntity ?qualPropLabel ?qualValue ?qualValueLabel
WHERE {
entityId: p:]] .. propertyId .. [[  ?statement .
?statement ps:]] .. propertyId .. [[ ?URL .
?URL rdfs:label ?Label
FILTER(LANG(?Label) = "en")
OPTIONAL {
    ?statement ?qualProp ?qualValue .
    FILTER(STRSTARTS(STR(?qualProp), STR(pq:)))  # only qualifiers
    # Map qualifier property to its property entity
    BIND(IRI(REPLACE(STR(?qualProp), "prop/qualifier", "entity")) AS ?qualPropEntity)
    OPTIONAL {
    ?qualPropEntity rdfs:label ?qualPropLabel .
    FILTER(LANG(?qualPropLabel) = "en")
    }
    OPTIONAL {
    ?qualValue rdfs:label ?qualValueLabel .
    FILTER(LANG(?qualValueLabel) = "en")
    }
}
}
ORDER BY ?Label
]]
-- Executing the SPARQL query and retrieving results in JSON format
local jsonResults = sparql.runQuery(sparqlQuery)
-- Validate results
if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
      return "No specialized research fields found"
    end
local listItems = {}
    -- Get the number of specialized research fields
local totallistItems = #jsonResults.results.bindings
-- Loop through the bindings
for index = 0, totallistItems do
    local item = jsonResults.results.bindings[index]
    if not item.Label.value then
        return "Error: Missing item.Label.value"
    elseif not item.URL.value then
        return "Error: Missing item.URL.value"
    else
    local label = item.Label.value
        local url = item.URL.value
        local numericId = url:match("Q(%d+)")
        local urlRendered = "https://portal.mardi4nfdi.de/wiki/Model:" .. numericId
        local qualValue = item.qualValueLabel or item.qualValue or ""
        local qualPropLabel = item.qualPropLabel or ""
        local labelWithUrl = string.format('[%s %s]', tostring(url), tostring(label))
        if qualValue ~= "" then
      local qualValueWithUrl = string.format('[%s %s]', tostring(item.qualValue.value), tostring(item.qualValueLabel.value))
        local row = "| " .. labelWithUrl ..  " || " ..  qualPropLabel.value .. " || " .. qualValueWithUrl
    table.insert(listItems, row)
        else
        table.insert(listItems, "| " .. labelWithUrl)
        end
    end
end
-- Construct the Wikitext table
local wikitextTable = "{| class='wikitable'\n" .. table.concat(listItems, "\n|-\n") .. "\n|}"
return wikitextTable
end
-- Function to get instance of types
function p.getInstanceOfTypes(frame)
local entityId = frame.args[1]
   
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
   
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P31: instance of property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
SELECT  ?InstanceOfTypeLabel WHERE {
  entityId: p:P31 ?statement .
  ?statement ps:P31 ?InstanceOfType .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
ORDER BY ?InstanceOfTypeLabel
]]
-- Executing the SPARQL query and retrieving results in JSON format
local jsonResults = sparql.runQuery(sparqlQuery)
-- Validate results
if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
    end
local InstanceOfTypes = {}
    -- Get the number of model types
local totalInstanceOfTypes = #jsonResults.results.bindings
-- Loop through the bindings
for index = 0, totalInstanceOfTypes  do
    local item = jsonResults.results.bindings[index]
    if item and item.InstanceOfTypeLabel and item.InstanceOfTypeLabel.value then
        local label = item.InstanceOfTypeLabel.value
        table.insert(InstanceOfTypes, label)
    end
end
-- Construct the Wikitext table
local wikitextTable = "{| class='wikitable'\n|-\n| " .. table.concat(InstanceOfTypes, " || ") .. "\n|}"
return wikitextTable
end
-- Function to get instance of types
function p.getListNamedAfter(frame)
local entityId = frame.args[1]
   
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
   
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P31: instance of property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
SELECT ?namedAfterLabel ?namedAfter
WHERE {
  entityId: p:P558 ?statement .
  ?statement ps:P558 ?namedAfter .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
ORDER BY ?namedAfterLabel
]]
-- Executing the SPARQL query and retrieving results in JSON format
local jsonResults = sparql.runQuery(sparqlQuery)
-- Validate results
if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
end
local ListNamedAfter = {}
    -- Get the number of persons named after
local totalPersons = #jsonResults.results.bindings
-- Loop through the bindings
for index = 0, totalPersons  do
    local item = jsonResults.results.bindings[index]
    if item and item.namedAfterLabel and item.namedAfterLabel.value then
        local label = item.namedAfterLabel.value
        local url = item.namedAfter.value
        local numericId = url:match("Q(%d+)")
    local urlRendered = "https://portal.mardi4nfdi.de/wiki/Person:" .. numericId
        local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
        table.insert(ListNamedAfter,  labelWithUrl)
    end
end
return table.concat(ListNamedAfter, ', ')
   
-- end of function getListNamedAfter
end
   


return p
return p

Latest revision as of 21:32, 16 December 2025

Documentation for this module may be created at Module:MathModDBHelperMethods/doc

-- Module for executing SPARQL queries
local sparql = require('SPARQL')
-- Required module containing helper methods
local helper = require('Module:HelperMethods')
-- MediaWiki library for logging and utilities
local mw = require('mw')
local json = require("mw.text") 

-- Main table to hold all functions
local p = {}

-- Function to replace pattern in the comma pattern separated list 
function p.replace_pattern(frame)
    local input = frame.args[1] or ""
    local sep = frame.args[2] or " "  -- default to space if no separator given
    -- Replace comma+pattern (,xxxx) with sep
    local result = string.gsub(input, ",xxxx%s*", sep)
    return result
end

-- Function to generate a table listing a type of individuals
-- test with =p.getList{args={'Model'}}
function p.getList(frame)
	
	local entityType = frame.args[1] or 'Model'
	local height = frame.args[2] or '400px' -- Default height if not specified
    local width = frame.args[3] or '800px' -- Default width if not specified
    local baseUrl = mw.site.server -- Get the current URL
    
    -- Define mapping of entity types to their corresponding Q IDs and URL prefixes
    local entityConfig = {
        ['Model'] = {qid = 'Q68663', urlPrefix = 'Model:', title = 'mathematical models'},
        ['Academic discipline'] = {qid = 'Q60231', urlPrefix = 'Academic_discipline:', title = 'academic disciplines'},
        ['Research problem'] = {qid = 'Q6534292', urlPrefix = 'Research_problem:', title = 'research problems'},
        ['Task'] = {qid = 'Q6534247', urlPrefix = 'Task:', title = 'computational tasks'},
        ['Quantity'] = {qid = 'Q6534237', urlPrefix = 'Quantity:', title = 'quantities'},
        ['Quantity kind'] = {qid = 'Q6534245', urlPrefix = 'Quantity:', title = 'quantity kind items'},
        ['Formula'] = {qid = 'Q6481152', urlPrefix = 'Formula:', title = 'mathematical expressions'}
    }
    
    -- Get configuration for the specified entity type
    local config = entityConfig[entityType]
    if not config then
        return "Invalid entity type. Valid options are: Model, Academic discipline, Research problem, Task, Quantity, Quantity kind, Formula"
    end

    -- Q6534265 refers to MathModDB community
    local sparqlQuery = [[
	SELECT ?itemLabel ?modelURL ?item
    WHERE {
      ?item wdt:P31 wd:]] .. config.qid .. [[;
            wdt:P1495 wd:Q6534265 .
      ?item rdfs:label ?itemLabel .
      FILTER(LANG(?itemLabel) = "en")
      BIND(REPLACE(STR(?item), "^.*/Q", "]] .. baseUrl .. [[/wiki/]] .. config.urlPrefix .. [[") AS ?modelURL)
    }
    ORDER BY LCASE(?itemLabel)
    ]]

    local jsonResults = sparql.runQuery(sparqlQuery)

	-- Handle error in SPARQL query execution
	if jsonResults and jsonResults.error then
    	mw.log("Error in SPARQL query: " .. tostring(jsonResults.error))
    	return nil
	end

	if not jsonResults then
        return "Could not fetch data."
	end

	if helper.countElementsInBindings(jsonResults.results.bindings) == 0 then
        return "No records found."
	end
	
	-- Convert the JSON results into a Lua table
    local fieldOrder = {"modelURL", "itemLabel", "item"}
	local dataTable = helper.convertJsonToTableOrdered(jsonResults, fieldOrder)
	
	-- Create and return HTML table from the data
    local headers = {entityType}
    local htmlTable =  helper.createHtmlTableWithMergedCols(dataTable, headers, {{3}})
	
	-- Create a parent container for the table
	local parentContainer = mw.html.create('div')
    	:addClass('parent-container')
    	:css('width', width)

	local heading = mw.html.create('h2')
    	:wikitext('List of ' .. config.title)

    -- Add the table and chart to the parent container
	parentContainer
	    :node(heading)
    	:node(htmlTable)

    return tostring(parentContainer)
end

-- Function to get linked items
function p.getLinkedItems(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
    
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>

SELECT DISTINCT ?itemLabel ?item ?propertyLabel ?property 
WHERE {
  # Replace with your specific entity
  ?itemInter ?ps entityId: .

  # Convert property URL to entity-style URL
 BIND(
    IRI(REPLACE(STR(?ps),
                 "^https://portal.mardi4nfdi.de/prop/(direct|qualifier|statement)/",
                 "https://portal.mardi4nfdi.de/entity/"))
    AS ?property
 )
 # Skip unwanted property
 FILTER(?property != <http://schema.org/about>)

  # Clean URL: keep only QID, remove /statement/ and trailing UUID
  BIND(
    IRI(
      REPLACE(
        STR(?itemInter),
        ".*/(Q[0-9]+).*",
        "https://portal.mardi4nfdi.de/entity/$1"
      )
    ) AS ?item
  )

  # Get labels
  SERVICE wikibase:label { 
    bd:serviceParam wikibase:language "en". 
    ?item rdfs:label ?itemLabel .
    ?property rdfs:label ?propertyLabel .
  }
}
ORDER BY LCASE(?itemLabel)

]]


	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return ""
    end
	
	local linkedItems = {}
	local totalLinkedItems = #jsonResults.results.bindings

	if totalLinkedItems >= 0 then
    	-- Loop through the bindings 
    	for index = 0, totalLinkedItems do
        	local item = jsonResults.results.bindings[index]
        	
        	if not item then
        		return ""
    		end

        	if not item.itemLabel or not item.itemLabel.value then
        		return ""
        	elseif not item.item or not item.item.value then
            	return ""
        	else
            	local itemLabel = item.itemLabel.value
            	local itemURL = item.item.value
            	local propertyLabel = item.propertyLabel and item.propertyLabel.value or ""
            	local propertyURL = item.property and item.property.value or ""

            	local itemWithURL = string.format('[%s %s]', tostring(itemURL), tostring(itemLabel))
            	local propertyWithURL = string.format('[%s %s]', tostring(propertyURL), tostring(propertyLabel))

            	table.insert(linkedItems, '| ' .. itemWithURL .. ' || ' .. propertyWithURL)
        	end
    	end
    	-- if there are linked items 
    	-- Construct the Wikitext table
		local wikitextTable = "{| class='wikitable'\n" ..
    	"! Item\n! Property\n" ..          -- header row
    	"|-\n" ..                          -- separator before first data row
    	table.concat(linkedItems, "\n|-\n") ..
    	"\n|}"
		return wikitextTable
	else
		return ""
	end

end

-- Function to get subclass of items
function p.getSubclassOf(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P36: subclass of property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?URL ?Label  
	WHERE {
		entityId: wdt:P36 ?URL.
		?URL rdfs:label ?Label
		FILTER(LANG(?Label) = "en")
	}
	ORDER BY ?Label
	]]

	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return "No specialized academic discipline found"
    end
	
	local subClasses = {}
    -- Get the number of specialized academic disciplines
	local totalSubClasses = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalSubClasses  do
    	local item = jsonResults.results.bindings[index]
    	if not item then
        		return ""
    	end
    	if not item.Label.value then
        	return ""
    	elseif not item.URL.value then
        	return ""
    	else
    		local label = item.Label.value
        	local url = item.URL.value
        	local numericId = url:match("Q(%d+)")
        	local urlRendered = "https://portal.mardi4nfdi.de/wiki/Academic_discipline:" .. numericId
        	local labelWithUrl = string.format('[%s %s]', tostring(url), tostring(label))
        	table.insert(subClasses, "| " .. labelWithUrl)
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(subClasses, "\n|-\n") .. "\n|}"
	return wikitextTable
end	


-- Function to get described by source
function p.getDescribedBySource(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P286: described by source property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?URL ?Label  
	WHERE {
		entityId: wdt:P286 ?URL.
		?URL rdfs:label ?Label
		FILTER(LANG(?Label) = "en")
	}
	ORDER BY ?Label
	]]

	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return "No specialized academic discipline found"
    end
	
	local describedBySources = {}
    -- Get the number of specialized academic disciplines
	local totalSources = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalSources  do
    	local item = jsonResults.results.bindings[index]
    	if not item then
        		return ""
    	end
    	if not item.Label.value then
        	return ""
    	elseif not item.URL.value then
        	return ""
    	else
    		local label = item.Label.value
        	local url = item.URL.value
        	local numericId = url:match("Q(%d+)")
        	local urlRendered = "https://portal.mardi4nfdi.de/wiki/Academic_discipline:" .. numericId
        	local labelWithUrl = string.format('[%s %s]', tostring(url), tostring(label))
        	table.insert(describedBySources, "| " .. labelWithUrl)
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(describedBySources, "\n|-\n") .. "\n|}"
	return wikitextTable
end	

function p.getImageWithLegend(frame)
	-- Property ID for the image
    local pidImage  = "P356" 
    -- Property ID for the (qualifier) media legend
    local pidMediaLegend = "P401"   
    local defaultLegend = "No legend available."

   	
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
    
    -- Attempt to retrieve entity data
    local entity = mw.wikibase.getEntity(entityId)
    local imageClaims = entity.claims[pidImage]
    local imageStrings = {}
	if imageClaims and type(imageClaims) == "table" then
    	local numClaims = #imageClaims
    	-- Loop through the image claims
		-- for index = 1, numClaims  do
		local index = 1
		for _, claim in ipairs(imageClaims) do
			-- Extract the image filename
    		-- local imageFilename = imageClaims[index].mainsnak.datavalue.value
    		local imageFilename = claim.mainsnak.datavalue.value
    		-- Default legend (empty string)
        	local imageLegend = ""
    		-- Check if the media legend qualifier exists
        	if claim.qualifiers and claim.qualifiers[pidMediaLegend] 
        		and #claim.qualifiers[pidMediaLegend] > 0 
        		and claim.qualifiers[pidMediaLegend][1].datavalue
        		and claim.qualifiers[pidMediaLegend][1].datavalue.value
        		and claim.qualifiers[pidMediaLegend][1].datavalue.value.text then

            	imageLegend = claim.qualifiers[pidMediaLegend][1].datavalue.value.text
        	end
			-- local imageLegend = imageClaims[index].qualifiers[pidMediaLegend][1].datavalue.value.text
			-- Add this image line to the list
			-- table.insert(imageStrings, {filename = imageFilename, legend = imageLegend})
        	table.insert(imageStrings, string.format("[[File:%s|thumb|380px|%s]]", imageFilename, imageLegend))
        
        	if index < numClaims then
        		-- spacer column
        		table.insert(imageStrings, '&nbsp;')  
        	end
			index = index + 1
		end    
		-- Combine all image cells into one row of a wikitable
		local imageTable = '{| class="wikitable"\n| ' .. table.concat(imageStrings, ' || ') .. '\n|}'
		return imageTable .. "\n\n"
	else
    	return "" 
	end

end


function p.getVideoWithLegend(frame)
	-- Property ID for the video
    local pidVideo  = "P797" 
    -- Property ID for the (qualifier) media legend
    local pidMediaLegend = "P401"   
    local defaultLegend = "No legend available."

   	
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
    
    -- Attempt to retrieve entity data
    local entity = mw.wikibase.getEntity(entityId)
    local videoClaims = entity.claims[pidVideo]
    local videoStrings = {}
	if videoClaims and type(videoClaims) == "table" then
    	local numClaims = #videoClaims
    	-- Loop through the image claims
		for index = 1, numClaims  do
			-- Extract the image filename
    		local videoFilename = videoClaims[index].mainsnak.datavalue.value
			local videoLegend = videoClaims[index].qualifiers[pidMediaLegend][1].datavalue.value.text
			-- Add this image line to the list
        	 table.insert(videoStrings, string.format("[[File:%s|thumb|340px|%s]]", videoFilename, videoLegend))
        
        	if index < numClaims then
        		-- spacer column
        		table.insert(videoStrings, '&nbsp;')  
    end
		end    
		-- Combine all image cells into one row of a wikitable
		local videoTable = '{| class="wikitable"\n| ' .. table.concat(videoStrings, ' || ') .. '\n|}'
		return videoTable .. "\n\n"
	else
    	return " " 
	end

end

function p.getLocalImageWithLegend(frame)
	-- Property ID for the image
    local pidImage  = "P1640" 
    -- Property ID for the (qualifier) media legend
    local pidMediaLegend = "P401"   
    local defaultLegend = "No legend available."

   	
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
    
    -- Attempt to retrieve entity data
    local entity = mw.wikibase.getEntity(entityId)
    local imageClaims = entity.claims[pidImage]
    local imageStrings = {}
	if imageClaims and type(imageClaims) == "table" then
    	local numClaims = #imageClaims
    	-- Loop through the image claims
		for index = 1, numClaims  do
			-- Extract the image filename
    		local imageFilename = imageClaims[index].mainsnak.datavalue.value
    		-- Default legend (empty string)
        	local imageLegend = ""
    		-- Check if the media legend qualifier exists
        	if imageClaims[index].qualifiers and imageClaims[index].qualifiers[pidMediaLegend] 
        		and #imageClaims[index].qualifiers[pidMediaLegend] > 0 
        		and imageClaims[index].qualifiers[pidMediaLegend][1].datavalue
        		and imageClaims[index].qualifiers[pidMediaLegend][1].datavalue.value
        		and imageClaims[index].qualifiers[pidMediaLegend][1].datavalue.value.text then

            	imageLegend = imageClaims[index].qualifiers[pidMediaLegend][1].datavalue.value.text
        	end
			-- Add this image line to the list
        	 table.insert(imageStrings, string.format("[[File:%s|thumb|380px|%s]]", imageFilename, imageLegend))
        
        	if index < numClaims then
        		-- spacer column
        		table.insert(imageStrings, '&nbsp;')  
    end
		end    
		-- Combine all image cells into one row of a wikitable
		local imageTable = '{| class="wikitable"\n| ' .. table.concat(imageStrings, ' || ') .. '\n|}'
		return imageTable .. "\n\n"
	else
    	return " " 
	end

end


function p.getLocalVideoWithLegend(frame)
	-- Property ID for the video
    local pidVideo  = "P1675" 
    -- Property ID for the (qualifier) media legend
    local pidMediaLegend = "P401"   
    local defaultLegend = "No legend available."

   	
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
    
    -- Attempt to retrieve entity data
    local entity = mw.wikibase.getEntity(entityId)
    local videoClaims = entity.claims[pidVideo]
    local videoStrings = {}
	if videoClaims and type(videoClaims) == "table" then
    	local numClaims = #videoClaims
    	-- Loop through the image claims
		for index = 1, numClaims  do
			-- Extract the image filename
    		local videoFilename = videoClaims[index].mainsnak.datavalue.value
			local videoLegend = videoClaims[index].qualifiers[pidMediaLegend][1].datavalue.value.text
			-- Add this image line to the list
        	 table.insert(videoStrings, string.format("[[File:%s|thumb|340px|%s]]", videoFilename, videoLegend))
        
        	if index < numClaims then
        		-- spacer column
        		table.insert(videoStrings, '&nbsp;')  
    end
		end    
		-- Combine all image cells into one row of a wikitable
		local videoTable = '{| class="wikitable"\n| ' .. table.concat(videoStrings, ' || ') .. '\n|}'
		return videoTable .. "\n\n"
	else
    	return " " 
	end

end

-- Function to get list with qualifier values only
function p.getListWithQualifierValues(frame)
	local entityId = frame.args[1]
    local propertyId = frame.args[2]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return " "
    end
   
    -- Constructing the SPARQL query with dynamic entity entityId
    local sparqlQuery = [[
	PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?URL ?Label ?qualPropEntity ?qualPropLabel ?qualValue ?qualValueLabel
	WHERE {
		entityId: p:]] .. propertyId .. [[  ?statement .
		?statement ps:]] .. propertyId .. [[ ?URL .
		?URL rdfs:label ?Label
		FILTER(LANG(?Label) = "en")

		OPTIONAL {
    		?statement ?qualProp ?qualValue .
    		FILTER(STRSTARTS(STR(?qualProp), STR(pq:)))   # only qualifiers

	    	# Map qualifier property to its property entity
    		BIND(IRI(REPLACE(STR(?qualProp), "prop/qualifier", "entity")) AS ?qualPropEntity)

	    	OPTIONAL {
    			?qualPropEntity rdfs:label ?qualPropLabel .
    			FILTER(LANG(?qualPropLabel) = "en")
    		}

    		OPTIONAL {
    			?qualValue rdfs:label ?qualValueLabel .
    			FILTER(LANG(?qualValueLabel) = "en")
    		}
		}
	}
	ORDER BY ?Label
	]]

	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return "No specialized research fields found"
    end
	
	local listItems = {}
    -- Get the number of specialized research fields
	local totallistItems = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totallistItems do
    	local item = jsonResults.results.bindings[index]
    	if not item.Label.value then
        	return "Error: Missing item.Label.value"
    	elseif not item.URL.value then
        	return "Error: Missing item.URL.value"
    	else
    		local label = item.Label.value
        	local url = item.URL.value
        	local numericId = url:match("Q(%d+)")
        	local urlRendered = "https://portal.mardi4nfdi.de/wiki/Model:" .. numericId
        	local qualValue = item.qualValueLabel or item.qualValue or ""
	        local labelWithUrl = string.format('[%s %s]', tostring(url), tostring(label))
	        if qualValue ~= "" then
	       		local qualValueWithUrl = string.format('[%s %s]', tostring(item.qualValue.value), tostring(item.qualValueLabel.value))
	        	local row = "| " .. labelWithUrl ..  " || (" ..  qualValueWithUrl .. ")"
    			table.insert(listItems, row)
	        else
        		table.insert(listItems, "| " .. labelWithUrl)
        	end
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(listItems, "\n|-\n") .. "\n|}"
	return wikitextTable
end


-- Function to get list with qualifier values and qualifier labels
function p.getListWithQualifierValuesLabels(frame)
	local entityId = frame.args[1]
    local propertyId = frame.args[2]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return " "
    end
   
    -- Constructing the SPARQL query with dynamic entity entityId
    local sparqlQuery = [[
	PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?URL ?Label ?qualPropEntity ?qualPropLabel ?qualValue ?qualValueLabel
	WHERE {
		entityId: p:]] .. propertyId .. [[  ?statement .
		?statement ps:]] .. propertyId .. [[ ?URL .
		?URL rdfs:label ?Label
		FILTER(LANG(?Label) = "en")

		OPTIONAL {
    		?statement ?qualProp ?qualValue .
    		FILTER(STRSTARTS(STR(?qualProp), STR(pq:)))   # only qualifiers

	    	# Map qualifier property to its property entity
    		BIND(IRI(REPLACE(STR(?qualProp), "prop/qualifier", "entity")) AS ?qualPropEntity)

	    	OPTIONAL {
    			?qualPropEntity rdfs:label ?qualPropLabel .
    			FILTER(LANG(?qualPropLabel) = "en")
    		}

    		OPTIONAL {
    			?qualValue rdfs:label ?qualValueLabel .
    			FILTER(LANG(?qualValueLabel) = "en")
    		}
		}
	}
	ORDER BY ?Label
	]]

	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return "No specialized research fields found"
    end
	
	local listItems = {}
    -- Get the number of specialized research fields
	local totallistItems = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totallistItems do
    	local item = jsonResults.results.bindings[index]
    	if not item.Label.value then
        	return "Error: Missing item.Label.value"
    	elseif not item.URL.value then
        	return "Error: Missing item.URL.value"
    	else
    		local label = item.Label.value
        	local url = item.URL.value
        	local numericId = url:match("Q(%d+)")
        	local urlRendered = "https://portal.mardi4nfdi.de/wiki/Model:" .. numericId
        	local qualValue = item.qualValueLabel or item.qualValue or ""
        	local qualPropLabel = item.qualPropLabel or "" 
	        local labelWithUrl = string.format('[%s %s]', tostring(url), tostring(label))
	        if qualValue ~= "" then
	       		local qualValueWithUrl = string.format('[%s %s]', tostring(item.qualValue.value), tostring(item.qualValueLabel.value))
	        	local row = "| " .. labelWithUrl ..  " || " ..  qualPropLabel.value .. " || " .. qualValueWithUrl 
    			table.insert(listItems, row)
	        else
        		table.insert(listItems, "| " .. labelWithUrl)
        	end
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(listItems, "\n|-\n") .. "\n|}"
	return wikitextTable
end


-- Function to get instance of types
function p.getInstanceOfTypes(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P31: instance of property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
SELECT  ?InstanceOfTypeLabel WHERE {
  entityId: p:P31 ?statement .
  ?statement ps:P31 ?InstanceOfType .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
ORDER BY ?InstanceOfTypeLabel
	]]


	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
    end
	
	local InstanceOfTypes = {}
    -- Get the number of model types
	local totalInstanceOfTypes = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalInstanceOfTypes  do
    	local item = jsonResults.results.bindings[index]
    	if item and item.InstanceOfTypeLabel and item.InstanceOfTypeLabel.value then
        	local label = item.InstanceOfTypeLabel.value
        	table.insert(InstanceOfTypes, label)
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n|-\n| " .. table.concat(InstanceOfTypes, " || ") .. "\n|}"
	return wikitextTable

end

-- Function to get instance of types
function p.getListNamedAfter(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P31: instance of property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
SELECT ?namedAfterLabel ?namedAfter
WHERE {
  entityId: p:P558 ?statement .
  ?statement ps:P558 ?namedAfter .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
ORDER BY ?namedAfterLabel
	]]


	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
	end

	local ListNamedAfter = {}
    -- Get the number of persons named after
	local totalPersons = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalPersons  do
    	local item = jsonResults.results.bindings[index]
    	if item and item.namedAfterLabel and item.namedAfterLabel.value then
        	local label = item.namedAfterLabel.value
        	local url = item.namedAfter.value
        	local numericId = url:match("Q(%d+)")
    		local urlRendered = "https://portal.mardi4nfdi.de/wiki/Person:" .. numericId
        	local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
        	table.insert(ListNamedAfter,  labelWithUrl)
    	end
	end
	
	return table.concat(ListNamedAfter, ', ')
    
-- end of function getListNamedAfter
end
    


return p