Mô đun:Television infoboxes disambiguation check

local libraryUtil = require('libraryUtil')
--=============================================================--
-- DisambiguationPattern class.
local function DisambiguationPattern(o)
	local DisambiguationPattern = o or {pattern = "", type = ""}
	local checkSelf = libraryUtil.makeCheckSelfFunction( 'Television infoboxes disambiguation check', 'DisambiguationPattern', DisambiguationPattern, 'Television infoboxes disambiguation check object' )
	return DisambiguationPattern
end
--=============================================================--
-- Constants.
local DAB_VALID = {
	true = "valid",
	false = "invalid"
}
local CATEGORY_INCORRECT = ""
local validationTypeList = {
	"VALIDATION_TYPE_YEAR_COUNTRY" = 1,
	"VALIDATION_TYPE_YEAR" = 2,
	"VALIDATION_TYPE_COUNTRY" = 3,
	"VALIDATION_TYPE_YEAR_SEASON_NUMBER" = 4,
	"VALIDATION_TYPE_COUNTRY_SEASON_NUMBER" = 5,
	"VALIDATION_TYPE_SEASON_NUMBER" = 6,
	"VALIDATION_TYPE_COUNTRY_SEASON" = 7,
	"VALIDATION_TYPE_YEAR_COUNTRY_SEASON_NUMBER" = 8
}
local debugMessageList = {
	"DEBUG_EMPTY_TITLE" = "Debug: Error: Empty title.",
	"DEBUG_NO_DAB" = "Debug: No disambiguation.",
	"DEBUG_TITLE_ON_EXCEPTION" = "Debug: Title on exception list.",
	"DEBUG_VALID_FORMAT" = "Debug: Using a valid format.",
	"DEBUG_NOT_VALID_FORMAT" = "Debug: Not a valid format.",
	"DEBUG_YEAR_COUNTRY" = "Debug: Using a valid format with an extended Year and Country - {}.",
	"DEBUG_YEAR" = "Debug: Using a valid format with an extended Year - {}.",
	"DEBUG_COUNTRY" = "Debug: Using a valid format with an extended Country - {}.",
	"DEBUG_INCORRECT_STYLE" = "Debug: Using a valid format but using an incorrect extended style.",
	"DEBUG_INCORRECT_INFOBOX" = "Debug: Using incorrect infobox - {}.",
	"DEBUG_YEAR_SEASON_NUMBER" = "Debug: Using a valid format with an extended Year and Season number - {}.",	
	"DEBUG_COUNTRY_SEASON_NUMBER" = "Debug: Using a valid format with an extended Country and Season number - {}.",	
	"DEBUG_SEASON_NUMBER" = "Debug: Using a valid format with a Season number - {}.",
	"DEBUG_COUNTRY_SEASON" = "Debug: Using a valid format with a Country and the word Season - {}.",
	"DEBUG_YEAR_COUNTRY_SEASON_NUMBER" = "Debug: Using a valid format with an extended Year, Country and Season number - {}."
}
-- Local function which checks if both booleans are true or not.
local function validateTwoParameters(isValid1, isValid2)
	if (isValid1 and isValid2) then
		return true
	else
		return false
	end
end
-- Validate that the season number entered is a valid number -
-- that it does not start with a leading zero (0).
local function validateSeasonNumber(seasonNumber)
	if (tonumber(string.sub(seasonNumber, 1, 1)) == 0) then
		return false
	else
		return true
	end
end
-- Validate that the year entered is a valid year.
local function validateYear(year)
	if (string.len(year) == 4) then
		return true
	else
		return false
	end
end
-- Validate that the text entered is a supported country adjective.
local function validateCountryAdjective(adjective)
	local data = mw.loadData('Module:Country adjective')
	-- Search for a country corresponding to the given text.
	if (data.getCountryFromAdjadjective) then
		return true
	else
		return false
	end
