Module:CFB schedule

local p = {} local horizontal = require('Module:List').horizontal

local dagger = ' '

local haslocgamename = false local hasoppgamename = false local haslocrivalry = false local hasopprivalry = false local hasrank = false local hasstrangescore = false local hasnowrap = false

local function isnotempty(s) return s and s:match( '^%s*(.-)%s*$' ) ~= '' end

local function yesno(s, d)	s = (s or ''):lower if (s == 'no' or s == 'n') then return false elseif (s == 'yes' or s == 'y') then return true else return d	end end

local function ifexist(page) if not page then return false end if mw.title.new(page).exists then return true end return false end

local function getdivision(y) if y >= 2006 then return 'NCAA Division I FBS' elseif y >= 1978 then return 'NCAA Division I-A' elseif y >= 1973 then return 'NCAA Division I'	elseif y >= 1956 then return 'NCAA University Division' elseif y >= 1910 then return 'NCAA' elseif y >= 1906 then return 'Intercollegiate Athletic Association of the United States' else return 'college' end

return '' end

local function getpolltext(y, d, p)	-- default poll is the Coaches poll if (p or ) ==  then p = 'Coaches\'' end

-- if p is linked then just return p	if (p or ''):find('[%[%]]') then return p	end

-- else if y is a number if isnotempty(y) and tonumber(y) then if (d or ) ==  then d = getdivision(tonumber(y)) end

return '' .. p .. ' Poll' .. ' released prior to the game' end

-- else if d is not empty if isnotempty(d) then d = d .. ' '

if ifexist(d .. p .. ' Poll') then return '' .. p .. ' Poll' .. ' released prior to the game' end end

-- else if p Poll is an article if ifexist(p .. ' Poll') then return (d or '') .. '' .. p .. ' Poll' .. ' released prior to the game' end

return (d or '') .. p .. ' poll released prior to the game' end

local function getopp(s, atvs, movegn) s = mw.ustring.gsub(s, '<[%s/]*[Nn][Cc][Gg][%s/]*>', ' * ') s = mw.ustring.gsub(s, '<[%s/]*[Hh][Cc][%s/]*>', dagger) atvs = mw.ustring.gsub(atvs or '', '^%s*@%s*', 'at') atvs = mw.ustring.gsub(atvs or '', '^%s*[Vv][Ss]?[%.%s]*', 'vs.') s = mw.ustring.gsub(s, '^([A-Za-z%.%s]*)[Nn][Oo][%.%s]*([0-9])', '%1 No. %2' ) s = mw.ustring.gsub(s, '^([A-Za-z%.%s]*)#([0-9])', '%1 No. %2') if mw.ustring.match(s, 'No%. %d') then hasrank=true end local gn, r = ,  if mw.ustring.match(s, '[Nn][Oo][Ww][Rr][Aa][Pp]') then hasnowrap = true end if mw.ustring.match(s, '[Nn][Bb][Ss][Pp]') then hasnowrap = true end if mw.ustring.match(s, '^.*%s*%(%s*%[%^%[%*%]%]%s*%)%s*.*$') then if mw.ustring.match(s, '%(%[%^%[%*%|%s*[Rr]ivalry') then			hasopprivalry = true		else			hasoppgamename = true		end		if movegn == true then			s, gn, r = mw.ustring.match(s, '^(.*)%s*%(%s*(%[%^%[%*%]%])%s*%)(%s*.*)$')		end	end	if atvs ~= '' then atvs = atvs .. ' ' end	return atvs .. s .. r, gn end

local function getrank(s) s = mw.ustring.gsub(s, '^%s*([%d][%d]*)', 'No. %1') s = mw.ustring.gsub(s, '^%s*(T)[%-–%s]*([%d][%d]*)', 'No. %1–%2') return s end

local function getsite(stadium, location, game_name) if isnotempty(stadium) and isnotempty(location) then game_name = mw.ustring.gsub(game_name, '^%s*', '') if isnotempty(game_name) then game_name = mw.ustring.gsub(game_name, '^([Rr][Ii][Vv][Aa][Ll][Rr][Yy])$', '%1') game_name = mw.ustring.gsub(game_name, '^([^%[%]]*)$', '%1') game_name = ' (' .. game_name .. ')' end if mw.ustring.match(location, '%s%(%[%[') then			if mw.ustring.match(location, '%s%(%[%^%*%|%s*[Rr]ivalry') then haslocrivalry = true else haslocgamename = true end end return horizontal({stadium, location .. game_name}) else game_name = mw.ustring.gsub(game_name, '^%s*', '') if isnotempty(game_name) then game_name = ' (' .. game_name .. ')' end return stadium .. location .. game_name end end

