Mô đun:CanadaByProvinceCatNav

--
	v01.18: fix handling of definite article (e.g. for 'the Northwest Territories') 
each title consists of 3 parts- prefix- province name- suffix
e.g. "Foo in Quebec"- prefix = "Foo in "- province name = "Quebec"- suffix = ""
e.g. "Nunavut-related lists"- prefix = ""- province name = "Nunavut"- suffix = "-related lists"
-- config
local textSize = '90%'
local tableClass="toc"
local evenRowStyle = "vertical-align:top; background-color:#f3f3f3;"
local oddRowStyle = "vertical-align:top;"
local labelStyle = "text-align:right; font-weight: bold; padding: 0.25em 0.5em 0.25em 0.5em;"
local listStyle = "text-align:left; font-weight: normal; padding: 0.25em 0.5em 0.25em 0.5em;"
local greyLinkColor = "#888"
-- Note that the table styles are designed to ensure that the navbox is as wide as possible, while still leaving
enough enough space on the right for portal boxes, commons links, and GeoGroup templates.
A lot of fiddling was needed to make it work, so please test any chnages very carfully in the sandbox.
local tableFallbackMaxWidth="auto"
local tableMaxWidth="calc(100% - 25em)" -- Template:GeoGroup has width: 23em= 10 then
		return ""
	end
	if  greyLinkCount > 5 then
		return ""
	end
	return ""
end
function makeTableRow(rowLabel, provinceList)
	debugLog(2, "makeTableRow, label: ")
	if (rowLabel == nil) then
		rowLabel = "Theo tỉnh bangvà lãnh thổ"
		debugLog(nil, rowLabel)
	else
		rowLabel = mw.text.trim(rowLabel)
		debugLog(nil, " " .. rowLabel .. "")
	end
	tableRowNum = tableRowNum + 1
	local thisRow
	if (tableRowNum % 2) == 0 then
		debugLog(3, "Even-numbered")
		thisRow = '\n'
	else
		debugLog(3, "Odd-numbered")
		thisRow = '\n'
	end
	if not ((rowLabel == nil) or (rowLabel =="")) then
		thisRow = thisRow ..  .. rowLabel .. '\n'
	end
	-- now begin making the row contents
	thisRow = thisRow .. '\n'
	local i, aProvince
		debugLog(3, "Process provinceList")
	for i, aProvince in ipairs(provinceList) do
		debugLog(4, "No. " .. tostring(i) .. ": " .. aProvince .. "")
		myCatName = makeCatName(aProvince, title_prefix, title_suffix)
		thisRow = thisRow .. "* " .. makeCatLink(myCatName, aProvince) .. "\n"
	end
	thisRow = thisRow .. '\n'
	return thisRow
end
function makeTable()
	debugLog(1, "makeTable")
	tableRowNum = 0
	local myTable = '\n'
	myTable = myTable .. makeTableRow(nil, CanadaProvinces)
	myTable = myTable .. "\n"
	return myTable
end
-- Make a piped link to a category, if it exists
-- If it doesn't exist, just display the greyed the link title without linking
function makeCatLink(catname, disp)
	local displaytext
	if (disp ~= "") and (disp ~= nil) then
		-- use 'disp' parameter, but strip any leading word "the"
		displaytext = mw.ustring.gsub(disp, "^tThe%s+", "");
	else
		displaytext = catname
	end
	local fmtlink
	local catPage = mw.title.new( catname, "Category" )
	if (catPage.exists) then
		fmtlink = "" .. displaytext .. ""
		blueLinkCount = blueLinkCount + 1
	else
		fmtlink =  .. displaytext .. ""
		greyLinkCount = greyLinkCount + 1
	end
	return fmtlink
end
function makeCatName(provinceName, prefix, suffix)
	local thisCatName = prefix .. provinceName .. suffix
	debugLog(5, "thisCatName = " .. thisCatName .. "")
	--
		Now check whether the all following conditions are true
			1/ the provinceName begins with "the"
			2/ the category does NOT exist if we use "the "
			3/ the category does exist if we strip "the "
		 If those conditions are all true, them strip "the" 
	 
	if (mw.ustring.match(provinceName, "^tThe ") ~= nil) then
		debugLog(6, "ProvinceName begins with 'the'")
		local provinceNameStripped = mw.ustring.gsub(provinceName, "^tThe ", "", 1)
		local thisCatNameStripped = prefix .. provinceNameStripped .. suffix
		debugLog(6, "thisCatNameStripped = " .. thisCatNameStripped .. "")
		local testCatPage = mw.title.new(thisCatName, "Category" )
		local testCatPageStripped = mw.title.new(thisCatNameStripped, "Category" )
		if not testCatPage.exists then
			debugLog(7, "" .. testCatPage.fullText .. " .. does not exist") 
			if (testCatPageStripped.exists) then
				debugLog(7, "" .. testCatPageStripped.fullText .. " .. DOES exist, so use that") 
				return thisCatNameStripped
			end
		end
	end
	return thisCatName