end
-- Checks pages using by validating the disambiguation patterns.
local function validatePatterns(disambiguation, disambiguationPatternList)
	local year = ""
	local adjective = ""
	local seasonNumber = ""
	local isYearValid
	local isAdjectiveValid
	local isSeasonNumberValid
	for i, v in ipairs(disambiguationPatternList) do
		local currentDisambiguationPattern = disambiguationPatternListi
		if (disambiguation:match(currentDisambiguationPattern.pattern)) then
			
			-- Year and Country styles: "1999 American TV series"
			if (currentDisambiguationPattern.type == validationTypeList"VALIDATION_TYPE_YEAR_COUNTRY") then
				year, adjective = disambiguation:match(currentDisambiguationPattern.pattern)
				isYearValid = validateYear(year)
				isAdjectiveValid = validateCountryAdjective(adjective)
				local isValid = validateTwoParameters(isYearValid, isAdjectiveValid)
				return isValid, debugMessageList"DEBUG_YEAR_COUNTRY":gsub("{}", DAB_VALIDisValid)
			-- Year styles: "1999 TV series"
			elseif (currentDisambiguationPattern.type == validationTypeList"VALIDATION_TYPE_YEAR") then
				year = disambiguation
				isYearValid = validateYear(year)
				return isYearValid, debugMessageList"DEBUG_YEAR":gsub("{}", DAB_VALIDisYearValid)
			-- Country styles: "American TV series"
			elseif (currentDisambiguationPattern.type == validationTypeList"VALIDATION_TYPE_COUNTRY") then
				adjective = disambiguation
				isAdjectiveValid = validateCountryAdjective(adjective)
				return isAdjectiveValid, debugMessageList"DEBUG_COUNTRY":gsub("{}", DAB_VALIDisAdjectiveValid)
			-- Year and Season number styles: "1999 TV series, season 1"
			elseif (currentDisambiguationPattern.type == validationTypeList"VALIDATION_TYPE_YEAR_SEASON_NUMBER") then
				year, seasonNumber = disambiguation:match(currentDisambiguationPattern.pattern)
				isYearValid = validateYear(year)
				isSeasonNumberValid = validateSeasonNumber(seasonNumber)
				local isValid = validateTwoParameters(isYearValid, isSeasonNumberValid)
				return isValid, debugMessageList"DEBUG_YEAR_SEASON_NUMBER":gsub("{}", DAB_VALIDisValid)
			-- Country and Season number styles: "American season 1" and "American TV series, season 1"
			elseif (currentDisambiguationPattern.type == validationTypeList"VALIDATION_TYPE_COUNTRY_SEASON_NUMBER") then
				adjective, seasonNumber = disambiguation:match(currentDisambiguationPattern.pattern)
				isAdjectiveValid = validateCountryAdjective(mw.text.trim(adjective))
				isSeasonNumberValid = validateSeasonNumber(seasonNumber)
				
				local isValid = validateTwoParameters(isAdjectiveValid, isSeasonNumberValid)
				return isValid, debugMessageList"DEBUG_COUNTRY_SEASON_NUMBER":gsub("{}", DAB_VALIDisValid)
			-- Country and the word season: "American season"
			elseif (currentDisambiguationPattern.type == validationTypeList"VALIDATION_TYPE_COUNTRY_SEASON") then
				adjective = disambiguation:match(currentDisambiguationPattern.pattern)
				isAdjectiveValid = validateCountryAdjective(mw.text.trim(adjective))
				return isAdjectiveValid, debugMessageList"DEBUG_COUNTRY_SEASON":gsub("{}", DAB_VALIDisAdjectiveValid)
			--Season number styles: "season 1"
			elseif (currentDisambiguationPattern.type == validationTypeList"VALIDATION_TYPE_SEASON_NUMBER") then
				seasonNumber = disambiguation:match(currentDisambiguationPattern.pattern)
				isSeasonNumberValid = validateSeasonNumber(seasonNumber)
				return isSeasonNumberValid, debugMessageList"DEBUG_SEASON_NUMBER":gsub("{}", DAB_VALIDisSeasonNumberValid)
			-- Year, Country and Season number styles: "Gladiators (2008 British TV series, series 2)"
			elseif (currentDisambiguationPattern.type == validationTypeList"VALIDATION_TYPE_YEAR_COUNTRY_SEASON_NUMBER") then
				year, adjective, seasonNumber = disambiguation:match(currentDisambiguationPattern.pattern)
				isYearValid = validateYear(year)
				isAdjectiveValid = validateCountryAdjective(mw.text.trim(adjective))
				isSeasonNumberValid = validateSeasonNumber(seasonNumber)
				
				local isValid = validateTwoParameters(isYearValid, isAdjectiveValid)
				isValid = validateTwoParameters(isValid, isSeasonNumberValid)
				return isValid, debugMessageList"DEBUG_YEAR_COUNTRY_SEASON_NUMBER":gsub("{}", DAB_VALIDisValid)
				
			-- Not a valid supported style.
			else
				-- Do nothing.
			end
		else
			-- Do nothing.
		end
	end
	return false, debugMessageList"DEBUG_INCORRECT_STYLE"
