Mô đun:EFloras

require('strict')
local p = {}
local data -- Load Module:eFloras/data if needed and assign to this variable.
local function getResource(floraID)
	data = data or mw.loadData("Module:eFloras/data")
	return data.resourcesfloraID or data.resourcestonumber(floraID)
end
function p.resource(frame)
	local floraID = string.match(frame.args1, "%d+")
	if floraID == nil then
		return "Please provide a resource number (flora_id). See the list of supported resource numbers at Module:eFloras/doc"
	else
		local familyToVolume = getResource(floraID)
		if familyToVolume == nil then
			return "The resource number (flora_id) " .. floraID .. " is not recognized. See the list of supported resource numbers at Module:eFloras/doc"
		else
			return familyToVolume
		end
	end
end
function p._volumeName(floraID, volume, family)
	floraID = tonumber(floraID)
	
	if not floraID then -- floraID is not a number.
		return
	end
	
	data = data or mw.loadData("Module:eFloras/data")
	
	if not volume then
		local familyToVolume = data.volumeTablefloraID
		if not familyToVolume then
			return
		end
		
		volume = tonumber(familyToVolumefamily)
	
		if not volume then
			return
		end
	end
	
	local floraVolumeNames = data.volumeNames and data.volumeNamesfloraID
	if floraVolumeNames and volume then
		return floraVolumeNamesvolume
	end
end
function p.volumeName(frame)
	if not (frame.args1 and (frame.args2 or frame.args3 or frame.args.family)) then
		return
	end
	
	local floraID = string.match(frame.args1, "%d+")
	local volume = tonumber(frame.args2)
	local family = frame.args3 or frame.args.family
	
	if not (floraID and (volume or family)) then
		return
	end
	
	return p._volumeName(floraID, volume, family)
end
function p._volumeDate(floraID, volume, family)
	floraID = tonumber(floraID)
	
	if not floraID then -- floraID is not a number.
		return
	end
	
	data = data or mw.loadData("Module:eFloras/data")
	
	if not volume then
		local familyToVolume = data.volumeTablefloraID
		if not familyToVolume then
			return
		end
		
		volume = tonumber(familyToVolumefamily)
	
		if not volume then
			return
		end
	end
	
	local floraVolumeDates = data.volumeDates and data.volumeDatesfloraID
	if floraVolumeDates then
		if volume and floraVolumeDatesvolume then
			return floraVolumeDatesvolume
		else
			return floraVolumeDates.default
		end
	end
end
function p.volumeDate(frame)
	if not (frame.args1 and (frame.args2 or frame.args3 or frame.args.family)) then
		return
	end
	
	local floraID = string.match(frame.args1, "%d+")
	local volume = tonumber(frame.args2)
	local family = frame.args3 or frame.args.family
	
	if not (floraID and (volume or family)) then
		return
	end
	
	return p._volumeDate(floraID, volume, family)
end
function p.volume(frame)
	local floraID = string.match(frame.args1, "%d+")
	local family = frame.args2 or frame.args.family
	data = data or mw.loadData("Module:eFloras/data")
	local familyToVolume = data.volumeTablefloraID or data.volumeTabletonumber(floraID)
	if familyToVolume == nil then
		return ""
	else
		local volume = familyToVolumefamily
		if volume == "error" then
			return "19–21 "
		elseif volume == nil then
			return ""
		else
			return volume
		end
	end
end
-- Italicize if name requires it.
function p.italicize(name)
	local orig = name
	name = string.gsub(name, "^%s*(.-)%s*$", "%1")
	
	local count
	name, count = string.gsub(name, "\'\'\'?", "")
	
	if count > 0 then
		-- A tracking method used on Wiktionary: wikt:Module:debug.
		-- To see the results:
		-- Special:WhatLinksHere/Template:tracking/eFloras/italics or bolding
		local frame = mw.getCurrentFrame()
		pcall(frame.expandTemplate, frame, { title = 'tracking/eFloras/italics or bolding' })
		mw.log("Italics in input to the italicize function in Module:eFloras:", orig)
	end
	
	local rank
	local lowerName = name:lower()
	if name == "" or name == nil then
		return
	elseif string.find(name, "^%u%l+ae$") then
		if string.find(name, "eae$") then
			if string.find(name, "aceae$") then
				rank = "family"
			elseif string.find(name, "oideae$") then
				rank = "subfamily"
			else
				rank = "tribe"
			end
		elseif string.find(name, "inae$") then
			rank = "subtribe"
		end
	elseif string.find(lowerName, "subsp.", 1, true) then
		rank = "subspecies"
	elseif string.find(lowerName, "subg.", 1, true) then
		rank = "subgenus"
	elseif string.find(lowerName, "var.", 1, true) then
		rank = "variety"
	elseif string.find(lowerName, "sect.", 1, true) then
		rank = "section"
	elseif string.find(name, "^%a+%s%a-+$") or string.find(name, "^%a+%s×%s%a-+$") then
		rank = "species"
	elseif string.find(name, "^%u%a+$") -- No one-letter genera, probably.
			and not string.find(name, ".%u") then -- Uppercase letters can only appear at beginning of taxonomic name.
		rank = "genus"
	end
	
	if not rank then
		mw.log("Module:eFloras could not determine a taxonomic rank for the input that it received: " .. name)
		return orig
	end
	
	if rank == "genus" or rank == "subgenus" or rank == "species"
			or rank == "subspecies" or rank == "variety" or rank == "section" then
		
		name = "" .. name .. ""
		local hybrid = "×"
		
		if name:find(".", 1, true) then
			local abbreviations = {
				"subsp." = true, "ssp." = true, "var." = true, "f." = true,
				"sect." = true, "subsect." = true, "subg." = true,
			}
			
			local unrecognized
			name = name:gsub(
				"%s+(%S+%.)%s+",
				function (abbreviation)
					mw.log(name, abbreviation, abbreviation:lower(), abbreviationsabbreviation:lower())
					if abbreviationsabbreviation:lower() then
						return " " .. abbreviation .. " "
					else
						unrecognized = unrecognized or {}
						table.insert(unrecognized, abbreviation)
					end
				end)
			
			if unrecognized then
				mw.log(string.format("The abbreviation%s %s %s not recognized.",
					unrecognized2 and "s" or "",
					table.concat(
						unrecognized,
						", "),
					unrecognized2 and "are" or "is"))
				return orig
			end
		end
		
		name = name:gsub("%s+" .. hybrid .. "%s+", " " .. hybrid .. " ")
	end -- Else do not modify name.
	
	return name
end
function p.name(frame)
	local name = frame.args1
	return p.italicize(name)
end 
p.get_volume = p.volume
return p