end
function patternSearchEncode(s)
	return mw.ustring.gsub(s, "(%W)", "%%%1")
end
-- Does the pagename include a province name?
function findprovinceNameInPagename(pn, provinceList, description)
	local i, aProvince, testProvince
	debugLog(2, "checking " .. pn .." for a province name in province set: " .. description)
	for i, aProvince in ipairs(provinceList) do
		testProvince = aProvince
		debugLog(3, "testing: "  .. testProvince .. "")
		local testProvinceEncoded = patternSearchEncode(testProvince)
		-- For efficiency, the first test is a simple match as a a screening test
		-- If the bare county name is nowhere in the pagename, then no need for
		-- more precise checks
		-- This check would be one line in regex, but Lua pattern matching is cruder,
		--so we need several passes to ensure that any match is of a complete word
		debugLog(4, "simple match? ")
		if (not mw.ustring.match(pn, testProvinceEncoded)) then
			debugLog(nil, "Fail")
		else
			debugLog(nil, "Success")
			-- test for false positives
			local j, aFalsePositiveTest
			for j, aFalsePositiveTest in ipairs(falsePositiveChecks) do
				debugLog(5, "false positive test pattern '" .. aFalsePositiveTest .. "' ? ")
				if (mw.ustring.match(pn, aFalsePositiveTest)) then
					debugLog(nil, "Match, so fail")
					return nil
				end
				debugLog(nil, "No match, so OK")
			end
			debugLog(4, "match whole name? ")
			if (pn == testProvince) then
				debugLog(nil, "Yes")
				return testProvince
			end
			debugLog(nil, "No")
			debugLog(4, "match at start, followed by separator? ")
			if mw.ustring.match(pn, "^" .. testProvinceEncoded .. "^%w") then
				debugLog(nil, "Yes")
				return testProvince
			end
			debugLog(nil, "No")
			
			debugLog(4, "match at end, preceded by separator? ")
			if mw.ustring.match(pn, "^%w" .. testProvinceEncoded .. "$") then
				debugLog(nil, "Yes")
				return testProvince
			end
			debugLog(nil, "No")
			debugLog(4, "match anywhere, preceded and followed by separator? ")
			if mw.ustring.match(pn, "^%w" .. testProvinceEncoded .. "^%w") then
				debugLog(nil, "Yes")
				return testProvince
			end
			debugLog(nil, "No")
		end
		-- Special case: if the province name we are testing begins with a prefixed "the"
		debugLog(4, "does testProvince begin with 'the' ? ")
		if (mw.ustring.match(testProvince, "^tThe ") == nil) then
			debugLog(nil, "No")
		else
			debugLog(nil, "Yes")
		end
		if (mw.ustring.match(testProvince, "^tThe ") ~= nil) then
			local testProvinceStripped = mw.ustring.gsub(testProvince, "^tThe ", "", 1)
			local testProvinceStrippedEncoded = patternSearchEncode(testProvinceStripped)
			debugLog(4, "test pattern without leading definite article, i.e. '" .. testProvinceStrippedEncoded .. "' ? ")
			if (mw.ustring.match(pn, "^%w" .. testProvinceStrippedEncoded .. "^%w")  ~= nil)
			or (mw.ustring.match(pn, "^" .. testProvinceStrippedEncoded .. "^%w")  ~= nil)
			or (mw.ustring.match(pn, "^%w" .. testProvinceStrippedEncoded .. "$")  ~= nil)
			or (mw.ustring.match(pn, "^" .. testProvinceStrippedEncoded .. "$")  ~= nil) then
				debugLog(nil, "Yes")
				return testProvinceStripped
			end
			debugLog(nil, "No")
		end
	end
	return nil
end
-- parse the pagename to find 3 parts: prefix, province name, suffix
function parsePagename(pn)
	debugLog(1, "parsePagename: " .. pn .. "")
	local validprovinceName
	validprovinceName = findprovinceNameInPagename(pn, CanadaProvinces, "provincelst")
	if validprovinceName == nil then
		return false
	end
	
	-- if we get here, the page name "pn" includes a validprovinceName
	-- so now we need to split the string
	
	debugLog(2, "split pagename around " .. validprovinceName .. "")
	local validProvinceEncoded = mw.ustring.gsub(validprovinceName, "(%W)", "%%%1")
	match_prefix, match_province, match_suffix = mw.ustring.match(pn, "^(.*)(" .. validProvinceEncoded .. ")(.*)$")
	
	title_prefix = match_prefix
	title_suffix = match_suffix
	debugLog(2, "parse successful")
	debugLog(3, "title_prefix = " .. title_prefix .. "")
	debugLog(3, "thisPageProvince = " .. match_province .. "")
	debugLog(3, "title_suffix = " .. title_suffix .. "")
	return true