local function setbg(WL,N) local BG = 'inherit' WL = mw.ustring.gsub(WL, '^%s*(.-)%s*$', '%1') WL = WL:upper if WL == 'W' then BG = '#DDFFDD' elseif WL == 'L' then BG = '#FFDDDD' elseif WL == 'T' then BG = '#FFFFE6' elseif WL == 'V' then BG = '#F0E8E8' WL = 'W' N = N .. ' (vacated)' end return BG, WL, N end

local function parse4(p, s)	local t = {, , , } for k = 1,4 do t[k] = mw.ustring.gsub(s, p, '%' .. k)	end local wl, sc, n, bg = t[1], t[2] .. '–' .. t[3], t[4], 'inherit' bg, wl, n = setbg(wl, n) return ' ' .. wl .. ' ' .. sc .. n, bg end local function getresult(wl, s, n)	local bg = 'inherit'

local loopnum = 0 while (mw.ustring.match(s, '&[Nn][Bb][Ss][Pp];') and loopnum < 5) do		hasstrangescore = true s = mw.ustring.gsub(s, '&[Nn][Bb][Ss][Pp];', ' ') s = mw.ustring.gsub(s, '<%s*[Ss][Pp][Aa][Nn][^<>]*>%s*', ' ') loopnum = loopnum + 1 end s = mw.ustring.gsub(s, '&[Nn][Bb][Ss][Pp];%s*(<[%s/]*[0-9]*OT[%s/]*>)', ' %1') s = mw.ustring.gsub(s, '%s*<([0-9]*)[Oo][Tt]>', ' %1OT') s = mw.ustring.gsub(s, '&[MmNn][Dd][Aa][Ss][Hh];', '–') s = mw.ustring.gsub(s, ' (.-) ', '%1') s = mw.ustring.gsub(s, '^%s*(.-)%s*$', '%1')

if wl ~= '' then s = mw.ustring.gsub(s, '^%s*([%d][%d]*)%s*[%‐‒–—―]%s*', '%1–') s = mw.ustring.gsub(s, '^%s*(%[%[%s*[^|]*|%s*[%d][%d]*)%s*[%‐‒–—―]%s*', '%1–') s = mw.ustring.gsub(s, '^%s*(%[[^|%[%]%s]*%s+[%d][%d]*)%s*[%‐‒–—―]%s*', '%1–')		local r		if mw.ustring.match(wl, '^%s*[%a]?%s*$') then			bg, wl, n = setbg(wl, n)			r = ' ' 				.. wl .. ' ' .. s .. n		else			hasstrangescore = true			r = wl .. s .. n		end		return r,bg	end	if s == 'Cancelled' or s == '' or s == '?' then		return wl .. s .. n, 'inherit'	end	if mw.ustring.match(s, '^[%a]%s+[^%d].*$') then		wl = mw.ustring.gsub(s, '^([%a])%s+(.-)$', '%1')		s = mw.ustring.gsub(s, '^([%a])%s+(.-)$', '%2')		bg, wl, n = setbg(wl, n)		local r = ' '			.. wl .. ' ' .. s .. n		return r,bg	end	if mw.ustring.match(s, '^[%a]$') then		bg, wl, n = setbg(s, n)		local r = ' '			.. wl .. ' ' .. n		return r, bg	end

local pat pat = '^([%a])%s*([%d][%d]*)[%D]%s*([%d][%d]*)(.-)$' if mw.ustring.match(s, pat) then return parse4(pat, s)	end

pat = '^([%a])%s*(%[%[%s*[^|]*|%s*[%d][%d]*)[%D]%s*([%d][%d]*%]%])(.-)$' if mw.ustring.match(s, pat) then return parse4(pat, s)	end pat = '^([%a])%s*(%[[^|%[%]%s]*%s+[%d][%d]*)[%D]%s*([%d][%d]*%s*%])(.-)$'	if mw.ustring.match(s, pat) then		return parse4(pat, s)	end	hasstrangescore = true

return wl .. s .. n, 'inherit' end