end
-- Validate that the disambiguation type is one of the supported types.
local function validateDisambiguationType(disambiguation, validDisambiguationTypeList)
	local extendedDisambiguation
	local count = 0
	
	for i, v in ipairs(validDisambiguationTypeList) do
		extendedDisambiguation, count = disambiguation:gsub(v, )
		extendedDisambiguation = mw.text.trim(extendedDisambiguation)
		if (count ~= 0) then
			-- Disambiguation was a valid type; Exit loop.
			break
		end
	end
	
	count = count ~= 0 
	return count, extendedDisambiguation
end
-- Validate that the complete disambiguation is using a supported style.
local function validateDisambiguation(invoker, disambiguation, validDisambiguationTypeList, validDisambiguationPatternList)
	-- Check if the list is empty.
	if (table.getn(validDisambiguationTypeList) ~= 0) then
		local isDisambiguationValid, extendedDisambiguation = validateDisambiguationType(disambiguation, validDisambiguationTypeList)
	
		-- Exit module if the disambiguation type is not a supported style.
		if (not isDisambiguationValid) then
			return false, debugMessageList"DEBUG_NOT_VALID_FORMAT"
		end

		-- Check if there is no extended disambiguation.
		if (extendedDisambiguation == ) then
			return true, debugMessageList"DEBUG_VALID_FORMAT"
		end
		
		-- A bit of hack so I won't need to refactor a ton of code.
		if (invoker ~= "infobox television season") then
			disambiguation = extendedDisambiguation
		end
	end
	
	return validatePatterns(disambiguation, validDisambiguationPatternList)
end
-- Check if the page is using disambiguation style that belongs to a different infobox.
local function isPageUsingIncorrectInfobox(disambiguation, otherInfoboxList)
	for k, v in pairs(otherInfoboxList) do
		if (string.match(disambiguation, k)) then
			return true, v, debugMessageList"DEBUG_INCORRECT_INFOBOX":gsub("{}", k)
		end
	end
	return false
end
-- Validate that the title has brackets that are part of the title and not part of disambiguation.
local function isOnExceptionList(title, exceptionList)
	for _, v in ipairs(exceptionList) do
		if (v == title) then
			return true
		elseif (string.match(title, v)) then
			return true
		end
	end
	return false
end
-- Get the disambiguation text and make sure that if the title has more than 1 pair of brackets, it returns the last one.
local function getDisambiguation(title)
	local match = require("Module:String")._match
	return match(title, "%s%((.-)%)", 1, -1, false, "")
--	return (string.match (title, '%s*%b()$') or ):gsub('%(%)', )
end
-- Validate that arg is not nill and not empty.
local function isEmpty(arg)
	if (not arg or arg == "") then
		return true
	else
		return false
	end
end
-- Returns two objects:
--- The first is either an empty string or a tracking category which will appear when using the live version.
--- The second is a debug string which will appear when using /testcases.
local function main(title, invoker, validDisambiguationTypeList, validDisambiguationPatternList, exceptionList, otherInfoboxList, invalidTitleStyleList)
	-- Exit module if the parameter has no value.
	if (isEmpty(title)) then
		return "", debugMessageList"DEBUG_EMPTY_TITLE"
	end
	-- Exit module if the title has brackets that are part of the title (not disambiguation).
	if (isOnExceptionList(title, exceptionList)) then
		return "", debugMessageList"DEBUG_TITLE_ON_EXCEPTION"
	end
	
	if (invoker == "infobox television season") then
		if (#invalidTitleStyleList ~= 0) then
			for i = 1, #invalidTitleStyleList do
				if (string.find(title, invalidTitleStyleListi)) then
					return CATEGORY_INCORRECT, debugMessageList"DEBUG_NOT_VALID_FORMAT"
				end
			end
		end
	end
		
				
	-- Get the disambiguation.
	local disambiguation = getDisambiguation(title)
	-- Exit module if the title has no disambiguation.
	if (isEmpty(disambiguation)) then
		return "", debugMessageList"DEBUG_NO_DAB"
	end
	-- Exit module if the disambiguation belongs to a different infobox.
	local isValid, category, debugString = isPageUsingIncorrectInfobox(disambiguation, otherInfoboxList)
	if (isValid) then
		return category, debugString
	end
	
	-- Check if the disambiguation is valid.
	isValid, debugString = validateDisambiguation(invoker, disambiguation, validDisambiguationTypeList, validDisambiguationPatternList)
	
	-- Check if the disambiguation is not valid and add category.
	if (not isValid) then
		category = CATEGORY_INCORRECT
	end
	return category, debugString
end
return {
	main = main,
	DisambiguationPattern = DisambiguationPattern
	}