require('strict');
local getArgs = require ('Module:Arguments').getArgs;  
local amendment_pattern = '%s*%(amended version of (%d%d%d%d) assessment%)';
local errata_pattern = '%s*%(errata version published in (%d%d%d%d)%)';
local green_status_pattern = '%s*%((Green Status assessment)%)';  
--2 templates cite single sources; when the identifiers in |doi=, |id=, and |page= are different from each other
then the template is attempting to cite multiple sources. This function evaluates the identifier portions of these
parameters. returns seven values: identifyier parts (or nil when parameter not used) and a message (nil on success,
error message else)  
the identifier portions of the several parameters must be properly formed  
local function iucn_identifiers_get (args, error_msgs_t)
local doi_taxon_ID, doi_assesment_ID
local page_taxon_ID, page_assesment_ID
local url_taxon_ID, url_assesment_ID  
if args.doi then
local lang_tag
doi_taxon_ID, doi_assesment_ID, lang_tag = args.doi:match ('[Tt](%d+)[Aa](%d+)%.(%l%l)$')
if not doi_taxon_ID or not ({['en'] = true, ['es'] = true, ['fr'] = true, ['pt'] = true})[lang_tag] then
table.insert (error_msgs_t, 'malformed |doi= identifier');
end
end
if args.page then
page_taxon_ID, page_assesment_ID = args.page:match ('^[eE]%.[Tt](%d+)[Aa](%d+)$')
if not page_taxon_ID then
table.insert (error_msgs_t, 'malformed |page= identifier');
end
end
if args.url then
if args.url:match ('https://www.iucnredlist.org/species/') then -- must be a 'new-form' url
url_taxon_ID, url_assesment_ID = args.url:match ('/species/(%d+)/(%d+)')
if not url_taxon_ID then
table.insert (error_msgs_t, 'malformed |url= identifier');
end
end
end  
if not error_msgs_t[1] then
if doi_taxon_ID and page_taxon_ID then
if (doi_taxon_ID ~= page_taxon_ID or ((doi_assesment_ID ~= page_assesment_ID) and not args.errata)) then
table.insert (error_msgs_t, '|doi= / |page= mismatch');
end
end
if doi_taxon_ID and url_taxon_ID then
if (doi_taxon_ID ~= url_taxon_ID or ((doi_assesment_ID ~= url_assesment_ID) and not args.errata)) then
table.insert (error_msgs_t, '|doi= / |url= mismatch');
end
end  
if page_taxon_ID and url_taxon_ID then
if (page_taxon_ID ~= url_taxon_ID or ((page_assesment_ID ~= url_assesment_ID) and not args.errata)) then
table.insert (error_msgs_t, '|page= / |url= mismatch');
end
end
end  
return doi_taxon_ID, doi_assesment_ID, page_taxon_ID, page_assesment_ID;
end  
--volume= (if present) against year in |date= or |year= (if present) against volume in |doi= (if present)  
returns nil if all that are present are correct; message else  
local function iucn_volume_check (args, maint_msgs_t)
local vol = args.volume;
local date = args.date or args.year;
local doi = args.doi and args.doi:match ('[Ii][Uu][Cc][Nn]%.[Uu][Kk]%.(%d%d%d%d)')  
if vol and date and (vol ~= date) then
table.insert (maint_msgs_t, '|volume= / |date= mismatch');
end  
if vol and doi and ((vol ~= doi) and not args.amends) then
table.insert (maint_msgs_t, '|volume= / |doi= mismatch');
end  
if date and doi and ((doi ~= date) and not args.amends) then
table.insert (maint_msgs_t, '|date= / |doi= mismatch');
end
end  
----------------------------< C I T E >----------------------------------------------------------------------  
Wraps :
takes cite journal parameters but updates old style url using electronic page number
page should be in format e.T13922A45199653
the url uses 13922/45199653
so we need to extract the number between T and A (taxon ID) and the number after A (assessment ID)
the target url is https://www.iucnredlist.org/species/13922/45199653
usage:
template:  
local function cite
local error_msgs_t = {}; -- holds error messages for rendering
local maint_msgs_t = {}; -- holds hidden maint messages for rendering
local namespace = mw.title.getCurrentTitle.namespace; -- used for categorization
local args = getArgs ; -- local copy of template arguments  
if args.title and (args.title:match (errata_pattern) or args.title:match (amendment_pattern)) then
table.insert (error_msgs_t, 'title has extraneous text'); -- announce that this template has has errata or amendment text
end  
local doi_taxon_ID, doi_assesment_ID; -- all of these contain the same identifying info in slightly
local page_taxon_ID, page_assesment_ID; -- different forms. when any combination of these is present,  
doi_taxon_ID, doi_assesment_ID, page_taxon_ID, page_assesment_ID = iucn_identifiers_get (args, error_msgs_t);  
args.id = nil -- unset; not supported  
local url_taxon_ID = page_taxon_ID or doi_taxon_ID; -- select for use in url that we will create
local url_assesment_ID = page_assesment_ID or doi_assesment_ID;  
local url = args.url;
if url then
if url:find ('iucnredlist.org/details/', 1, true) then -- old-form url
if url_taxon_ID then -- when there is an identifier
url = nil -- unset; we'll create new url below
else -- here when old-form but no identifier that we can use to create new url
args.url = args.url:gsub ("http:", "https:") -- sometimes works with redirect on iucn site
end
table.insert (maint_msgs_t, 'old-form url') -- announce that this template has has an old-form url
elseif url:find ('iucnredlist.org/species/', 1, true) then -- new-form url
-- table.insert (maint_msgs_t, 'new-form url') --TODO: restore this line when most new-form urls have been removed from article space -- announce that this template has has an new-form url
else
table.insert (error_msgs_t, 'unknown url') -- emit error message
end
end  
if not url then -- when no url or unset old-form url
if url_taxon_ID then
args.url = "https://www.iucnredlist.org/species/" .. url_taxon_ID .. '/' .. url_assesment_ID
else
table.insert (error_msgs_t, 'no identifier') -- emit error message
end
end  
-- add journal if not provided (TODO decide if this should override provided value)
if not args['journal'] and not args['work'] then
args['journal'] = "IUCN Red List of Threatened Species"
end  
iucn_volume_check (args, maint_msgs_t); -- |volume=, |year= (|date=), |doi= must all refer to the same volume  
if not args.volume and (args.year or args.date) then
args.volume = args.year or args.date
end  
if args.errata then
args['orig-date'] = 'errata version of ' .. (args.year or args.date or args.volume) .. ' assessment';
args.date = args.errata; -- update publication data to errata year
args.year = nil; -- unset these as no longer needed
args.errata = nil;
elseif args.amends then
args['orig-date'] = 'amended version of ' .. args.amends .. ' assessment';
args.amends = nil; -- unset as no longer needed
end
-- add free-to-read icon to mark a correctly formed doi
args['doi-access'] = args.doi and args.doi:match ('10%.2305/[Ii][Uu][Cc][Nn].+[Tt]%d+[Aa]%d+%.%a%a') and 'free' or nil  
local out_t = {};
if error_msgs_t[1] then
table.insert (out_t, ' <span>: error: ');
table.insert (out_t, table.concat (error_msgs_t, ', '));
table.insert (out_t, ' (help)');
if (0 == namespace) then
table.insert (out_t, '');
end
table.insert (out_t, '</span>');
end  
if maint_msgs_t[1] then
table.insert (out_t, '<span>');
if not error_msgs_t[1] then
table.insert (out_t, ': ')
table.insert (out_t, table.concat (maint_msgs_t, ', '));
table.insert (out_t, ' (help)');
if (0 == namespace) then
table.insert (out_t, '');
end
end
table.insert (out_t, '</span>');
end  
if (not args['doi-access']) and (0 == namespace) then
table.insert (out_t, '');
end  
return :expandTemplate{ title = 'cite journal', args = args } .. -- the template
table.concat (out_t); -- error and maint messages and categories
end  
--[=[-------------------------< E T _ A L _ P A T T E R N S >--------------------------------------------------  
This adapted from Module:Citation/CS1/Configuration  
This table provides Lua patterns for the phrase "et al" and variants in a name.  
]=]  
local et_al_patterns = {
"[;,]? *[\"']*%f[%a][Ee][Tt]%.? *[Aa][Ll][%.;,\"']*$", -- variations on the 'et al' theme