모듈:Infobox television season name

require('strict')
local match = require("Module:String")._match
local p = {}
--- Returns a formatted link to the list of episodes article.
--- @param listOfEpisodesArticle string
--- @return string
local function getListOfEpisodesLink(listOfEpisodesArticle)
	local listOfEpisodesPage = mw.title.new(listOfEpisodesArticle, 0)
	if listOfEpisodesPage and listOfEpisodesPage.exists and listOfEpisodesPage.redirectTarget ~= mw.title.getCurrentTitle() then
		return string.format("에피소드 목록", listOfEpisodesArticle)
	end
end
--- Returns an article link.
--- @param article string The article's title.
--- @param pipedLink string The piped link.
--- @return string
local function getArticleLink(article, pipedLink)
	if not pipedLink or pipedLink == "" then
		return "" .. article .. ""
	end
	return "" .. pipedLink .. ""
end
--- Returns the show name and season number from a title.
--- @param showName string The show's title.
--- @return nil | number | string, nil | number | string
local function getShowNameAndSeasonNumberFromShowName(showName)
	local _, _, showNameModified, seasonNumber = string.find(showName, "(.*)%s+(%d+)$")
	return showNameModified, seasonNumber
end
--- Returns the current season number from the disambiguation.
--- @param disambiguation string The article's disambiguation.
--- @return string
local function getCurrentSeasonNumberFromDisambiguation(disambiguation)
	return match(disambiguation , "%d+", 1, -1, false, "")
end
--- Returns the type of word used for "season" in the title.
---
--- The returned value can be one of three options: "season", "series", "story arc" or "specials".
--- @param title string The article's title.
--- @return string
local function getSeasonType(title)
	for _, seasonType in pairs({"시즌", "시리즈", "스페셜", "특집", "스토리 아크"}) do
		if string.find(title, seasonType) then
			return seasonType
		end
	end
	return "시즌"
end
--- Returns the season number from the title.
--- @param title string The article's title.
--- @return string | nil
local function getSeasonNumber(title)
	return match(title , "%d+", 1, -1, false, "")
end
--- Returns the disambiguation from the title.
--- @param title string The article's title.
--- @return string | nil
local function getDisambiguation(title)
	local disambiguation = match(title, "%s%((.-)%)", 1, -1, false, "")
	if disambiguation and disambiguation == "" then
		return nil
	end
	return disambiguation
end
--- Returns the title without its disambiguation.
--- @param title string The article's title.
--- @return string | nil
local function getTitleWithoutDisambiguation(title)
	local disambiguation = getDisambiguation(title)
	if disambiguation then
		return string.gsub(title, "%(" .. disambiguation  .. "%)", "")
	end
	return title
end
--- Returns the TV program's disambiguation.
--- @param disambiguation string The disambiguation used in the season's article title.
--- @return string
local function getTVProgramDisambiguation(disambiguation)
	if not disambiguation then
		return ""
	end
	-- Check if the disambiguation is normal 'season #' or 'series #'.
	-- If so, remove disambiguation.
	if string.match(disambiguation, "^시즌 %d*$") or string.match(disambiguation, "^시리즈 %d*$") then
		return ""
	end
	local disambiguationStyle = " (%s)"
	-- Check if the disambiguation is extended and has 'TV series' and isn't just season #.
	-- Only leave the TV series disambiguation, not including the season #.
	-- Example: Teenage Mutant Ninja Turtles (1987 TV series, season 5) will return '1987 TV series'.
	if string.find(disambiguation, "텔레비전 프로그램") then
		local shortDisambiguation, _ = disambiguation:match("^(.*),")
		if shortDisambiguation then
			return string.format(disambiguationStyle, shortDisambiguation)
		end
	end
	-- Check if the disambiguation is extended with country adjective.
	-- Example: The Office (American season 2) will return "American season 2".
	-- Keep only country adjective.
	local countryDisambiguation = disambiguation:match("^(.*) 시즌 %d*") or disambiguation:match("^(.*) 시리즈 %d*")
	local data = mw.loadData("Module:Country adjective")
	local valid_result = data.getCountryFromAdjcountryDisambiguation
	-- Check if the country adjective is valid.
	if valid_result then
		-- Add 'TV series' suffix
		return string.format(disambiguationStyle, countryDisambiguation .. " TV series")
	end
	-- Not a known disambiguation style. Use whatever was used in the title or manually added.
	-- Note: might not be a valid style link.
	return string.format(disambiguationStyle, disambiguation)
end
--- Returns the show's name from the title.
--- @param title string The article's title.
--- @return string
local function getShowName(title)
	local name, _ = mw.ustring.gsub(title, "시즌 %d*$", "")
	name, _ = mw.ustring.gsub(name, "시리즈 %d*$", "")
	name, _ = mw.ustring.gsub(name, "스페셜", "")
	name, _ = mw.ustring.gsub(name, "특집", "")
	name, _ = mw.ustring.gsub(name, "스토리 아크 %d*$", "")
	name = string.match(name, "^%s*(.-)%s*$") -- Trim spaces.
	return name
