--Expects a PAGENAME of the form "Some sequential 2000 example cat", where
-- firstpart = Some sequential
-- decade = 2000
-- lastpart = example cat
-- mindecade = 1800 ('min' decade parameter; optional; defaults to -9999)
-- maxdecade = 2020 ('max' decade parameter; optional; defaults to 9999)  
--sterilize dec
local dec = sterilizedec(decade)
if dec == nil then
errors = p.errorclass('Function nav_decade was sent "'..(decade or '')..'" as its 2nd parameter, '..
'but expects a 1 to 4-digit year ending in "0".')
return p.failedcat(errors, 'D')
end
local ndec = tonumber(dec)  
--sterilize mindecade & determine AD/BC
local mindefault = '-9999'
local mindec = sterilizedec(mindecade) --returns a tostring(unsigned int), or nil
if mindec then
if string.match(mindecade, '-%d') or
string.match(mindecade, 'BC')
then
mindec = '-'..mindec --better +/-0 behavior with strings (0-initialized int == "-0" string...)
end
elseif mindec == nil and mindecade and mindecade ~= '' then
errors = p.errorclass('Function nav_decade was sent "'..(mindecade or '')..'" as its 4th parameter, '..
'but expects a 1 to 4-digit year ending in "0", the earliest decade to be shown.')
return p.failedcat(errors, 'E')
else --mindec == nil
mindec = mindefault --tonumber later, after error checks
end  
--sterilize maxdecade & determine AD/BC
local maxdefault = '9999'
local maxdec = sterilizedec(maxdecade) --returns a tostring(unsigned int), or nil + error
if maxdec then
if string.match(maxdecade, '-%d') or
string.match(maxdecade, 'BC')
then --better +/-0 behavior with strings (0-initialized int == "-0" string...),
maxdec = '-'..maxdec --but a "-0" string -> tonumber -> tostring = "-0",
end --and a "0" string -> tonumber -> tostring = "0"
elseif maxdec == nil and maxdecade and maxdecade ~= '' then
errors = p.errorclass('Function nav_decade was sent "'..(maxdecade or '')..'" as its 5th parameter, '..
'but expects a 1 to 4-digit year ending in "0", the highest decade to be shown.')
return p.failedcat(errors, 'F')
else --maxdec == nil
maxdec = maxdefault
end  
local tspace = ' ' --assume trailing space for "1950s in X"-type cats
if string.match(lastpart, '^-') then tspace = '' end --DNE for "1970s-related"-type cats  
--AD/BC switches & vars  
local parentBC = string.match(lastpart, '^BC') --following the "0s BC" convention for all years BC
lastpart = mw.ustring.gsub(lastpart, '^BC%s*', '') --handle BC separately; AD never used
--TODO?: handle BCE, but only if it exists in the wild  
local dec0to40AD = (ndec >= 0 and ndec <= 40 and not parentBC) --special behavior in this range
local switchADBC = 1 -- 1=AD parent
if parentBC then switchADBC = -1 end -- -1=BC parent; possibly adjusted later
local BCdisp = ''
local D = -math.huge --secondary switch & iterator for AD/BC transition  
--check non-default min/max more carefully
if mindec ~= mindefault then
if tonumber(mindec) > ndec*switchADBC then
mindec = tostring(ndec*switchADBC) --input error; mindec should be <= parent
end
end
if maxdec ~= maxdefault then
if tonumber(maxdec) < ndec*switchADBC then
maxdec = tostring(ndec*switchADBC) --input error; maxdec should be >= parent
end
end
local nmindec = tonumber(mindec) --similar behavior to nav_year & nav_nordinal
local nmaxdec = tonumber(maxdec) --similar behavior to nav_nordinal  
--begin navdecade
local bnb = '' --/no
if navborder == false then --for Navseasoncats year and decade
bnb = ' -style: ; background-color: transparent;'
end
local navd = '{|\n'..'|\n'  
local i = -50 --nav position x 10
while i <= 50 do
local d = ndec + i*switchADBC  
local BC = ''
BCdisp = ''
if dec0to40AD then
if D < -10 then
d = math.abs(d + 10) --b/c 2 "0s" decades exist: "0s BC" & "0s" (AD)
BC = 'BC '
if d == 0 then
D = -10 --track 1st d = 0 use (BC)
end
elseif D >= -10 then
D = D + 10 --now iterate from 0s AD
d = D --2nd d = 0 use
end
elseif parentBC then
if switchADBC == -1 then --parentBC looking at the BC side (the common case)
BC = 'BC '
if d == 0 then --prepare to switch to the AD side on the next iteration
switchADBC = 1 --1st d = 0 use (BC)
D = -10 --prep
end
elseif switchADBC == 1 then --switched to the AD side
D = D + 10 --now iterate from 0s AD
d = D --2nd d = 0 use (on first use)
end
end
if BC ~= '' and ndec <= 50 then
BCdisp = ' BC' --show BC for all BC decades whenever a "0s" is displayed on the nav
end  
--determine target cat
local disp = d..'s'..BCdisp
local catlink = catlinkfollowr( , firstpart..' '..d..'s'..tspace..BC..lastpart, disp )
if catlink.rtarget then --a was followed
trackcat(18, 'Navseasoncats decade redirected')
end  
--populate / navd
local shown = navcenter(i, catlink)
local hidden = '<span>'..disp..'</span>'
local dsign = d --use d for display & dsign for logic
if BC ~= '' then dsign = -dsign end
if (nmindec <= dsign) and (dsign <= nmaxdec) then
if dsign == 0 and (nmindec == 0 or nmaxdec == 0) then --distinguish b/w -0 (BC) & 0 (AD)
--"zoom in" on +/- 0 and turn dsign/min/max temporarily into +/- 1 for easier processing
local zsign, zmin, zmax = 1, nmindec, nmaxdec
if BC ~= '' then zsign = -1 end
if mindec == '-0' then zmin = -1
elseif mindec == '0' then zmin = 1 end
if maxdec == '-0' then zmax = -1
elseif maxdec == '0' then zmax = 1 end  
if (zmin <= zsign) and (zsign <= zmax) then
navd = navd..shown
hidden = nil
else
navd = navd..'*'..hidden..'\n'
end
else
navd = navd..shown --the common case
hidden = nil
end
else
navd = navd..'*'..hidden..'\n'
end
if listall and hidden then
tlistall[#tlistall] = tlistall[#tlistall]..' ('..hidden..')'
end  
i = i + 10
end  
isolatedcat
if listall then
return listalllinks
else
return navd..'|}'
end
end  
--==========================================================  
local function nav_year( , firstpart, year, lastpart, minimumyear, maximumyear )
--Expects a PAGENAME of the form "Some sequential 1760 example cat", where
-- firstpart = Some sequential
-- year = 1760
-- lastpart = example cat
-- minimumyear = 1758 ('min' year parameter; optional)
-- maximumyear = 1800 ('max' year parameter; optional)
local minyear_default = -9999
local maxyear_default = 9999
year = tonumber(year) or tonumber(mw.ustring.match(year or '', '^%s*(%d*)'))
local minyear = tonumber(string.match(minimumyear or '', '-?%d+')) or minyear_default --allow +/- qualifier
local maxyear = tonumber(string.match(maximumyear or '', '-?%d+')) or maxyear_default --allow +/- qualifier
if string.match(minimumyear or '', 'BC') then minyear = -math.abs(minyear) end --allow BC qualifier (AD otherwise assumed)
if string.match(maximumyear or '', 'BC') then maxyear = -math.abs(maxyear) end --allow BC qualifier (AD otherwise assumed)  
if year == nil then
errors = p.errorclass('Function nav_year can\'t recognize the year sent to its 2nd parameter.')
return p.failedcat(errors, 'Y')
end  
--AD/BC switches & vars  
local yearBCElastparts = { --needed for parent = AD 1-5, when the BC/E format is unknown
--"BCE" removed to match both AD & BCE cats; easier & faster than multiple string.matchs
['example_Hebrew people_example'] = 'BCE', --example entry format; add to & adjust as needed
}
local parentAD = string.match(firstpart, 'AD$') --following the "AD 1" convention from AD 1 to AD 10
local parentBC = string.match(lastpart, '^BCE?') --following the "1 BC" convention for all years BC
firstpart = mw.ustring.gsub(firstpart, '%s*AD$', '') --handle AD/BC separately for easier & faster accounting
lastpart = mw.ustring.gsub(lastpart, '^BCE?%s*', '')
local BCe = parentBC or yearBCElastparts[lastpart] or 'BC' --"BC" default  
local year1to10 = (year >= 1 and year <= 10)
local year1to10ADBC = year1to10 and (parentBC or parentAD) --special behavior 1-10 for low-# non-year series
local year1to15AD = (year >= 1 and year <= 15 and not parentBC) --special behavior 1-15 for AD/BC display
local switchADBC = 1 -- 1=AD parent
if parentBC then switchADBC = -1 end -- -1=BC parent; possibly adjusted later
local Y = 0 --secondary iterator for AD-on-a-BC-parent