end
function publishDebugLog()
	if not debugging then
		return ""
	end
	return "==Debugging ==\n\n" .. debugmsg .. "\n== Output ==\n"
end
-- debugLog builds a log which can be output if debuging is enabled
-- each log entry is given a level, so that the output is not simply a flat list
-- a debug msg may be appended to the previous msg by setting the level to nil
function debugLog(level, msg)
	if (debugmsg == nil) then
		debugmsg = ""
	end
	if (level ~= nil) then
		-- not appending, so make a new line
		debugmsg = debugmsg .. "\n"
		-- then add the level
		local i
		for i = 1, level do
			if (i % 2) == 1 then
				debugmsg = debugmsg .. "#"
			else
				debugmsg = debugmsg .. "*"
			end
		end 
	end
	debugmsg = debugmsg .. " " .. msg
	return true
end
function getYesNoParam(args, thisParamName, defaultVal)
	local paramVal = argsthisParamName
	if paramVal == nil then
		paramVal = ""
	end
	debugLog(2, "Evaluate yes/no parameter: " .. thisParamName .. " = " .. paramVal .. "")
	debugLog(3, "default = " .. ((defaultVal and "Yes") or "No"))
	debugLog(3, "Evaluate as: ")
	local returnValue
	if paramVal == "" then
		returnValue = defaultVal
	else
		returnValue = yesno(argsthisParamName, defaultVal)
	end
	if (returnValue) then
		debugLog(nil, "Yes")
	else
		debugLog(nil, "No")
	end
	return returnValue
end
function makeErrorMsg(s)
	return  .. parentname .. ' Error: ' .. s .. '\n'
end
function isValidParent(p)
	local i, aParent
	for i, aParent in ipairs(callingTemplates) do
		if p == aParent then
			return true
		end
	end
	return false
end
function p.main(frame)
	local parent = frame:getParent()
	if parent then
		 parentname = parent:getTitle():gsub('/sandbox$', )
	end
	if (parentname == nil) or not isValidParent(parentname) then
		local errormsg = ' Error: ' .. parentname .. ' is not a valid wrapper for ' .. frame:getTitle() .. '\n'
		errormsg = errormsg .. 'Valid wrappers: '
		local i, aParent
		for i, aParent in ipairs(callingTemplates) do
			errormsg = errormsg ..  .. aParent  .. 
		end
		errormsg = errormsg .. 
		return errormsg
	end
	templateName = mw.ustring.gsub(parentname, "^Template:", "")
	
	debugLog(1, "Check parameters")
	debugging = getYesNoParam(frame.args, "debug", false)
	-- get the page title
	thispage = mw.title.getCurrentTitle()
	thispagename = thispage.text;
	
	debugLog(1, "mw.title.getCurrentTitle()")
	debugLog(2, "thispage.text = " .. thispage.text .."")
	debugLog(2, "thispage.namespace = " .. thispage.namespace .."")
	debugLog(2, "thispage.nsText = " .. thispage.nsText .."")
	debugLog(2, "is it a cat? using (thispage:inNamespace(14)): ")
	if not (thispage:inNamespace(14)) then
		debugLog(nil, "No, this is not a category")
		debugLog(1, "Not a category, so no output")
		return makeErrorMsg("only for use on a category page") .. publishDebugLog()
	end
	debugLog(nil, "Yes, this is a category")
	if not parsePagename(thispagename) then
		-- some error parsing the title, so don't proceed to output
		local trackingCatInvalid = ""
		return makeErrorMsg('the name of this category does not include a valid Candian province or territory') .. publishDebugLog() .. trackingCatInvalid
	end
	
	debugLog(1, "all parse done")
	debugLog(2, "title_prefix = " .. title_prefix .. "")
	debugLog(2, "title_suffix = " .. title_suffix .. "")
	
	local myNavTable = makeTable()
	debugLog(2, "blueLinkCount = " .. blueLinkCount .. ".   (NB The current page is always counted as a bluelink, but will not be navigable)")
	debugLog(2, "greyLinkCount = " .. greyLinkCount .. "")
	
	if (blueLinkCount <= 1) then
		-- This is a navbar to nowhere, so suppress display
		myNavTable = ""
		debugLog(1, "Zero bluelinks (other than the current page) makes this a navbox to nowhere, so do not display the navbox")
	end
	
	local myTrackingCat = makeTrackingCategory()
	return publishDebugLog() .. myNavTable .. myTrackingCat
end
return p