end
--- Returns "true" if the given link is valid; nil otherwise.
--- A link is valid in the following cases:
---	-- A season article exists.
---	-- A redirect exists to a season section.
---
--- A link is invalid in the following cases:
---	-- A season article or redirect do not exist.
---	-- A redirect exists, but it is a general redirect and not for any specific season section.
---
--- Note: Return values are not booleans as the returned value is used in template space.
--- @param title string The article's title.
--- @return string | nil
local function isLinkValid(title)
	local article = mw.title.new(title)
	-- Article or redirect do not exist; Not a valid link.
	if not article or not article.exists then
		return nil
	end
	local redirectTarget = article.redirectTarget
	-- Article exists and is not a redirect; Valid link.
	if not redirectTarget then
		return "true"
	end
	local fullLink = redirectTarget.fullText
	local isSection = fullLink:find("#")
	-- Article is a section redirect; Valid link.
	if isSection then
		return "true"
	end
	-- Article is a general redirect; Not a valid link.
	return nil
end
--- Returns a season article title and a piped link.
---
--- The following are the supported season naming styles:
---	--  Style:   
---		Example: Lost season 2.
---		Example: Doctor Who series 2.
---	--  Style:  ( TV series)  
---		Example: The Office (American TV series) season 2.
---		Example: Teenage Mutant Ninja Turtles (1987 TV series) season 2
---		Example: X Factor (British TV series) series 2.
---		Example: Love Island (British TV series) series 2
---	--  Style:  ( TV series)  
---		Example: Love Island (2015 TV series) series 2
---	--  Style:  ( )
---		Example: Big Brother 2 (American season).
--- @param title string The article's title.
--- @param seasonNumberDiff number The number difference between the current season and the other season.
--- @return string, string
local function getArticleTitleAndPipedLink(title, seasonNumberDiff)
	local seasonType = getSeasonType(title)
	local currentSeasonNumber = getSeasonNumber(title)
	if tonumber(currentSeasonNumber) == nil then
		return "", nil
	end
	local seasonNumber = currentSeasonNumber + seasonNumberDiff
	local modifiedTitle, numberOfReplacements = string.gsub(title, "%d+$", seasonNumber)
	local pipedLink = seasonType:gsub("^%l", string.upper) .. " " .. seasonNumber
	local disambiguation = getDisambiguation(title)
	-- Titles such as "Big Brother 2 (American season) and Teenage Mutant Ninja Turtles (1987 TV series) season 2".
	if disambiguation then
		local titleWithoutDisambiguation = string.gsub(title, disambiguation, "_DAB_")
		modifiedTitle, numberOfReplacements = string.gsub(titleWithoutDisambiguation, "%d+", seasonNumber)
		 -- Articles, such as "Hawaii Five-0 (2010 TV series) season 2", that have a number
		 -- as part of their title will need an additional fix in order for that number not to change.
		if numberOfReplacements > 1 then
			local titleFix = string.match(title, "%d+", 1)
			modifiedTitle = string.gsub(modifiedTitle, "%d+", titleFix, 1)
		end
	
		modifiedTitle = string.gsub(modifiedTitle, "_DAB_", disambiguation)
		return modifiedTitle, pipedLink
	-- Titles such as "Big Brother Brasil 2".
	elseif not string.find(title, seasonType) then
		return modifiedTitle, nil
	-- Invalid usages of TV series articles with the television season infobox.
	elseif disambiguation and string.find(disambiguation, "TV series") and not (string.find(disambiguation, ", season") or string.find(disambiguation, ", series"))  then
		return "", nil
	-- Standard titles such as "Lost season 1".
	else
		return modifiedTitle, pipedLink
	end
end
--- Returns the article's title either from args (usually from /testcases) or from the page itself.
--- @param frame table The frame invoking the module.
--- @return string
local function getTitle(frame)
	local getArgs = require("Module:Arguments").getArgs
	local args = getArgs(frame)
	
	local title = args.title
	if not title then
		title = mw.title.getCurrentTitle().text
	end
	return title
end
--- Returns "true" if the given season link is valid; nil otherwise.
--- @param frame table The frame invoking the module.
--- @param seasonNumberDiff number The number difference between the current season and the other season.
--- @return string | nil
local function isSeasonLinkValid(frame, seasonNumberDiff)
	local title = getTitle(frame)
	local articleTitle, _ = getArticleTitleAndPipedLink(title, seasonNumberDiff)
	return isLinkValid(articleTitle)
end
--- Returns a season article link.
--- @param frame table The frame invoking the module.
--- @param seasonNumberDiff number The number difference between the current season and the other season.
--- @return string
local function getSeasonArticleLink(frame, seasonNumberDiff)
	local title = getTitle(frame)
	local articleTitle, pipedLink = getArticleTitleAndPipedLink(title, seasonNumberDiff)
	return getArticleLink(articleTitle, pipedLink)
end
--- Returns "true" if the season link for the next season is valid; nil otherwise.
--- @param frame table The frame invoking the module.
--- @return string | nil
function p.isNextSeasonLinkValid(frame)
	return isSeasonLinkValid(frame, 1)