local function getfootnotes(ncg, hc, oe, rank, opprank, poll, tz, src) -- footnotes local fn = {} if ncg then table.insert(fn,'*Non-conference game') end if hc then table.insert(fn, dagger .. 'Homecoming') end if isnotempty(oe) then table.insert(fn, oe) end if (rank == true) or (opprank == true) then table.insert(fn, 'Rankings from ' .. poll) end if isnotempty(tz) then table.insert(fn,'All times are in ' .. tz .. ' time') end if isnotempty(src) then table.insert(fn, 'Source: ' .. src) end

if (#fn > 0) then return horizontal(fn) else return nil end end

local function make_outer_table(args) local showdate  = yesno(args['date'], false) local showtime  = yesno(args['time'], false) local showrank  = yesno(args['rank'], false) local showtv    = yesno(args['tv'], false) local showattend = yesno(args['attend'], false) local showsource = yesno(args['source'], false) local ncg, hc = false, false local row

-- Step 1: Inspect the rows to determine which headers are active local k = 1 while args[k] ~= nil do		if showdate == false then if args[k]:find(']*CFB%-schedule%-date[^>]*>%s*[^%s<]') then showdate = true end end if showtime == false then if args[k]:find(']*CFB%-schedule%-time[^>]*>%s*[^%s<]') then showtime = true end end if showrank == false then if args[k]:find(']*CFB%-schedule%-rank[^>]*>%s*[^%s<]') then showrank = true end end if showtv == false then if args[k]:find(']*CFB%-schedule%-tv[^>]*>%s*[^%s<]') then showtv = true end end if showattend == false then if args[k]:find(']*CFB%-schedule%-attend[^>]*>%s*[^%s<]') then showattend = true end end if showsource == false then if args[k]:find(']*CFB%-schedule%-source[^>]*>%s*[^%s<]') then showsource = true end end if ncg == false then if args[k]:find(']*CFB%-schedule%-ncgame') then ncg = true end end if hc == false then if args[k]:find(']*CFB%-schedule%-hcgame') then hc = true end end if hasrank == false then if showrank == true or args[k]:find('No%. %d') or args[k]:find('No%. T[%-–%s]*%d') then hasrank = true end end k = k + 1 end if k == 1 then return '' end -- Step 2: Build the table local root = mw.html.create('table') root:addClass('wikitable') :css('font-size', '95%')

-- optional caption if args['caption'] then root:tag('caption'):wikitext(args['caption']) end -- add the headers local cols = 3 row = root:tag('tr') if showdate then row:tag('th'):wikitext('Date') cols = cols + 1 end if showtime then row:tag('th'):wikitext('Time') cols = cols + 1 end row:tag('th'):wikitext('Opponent') if showrank then row:tag('th'):wikitext('Rank') cols = cols + 1 end row:tag('th'):wikitext('Site') if showtv then row:tag('th'):wikitext('TV') cols = cols + 1 end row:tag('th'):wikitext('Result') if showattend then row:tag('th'):wikitext('Attendance') cols = cols + 1 end if showsource then row:tag('th'):wikitext('Source') cols = cols + 1 end

k = 1 while args[k] ~= nil do		row = args[k] or '' if showdate then row = mw.ustring.gsub(row, ']*CFB%-schedule%-date[^>]*>', '') else row = mw.ustring.gsub(row, ']*CFB%-schedule%-date[^>]*>%s* %s*', '') end if showtime then row = mw.ustring.gsub(row, ']*CFB%-schedule%-time[^>]*>', '') else row = mw.ustring.gsub(row, ']*CFB%-schedule%-time[^>]*>%s* %s*', '') end if showrank then row = mw.ustring.gsub(row, '<td[^>]*CFB%-schedule%-rank[^>]*>', '<td style="white-space:nowrap">') else row = mw.ustring.gsub(row, '<td[^>]*CFB%-schedule%-rank[^>]*>%s* %s*', '') end if showtv then row = mw.ustring.gsub(row, '<td[^>]*CFB%-schedule%-tv[^>]*>', ' ') else row = mw.ustring.gsub(row, '<td[^>]*CFB%-schedule%-tv[^>]*>%s* %s*', '') end if showattend then row = mw.ustring.gsub(row, '<td[^>]*CFB%-schedule%-attend[^>]*>', '<td style="text-align:center">') else row = mw.ustring.gsub(row, '<td[^>]*CFB%-schedule%-attend[^>]*>%s* %s*', '') end if showsource then row = mw.ustring.gsub(row, '<td[^>]*CFB%-schedule%-source[^>]*>', '<td style="text-align:center">') else row = mw.ustring.gsub(row, '<td[^>]*CFB%-schedule%-source[^>]*>%s* %s*', '') end root:wikitext(row) k = k + 1 end

-- footnotes local fnotes = getfootnotes(		ncg,		hc,		args['other-event'] or args['other_event'] or args['otherevent'],		showrank,		yesno(args['opprank'], hasrank),		getpolltext( args['rank_year'] or args['rankyear'], args['rank_division'] or args['rankdivision'], args['poll'] ),		showtime and args['timezone'] or '',		args['seasonsource']	)

if fnotes ~= nil then root:tag('tr') :tag('td') :attr('colspan',cols) :css('font-size', '85%') :wikitext(fnotes) end return tostring(root) end

local function convert_table(args) local function splitresult(s) local wl = '' s = mw.ustring.gsub(s or '', '&[MmNn][Dd][Aa][Ss][Hh];', '–') s = mw.ustring.gsub(s, '^%s*(.-)%s*$', '%1') local r = '' if mw.ustring.match(s, '^[%a]%s*[%d][%d]*[%D]%s*[%d][%d]*%s*.*$') then local t = {, , , } for k = 1,4 do t[k] = mw.ustring.gsub(s,'^([%a])%s*([%d][%d]*)[%D]%s*([%d][%d]*)%s*(.*)$', '%' .. k)			end local wl, s1, s2, n = t[1], t[2], t[3], t[4] wl = wl:lower return wl, s1 .. '–' .. s2 .. n		end return '', s	end local res = ''

return res end

local function make_table(args) local hasgamename = true

-- switch headers on and off local headers = {'Date', 'Time', 'At/Vs', 'Opponent', 'Rank', 'Site', 'Location', 'Game name', 'TV', 'Result', 'Attendance', 'Source'} local resultoffset = 9

local ncg, hc = false, false

for k = #headers,1,-1 do		if headers[k] == 'Time' and (yesno(args['time'], false) == false) then table.remove(headers,k) resultoffset = resultoffset - 1 elseif headers[k] == 'At/Vs' and (yesno(args['atvs'], true) == false) then table.remove(headers,k) resultoffset = resultoffset - 1 elseif headers[k] == 'Rank' and (yesno(args['rank'], false) == false) then table.remove(headers,k) resultoffset = resultoffset - 1 elseif headers[k] == 'Game name' and (yesno(args['gamename'], false) == false) then table.remove(headers,k) resultoffset = resultoffset - 1 hasgamename = false elseif headers[k] == 'TV' and (yesno(args['tv'], false) == false) then table.remove(headers,k) resultoffset = resultoffset - 1 elseif headers[k] == 'Attendance' and (yesno(args['attend'], false) == false) then table.remove(headers,k) elseif headers[k] == 'Source' and (yesno(args['source'], false) == false) then table.remove(headers,k) end end

-- create the root table local root = mw.html.create('table') root:addClass('wikitable') :css('font-size', '95%') -- optional caption if args['caption'] then root:tag('caption'):wikitext(args['caption']) end

-- add the headers local row = root:tag('tr') for k=1,#headers do		if headers[k] == 'Rank' then local cell = row:tag('th') cell:wikitext('Rank') elseif headers[k] == 'Location' then elseif headers[k] == 'At/Vs' then elseif headers[k] == 'Opponent' then local cell = row:tag('th') cell:wikitext('Opponent') else local cell = row:tag('th') cell:wikitext(headers[k]) end end

-- build the table local k = 1 local stopflag = (args[k] == nil) and true or false if stopflag then return '' end while stopflag == false do		local res, bg = getresult(, args[k+resultoffset] or , '') row = root:tag('tr'):css('background-color', bg) local op, gn = ,  for j = 1,#headers do			if headers[j] == 'Result' then row:tag('td'):css('white-space', 'nowrap'):wikitext(res) elseif headers[j] == 'At/Vs' then elseif headers[j] == 'Opponent' then if mw.ustring.find(args[k] or '', '<[%s/]*[Nn][Cc][Gg][%s/]*>') then ncg = true end if mw.ustring.find(args[k] or '', '<[%s/]*[Hh][Cc][%s/]*>') then hc = true end op, gn = getopp(args[k], (yesno(args['atvs'], true) == true) and (args[k-1] or ) or , true) row:tag('td'):wikitext(op) elseif headers[j] == 'Rank' then row:tag('td'):wikitext(getrank(args[k])) elseif headers[j] == 'Site' then row:tag('td'):wikitext(getsite(args[k] or , args[k+1] or , (hasgamename and (args[k+2] or ) or ) .. (' ' .. gn))) elseif headers[j] == 'Location' then elseif headers[j] == 'Game name' then elseif headers[j] == 'Attendance' then row:tag('td'):css('text-align', 'center'):wikitext(args[k]) else row:tag('td'):wikitext(args[k]) end k = k + 1 stopflag = (args[k] == nil) and true or false end end

-- footnotes local fnotes = getfootnotes(		ncg,		hc,		args['other-event'] or args['other_event'] or args['otherevent'],		yesno(args['rank'], false),		yesno(args['opprank'], hasrank),		getpolltext( args['rank_year'] or args['rankyear'], args['rank_division'] or args['rankdivision'], args['poll'] ),		(yesno(args['time'], false) == false) and '' or args['timezone'],		args['seasonsource']	)

if fnotes ~= nil then row = root:tag('tr') row:tag('td') :attr('colspan',#headers) :css('font-size', '85%') :wikitext(fnotes) end

-- return the root table return tostring(root) .. (haslocgamename and  or ) .. (hasoppgamename and  or ) .. (haslocrivalry and  or ) .. (hasopprivalry and  or ) .. (hasstrangescore and  or ) .. (hasnowrap and  or ) end

function p.entry(frame) local args = (frame.args.opponent ~= nil) and frame.args or frame:getParent.args local cell

if args['overtime'] then args['overtime'] = ' ' .. args['overtime'] .. ''	end

local res, bg = getresult(		(args['w/l'] or ) .. ' ', 		args['score'] or , 		args['overtime'] or ''		)

local root = mw.html.create('tr') :addClass('CFB-schedule-row') :css('background-color', bg)

-- Date cell = root:tag('td'):addClass('CFB-schedule-date') if args.date and (args.date):lower ~= 'no' then cell :css('white-space','nowrap') :wikitext(args.date or '') else cell:css('display','none') end

-- Time cell = root:tag('td'):addClass('CFB-schedule-time') if args.time and (args.time):lower ~= 'no' then cell :css('white-space','nowrap') :wikitext(args.time or '') else cell:css('display','none') end

-- Opponent local op, gn = getopp(		(isnotempty(args.opprank) and getrank(args.opprank) .. ' ' or ) ..		(args.opponent or ) ..		((yesno(args.nonconf,false) == true) and ' ' or ) ..		((yesno(args.homecoming,false) == true) and '<hc>' or ) ..		(args.ref or ),		(isnotempty(args.away) and 'at' or ) ..		(isnotempty(args.neutral) and 'vs.' or ''),		false		) root:tag('td') :css('white-space', 'nowrap') :wikitext(op)

-- Rank cell = root:tag('td'):addClass('CFB-schedule-rank') if args.rank and (args.rank):lower ~= 'no' then local rank = args.rank or '' if rank ~= '' then rank = 'No. ' .. rank end cell :css('text-align','center') :css('white-space','nowrap') :wikitext(rank) else cell:css('display','none') end

-- Gamename local gamename = args.gamename or ''

-- Site root:tag('td') :wikitext(getsite(args.stadium or args.site_stadium or , (args.cityst or args.site_cityst or ), gamename))

-- TV	cell = root:tag('td'):addClass('CFB-schedule-tv') if args.tv and (args.tv):lower ~= 'no' then cell :wikitext(args.tv or '') else cell:css('display','none') end

-- Result root:tag('td') :css('white-space','nowrap') :wikitext(res)

-- Attendance cell = root:tag('td'):addClass('CFB-schedule-attend') if args.attend and (args.attend):lower ~= 'no' then cell :css('text-align','center') :wikitext(args.attend or '') else cell:css('display','none') end

-- Source cell = root:tag('td'):addClass('CFB-schedule-source') if args.source and (args.source):lower ~= 'no' then cell :css('text-align','center') :wikitext(args.source or '') else cell:css('display','none') end

return tostring(root) end

function p.subst(frame) local args = frame.args[1] and frame.args or frame:getParent.args if (args[1] or ''):find('<tr[^>]*CFB%-schedule%-row') then return make_outer_table(args) else return convert_table(args) end end

function p.table(frame) local args = frame.args[1] and frame.args or frame:getParent.args if (args[1] or ''):find('<tr[^>]*CFB%-schedule%-row') then return make_outer_table(args) .. ''	else return make_table(args) .. ''	end end

return p