Open main menu
--[=[
This module offers more flexibility in chosing which link to take than
[[Module:City]]

Standard fallback behavior for link:
* item -> [[Module:Wikidata label]]
	* from lookupPage
	* from gallery namespace
	* from category namespace
* gallery namespace
* category namespace
]=]

local p = {}

function p.qCode(matchStr, lookupPage, linkTypes)
	-- recover a q-code based on matchStr name, also if one can link to a page on commons return such link
	local item, link = nil, nil

	-- === STEP 1: if "matchStr" is empty than return nothing ==============
	if (not matchStr) or (matchStr == "") then
		return item, link
	end
	
	-- === STEP 2: Check if "matchStr"  holds a q-code or matches any of the hardwired names  ==============
	if string.match(matchStr, "^Q%d+$") then
		return matchStr, link -- matchStr string contains a q-code
	elseif lookupPage then
		-- if multiple calls from a single file,
		-- then mw.loadData should load lookupPage only once
		local LookupTable = mw.loadData(lookupPage)
		item = LookupTable[mw.ustring.lower(matchStr)]
		if item then
			return item, link
		end
	end

	-- === STEP 3: Check if {{{1}}} matches existing template, gallery or category and if so provide the link  ===
	local link0
	if #matchStr>=3 and #matchStr<40 then
		for i,linkType in pairs(linkTypes) do
			if linkType == '-' then
				return item, matchStr
			elseif linkType == 'commons gallery' then
				local page = mw.title.new( matchStr, '' )
				if page and page.exists then
					item = mw.wikibase.getEntityIdForTitle( matchStr ) or nil
					link = "[[" .. matchStr .. "]]"
					link0 = link0 or link
					if item then
						return item, link
					else
						link = link0
					end
				end
			elseif linkType == 'commons category' then
				page = mw.title.new( matchStr, 'category' )
				if page and page.exists then
					item = mw.wikibase.getEntityIdForTitle( 'Category:' .. matchStr )
					link = "[[:Category:" .. matchStr .. "|" .. matchStr .. "]]"
					link0 = link0 or link
					if item then
						entity = mw.wikibase.getEntityObject(item)
						if entity then
							local s = entity:getBestStatements( 'P31' )
							if s[1] and s[1].mainsnak.datavalue.value.id=="Q4167836" then 
								-- if "instance of "(P31) = "Wikimedia category" (Q4167836)
								s = entity:getBestStatements( 'P301' ) -- category's main topic 
								if s[1] then -- if property "category's main topic" (P301) is set
									item = s[1].mainsnak.datavalue.value.id 
								else
									item = nil
								end
							end
						end
					end
					if item then
						return item, link
					else
						link = link0
					end
				end
			end
		end
	end
	return item, link or matchStr
end

function p._link(matchStr, lang, linkTypes, lookupPage)
	-- Prepare the order of the link types in which they are searched for
	if linkTypes then
		linkTypes = mw.text.split(linkTypes, ",")
	else
		linkTypes = {}
	end
	for i,j in pairs(linkTypes) do
		linkTypes[i] = mw.text.trim(j)
	end
	for i,j in pairs(linkTypes) do
		if j == 'commons' then
			table.insert(linkTypes, i+1, 'commons gallery')
			table.insert(linkTypes, i+2, 'commons category')
		end
	end
	local standardLinkTypes = {'wikipedia','commons gallery','commons category'}
	if linkTypes[#linkTypes] ~= '-' then
		-- merge the standard types to those given
		for i,j in pairs(standardLinkTypes) do
			local missing = true
			for k,l in pairs(linkTypes) do
				if l == j then missing = false end
			end
			if missing then table.insert(linkTypes, standardLinkTypes[i]) end
		end
	end
	local linkType = linkTypes[1]
	
	if (not matchStr) or (matchStr == "") then
		return "" --if "matchStr" is empty than do nothing
	end
	
	if string.match(matchStr, "[%{%{|%[%[].+[%}%}|%]%]]") then
		return matchStr --  if "matchStr" already has a link and if so than skip the rest of the template
	end

	-- Check if we can recover a q-code
	local item, linkStr = p.qCode(matchStr, lookupPage, linkTypes)
	if item then
		local wikidata = require("Module:Wikidata label")
		return wikidata._getLabel(item, lang, linkType)
	elseif linkStr then
		return linkStr -- no q-code but we matched one of the galleries or categories
	end

	-- return as is
	return matchStr
end

function p.link(frame)
	local args = frame.args
	if not (args.lang and mw.language.isSupportedLanguage(args.lang)) then 
		args.lang = frame:callParserFunction( "int", "lang" ) -- get user's chosen language 
	end
	args.matchStr = mw.text.trim(args.matchStr or args[1] or '')
	return p._link(args.matchStr, args.lang, args.link, args.lookuppage)
end

return p