end
--- Returns "true" if the season link for the previous season is valid; nil otherwise.
--- @param frame table The frame invoking the module.
--- @return string | nil
function p.isPrevSeasonLinkValid(frame)
	return isSeasonLinkValid(frame, -1)
end
--- Returns "true" if the season link for the previous or next season is valid; nil otherwise.
--- @param frame table The frame invoking the module.
--- @return string | nil
function p.isPrevOrNextSeasonLinkValid(frame)
	if p.isPrevSeasonLinkValid(frame) == "true" then
		return "true"
	end
	return p.isNextSeasonLinkValid(frame)
end
--- Returns the next season article title.
--- @param frame table The frame invoking the module.
--- @return string
function p.getNextSeasonArticle(frame)
	return getSeasonArticleLink(frame, 1)
end
--- Returns the previous season article title.
--- @param frame table The frame invoking the module.
--- @return string
function p.getPrevSeasonArticle(frame)
	return getSeasonArticleLink(frame, -1)
end
--- Returns the type of season word used - "season" or "series".
--- @param frame table The frame invoking the module.
--- @return string
function p.getSeasonWord(frame)
	local title = getTitle(frame)
	title = getTitleWithoutDisambiguation(title)
	local seasonType = getSeasonType(title)
	return seasonType
end
--- Returns the text used for the |above= field of the infobox.
---
--- @param frame table
--- @return string
function p.getAboveTitle(frame)
local getArgs = require("Module:Arguments").getArgs
local args = getArgs(frame)
local title = getTitle(frame)
-- 제목에서 '의 에피소드 목록' 또는 '(2017년)'과 같은 부분을 제거
local showName = getShowName(getTitleWithoutDisambiguation(title))
-- "의 에피소드 목록"과 "(2017년)" 제거
showName = string.gsub(showName, "의 에피소드 목록", "")  -- '의 에피소드 목록' 제거
showName = string.gsub(showName, "%(%d+년%)", "")  -- "(2018년)"과 같은 연도 제거

-- showName을 반환하여 프로그램 이름만 추출
return showName
end
--- Returns the text used for the |subheader= field of the infobox.
---
--- The text is returned in the format of "Season #" or "Series #",
--- depending on either what the article disambiguation uses, or on the manually entered parameters of the infobox.
--- @param frame table The frame invoking the module.
--- @return string | nil
function p.getSubHeader(frame)
local getArgs = require("Module:Arguments").getArgs
local args = getArgs(frame)
-- args에 시즌 번호 또는 시리즈 번호가 제공되었는지 확인
local seasonType
local seasonNumber
if (args'시즌번호') then
seasonType = "시즌"
seasonNumber = args'시즌번호'
elseif (args'시리즈번호') then
seasonType = "시리즈"
seasonNumber = args'시리즈번호'
end
-- args에 시즌 번호나 시리즈 번호가 없으면 제목에서 정보를 추출
if not seasonNumber then
local title = getTitle(frame)
local titleWithoutDisambiguation = getTitleWithoutDisambiguation(title)

-- "에피소드 목록"이 포함된 제목인 경우, 년도를 반환하도록 수정
if string.find(title, "에피소드 목록") then
-- 괄호 안의 년도 추출 (예: (2017년)에서 2017년을 추출)
local year = string.match(title, "%((%d+)년%)")
if year then
return year .. "년"  -- 2017년 형태로 반환
end
end
seasonNumber = getSeasonNumber(titleWithoutDisambiguation)
seasonType = getSeasonType(titleWithoutDisambiguation)

-- 특집인 경우에는 특집 정보 포함
if (seasonType == "특집" or seasonType == "스페셜") then
local disambiguation = getDisambiguation(title) or ""
return disambiguation .. " " .. seasonType
end
-- 시즌, 시리즈 정보가 있으면 첫 글자만 대문자로 변환
seasonType = seasonType:sub(1, 1):upper() .. seasonType:sub(2)
end
-- 시즌 번호가 있으면 반환
if seasonNumber and seasonNumber ~= "" then
return seasonType .. " " .. seasonNumber
end
return nil
end
--- Returns a formatted link to the list of episodes article.
---
--- The returned link is in the style of:
--- List of episodes
---
--- The link will only return if the page exists.
--- @param frame table The frame invoking the module.
--- @return string | nil
function p.getListOfEpisodes(frame)
	local getArgs = require("Module:Arguments").getArgs
	local args = getArgs(frame)
	if args.link then
		-- Parameter should be unformatted.
		if string.find(args.link, "%") then
			local delink = require("Module:Delink")._delink
			args.link = delink({args.link, wikilinks = "target"})
		end
		return getListOfEpisodesLink(args.link)
	end
	local title = getTitle(frame)
	local showName = getShowName(getTitleWithoutDisambiguation(title))
	if showName then
		local disambiguation = getDisambiguation(title)
		if disambiguation then
			disambiguation = " (" .. disambiguation .. ")"
		end
		local listOfEpisodesArticle = string.format("%s%s의 에피소드 목록", showName, disambiguation or "")
		return getListOfEpisodesLink(listOfEpisodesArticle)
	end
end
return p