Module:Sandbox/B2project/NHL Standings

From WikiProjectMed
Jump to navigation Jump to search
-- This module copies content from Template:MLB_standings; see the history of that page
-- for attribution. 6/15/16

local me = { }

local nhlData

-- if mw.loadData() not supported, use require() instead
if mw.loadData then
    nhlData = mw.loadData('Module:Sandbox/B2project/NHL Standings/data')
else
    nhlData = require('Module:Sandbox/B2project/NHL Standings/data')
end

local Navbar = require('Module:Navbar')

-- Temporary workaround for missing mw.text utility functions
mw.text = mw.text or {}

if (mw.text.trim == nil) then
    mw.text.trim = function(s)
        if (s == nil) then
            return ''
        end
        return mw.ustring.match(s, "^%s*(.-)%s*$")
    end
end

if (mw.text.gsplit == nil) then
    mw.text.gsplit = function( text, pattern, plain )
        local s, l = 1, mw.ustring.len( text )
        return function ()
            if s then
                local e, n = mw.ustring.find( text, pattern, s, plain )
                local ret
                if not e then
                    ret = mw.ustring.sub( text, s )
                    s = nil
                elseif n < e then
                    -- Empty separator!
                    ret = mw.ustring.sub( text, s, e )
                    if e < l then
                        s = e + 1
                    else
                        s = nil
                    end
                else
                    ret = e > s and mw.ustring.sub( text, s, e - 1 ) or ''
                    s = n + 1
                end
                return ret
            end
        end, nil, nil
    end
end

if (mw.text.split == nil) then
    mw.text.split = function ( text, pattern, plain )
        local ret = {}
        for m in mw.text.gsplit( text, pattern, plain ) do
            ret[#ret+1] = m
        end
        return ret
    end
end

local defaultOutputForInput = {
    default = 'default',
    current = 'current',
    winsloss = 'winsloss',
    WLT = 'WLT',
}

local readTeamInfo = {
    default = function(args, currentIdx, returnData)
    	if (args[currentIdx]   == nil or
            args[currentIdx+1] == nil or
            args[currentIdx+2] == nil or
            args[currentIdx+3] == nil or
            args[currentIdx+4] == nil or
            args[currentIdx+5] == nil or
            args[currentIdx+6] == nil or
            args[currentIdx+7] == nil ) then
            return nil
        end
        teamInfo = {
            name = mw.text.trim(args[currentIdx]),
            wins = tonumber(mw.text.trim(args[currentIdx+1])),
            losses = tonumber(mw.text.trim(args[currentIdx+2])),
            ties = tonumber(mw.text.trim(args[currentIdx+3])),
            otlosses = tonumber(mw.text.trim(args[currentIdx+4])),
            row = tonumber(mw.text.trim(args[currentIdx+5])),
            gf = tonumber(mw.text.trim(args[currentIdx+6])),
            ga = tonumber(mw.text.trim(args[currentIdx+7])),
            winpoints = 2,
            tiepoints = 1,
            otlpoints = 1,
            points = '',
            gamesplayed = '',
        }
        returnData.cIndicesRead = 8
        
        teamInfo.gamesplayed = teamInfo.wins + teamInfo.losses + teamInfo.ties + teamInfo.otlosses
        
        teamInfo.points = (teamInfo.winpoints*teamInfo.wins)+(teamInfo.tiepoints*teamInfo.ties)+(teamInfo.otlpoints*teamInfo.otlosses)

        return teamInfo
    end,  -- function readTeamInfo.default()
    
    current = function(args, currentIdx, returnData)
    	if (args[currentIdx]   == nil or
            args[currentIdx+1] == nil or
            args[currentIdx+2] == nil or
            args[currentIdx+3] == nil or
            args[currentIdx+4] == nil or
            args[currentIdx+5] == nil or
            args[currentIdx+6] == nil ) then
            return nil
        end
        teamInfo = {
            name = mw.text.trim(args[currentIdx]),
            wins = tonumber(mw.text.trim(args[currentIdx+1])),
            losses = tonumber(mw.text.trim(args[currentIdx+2])),
            otlosses = tonumber(mw.text.trim(args[currentIdx+3])),
            row = tonumber(mw.text.trim(args[currentIdx+4])),
            gf = tonumber(mw.text.trim(args[currentIdx+5])),
            ga = tonumber(mw.text.trim(args[currentIdx+6])),
			winpoints = 2,
            otlpoints = 1,
            points = '',
            gamesplayed = '',
        }
        returnData.cIndicesRead = 7
        
        teamInfo.gamesplayed = teamInfo.wins + teamInfo.losses + teamInfo.otlosses
        
        teamInfo.points = (teamInfo.winpoints*teamInfo.wins)+(teamInfo.otlpoints*teamInfo.otlosses)

        return teamInfo
    end,  -- function readTeamInfo.default()
    
    winsloss = function(args, currentIdx, returnData)
    	if (args[currentIdx]   == nil or
            args[currentIdx+1] == nil or
            args[currentIdx+2] == nil or
            args[currentIdx+3] == nil or
            args[currentIdx+4] == nil ) then
            return nil
        end
        teamInfo = {
            name = mw.text.trim(args[currentIdx]),
            wins = tonumber(mw.text.trim(args[currentIdx+1])),
            losses = tonumber(mw.text.trim(args[currentIdx+2])),
            gf = tonumber(mw.text.trim(args[currentIdx+3])),
            ga = tonumber(mw.text.trim(args[currentIdx+4])),
			winpoints = 2,
            points = '',
            gamesplayed = '',
        }
        returnData.cIndicesRead = 5
        
        teamInfo.gamesplayed = teamInfo.wins + teamInfo.losses
        
        teamInfo.points = (teamInfo.winpoints*teamInfo.wins)

        return teamInfo
    end,  -- function readTeamInfo.default()
    
    WLT = function(args, currentIdx, returnData)
    	if (args[currentIdx]   == nil or
            args[currentIdx+1] == nil or
            args[currentIdx+2] == nil or
            args[currentIdx+3] == nil or
            args[currentIdx+4] == nil or
            args[currentIdx+5] == nil ) then
            return nil
        end
        teamInfo = {
            name = mw.text.trim(args[currentIdx]),
            wins = tonumber(mw.text.trim(args[currentIdx+1])),
            losses = tonumber(mw.text.trim(args[currentIdx+2])),
            ties = tonumber(mw.text.trim(args[currentIdx+3])),
            gf = tonumber(mw.text.trim(args[currentIdx+4])),
            ga = tonumber(mw.text.trim(args[currentIdx+5])),
			winpoints = 2,
			tiepoints = 1,
            points = '',
            gamesplayed = '',
        }
        returnData.cIndicesRead = 6
        
        teamInfo.gamesplayed = teamInfo.wins + teamInfo.losses + teamInfo.ties
        
        teamInfo.points = (teamInfo.winpoints*teamInfo.wins) + (teamInfo.tiepoints*teamInfo.ties)

        return teamInfo
    end,  -- function readTeamInfo.default()

}  -- readTeamInfo object

local generateTableHeader = {
    default = function(tableHeaderInfo)
        return
'{| class="wikitable sortable" width="" style="text-align:center;"\
|+ [[' .. tableHeaderInfo.divisionLink.. '|' .. tableHeaderInfo.division .. ']]' ..tableHeaderInfo.source.. '\
! width=32 | <abbr title="Position">Pos</abbr>\
! width=190 | Team ' .. tableHeaderInfo.navbarText .. '\
! width=32 | <abbr title="Games played">GP</abbr>\
! width=32 | <abbr title="Won">W</abbr>\
! width=32 | <abbr title="Lost">L</abbr>\
! width=32 | <abbr title="Ties">T</abbr>\
! width=32 | <abbr title="Lost in overtime">OTL</abbr>\
! width=32 | <abbr title="Regulation + Overtime wins">ROW</abbr>\
! width=32 | <abbr title="Goals for">GF</abbr>\
! width=32 | <abbr title="Goals for">GA</abbr>\
! width=32 | <abbr title="Goal difference">GD</abbr>\
! width=32 | <abbr title="Points">Pts</abbr>\
'
end,  -- function generateTableHeader.default()

	current = function(tableHeaderInfo)
        return
'{| class="wikitable sortable" width="" style="text-align:center;"\
|+ [[' .. tableHeaderInfo.divisionLink.. '|' .. tableHeaderInfo.division .. ']]\
! width=32 | <abbr title="Position">Pos</abbr>\
! width=190 | Team ' .. tableHeaderInfo.navbarText .. '\
! width=32 | <abbr title="Games played">GP</abbr>\
! width=32 | <abbr title="Won">W</abbr>\
! width=32 | <abbr title="Lost">L</abbr>\
! width=32 | <abbr title="Lost in overtime">OTL</abbr>\
! width=32 | <abbr title="Regulation + Overtime wins">ROW</abbr>\
! width=32 | <abbr title="Goals for">GF</abbr>\
! width=32 | <abbr title="Goals for">GA</abbr>\
! width=32 | <abbr title="Goal difference">GD</abbr>\
! width=32 | <abbr title="Points">Pts</abbr>\
'
end,

    winsloss = function(tableHeaderInfo)
        return
'{| class="wikitable sortable" width="" style="text-align:center;"\
|+ [[' .. tableHeaderInfo.divisionLink.. '|' .. tableHeaderInfo.division .. ']]\
! width=32 | <abbr title="Position">Pos</abbr>\
! width=190 | Team ' .. tableHeaderInfo.navbarText .. '\
! width=32 | <abbr title="Games played">GP</abbr>\
! width=32 | <abbr title="Won">W</abbr>\
! width=32 | <abbr title="Lost">L</abbr>\
! width=32 | <abbr title="Goals for">GF</abbr>\
! width=32 | <abbr title="Goals for">GA</abbr>\
! width=32 | <abbr title="Goal difference">GD</abbr>\
! width=32 | <abbr title="Points">Pts</abbr>\
'
end,  -- function generateTableHeader.winloss()

    WLT = function(tableHeaderInfo)
        return
'{| class="wikitable sortable" width="" style="text-align:center;"\
|+ [[' .. tableHeaderInfo.divisionLink.. '|' .. tableHeaderInfo.division .. ']]\
! width=32 | <abbr title="Position">Pos</abbr>\
! width=190 | Team ' .. tableHeaderInfo.navbarText .. '\
! width=32 | <abbr title="Games played">GP</abbr>\
! width=32 | <abbr title="Won">W</abbr>\
! width=32 | <abbr title="Lost">L</abbr>\
! width=32 | <abbr title="Ties">T</abbr>\
! width=32 | <abbr title="Goals for">GF</abbr>\
! width=32 | <abbr title="Goals for">GA</abbr>\
! width=32 | <abbr title="Goal difference">GD</abbr>\
! width=32 | <abbr title="Points">Pts</abbr>\
'
end,  -- function generateTableHeader.WLT()
	
}  -- generateTableHeader object

local generateTeamRow = {
    default = function(teamRowInfo, teamInfo)
        return
'|-' .. teamRowInfo.rowStyle .. '\
|| ' .. teamRowInfo.position ..'\
| style="text-align:left;" | ' .. teamRowInfo.statusText .. '[[' .. teamRowInfo.teamSeasonPage .. '|' .. teamInfo.name .. ']]\
|| ' .. teamInfo.gamesplayed .. '\
|| ' .. teamInfo.wins .. '\
|| ' .. teamInfo.losses .. '\
|| ' .. teamInfo.ties ..'\
|| ' .. teamInfo.otlosses ..'\
|| ' .. teamInfo.row ..'\
|| ' .. teamInfo.gf .. '\
|| ' .. teamInfo.ga .. '\
|| ' .. teamRowInfo.goaldiff ..'\
| style="font-weight:bold;" | ' .. teamInfo.points ..'\n'

end,  -- function generateTeamRow.default()

    current = function(teamRowInfo, teamInfo)
        return
'|-' .. teamRowInfo.rowStyle .. '\
|| ' .. teamRowInfo.position ..'\
| style="text-align:left;" | ' .. teamRowInfo.statusText .. '[[' .. teamRowInfo.teamSeasonPage .. '|' .. teamInfo.name .. ']]\
|| ' .. teamInfo.gamesplayed .. '\
|| ' .. teamInfo.wins .. '\
|| ' .. teamInfo.losses .. '\
|| ' .. teamInfo.otlosses ..'\
|| ' .. teamInfo.row ..'\
|| ' .. teamInfo.gf .. '\
|| ' .. teamInfo.ga .. '\
|| ' .. teamRowInfo.goaldiff ..'\
| style="font-weight:bold;" | ' .. teamInfo.points ..'\n'

end,

    winsloss = function(teamRowInfo, teamInfo)
        return
'|-' .. teamRowInfo.rowStyle .. '\
|| ' .. teamRowInfo.position ..'\
| style="text-align:left;" | ' .. teamRowInfo.statusText .. '[[' .. teamRowInfo.teamSeasonPage .. '|' .. teamInfo.name .. ']]\
|| ' .. teamInfo.gamesplayed .. '\
|| ' .. teamInfo.wins .. '\
|| ' .. teamInfo.losses .. '\
|| ' .. teamInfo.gf .. '\
|| ' .. teamInfo.ga .. '\
|| ' .. teamRowInfo.goaldiff ..'\
| style="font-weight:bold;" | ' .. teamInfo.points ..'\n'

end,  -- function generateTeamRow.default()

    WLT = function(teamRowInfo, teamInfo)
        return
'|-' .. teamRowInfo.rowStyle .. '\
|| ' .. teamRowInfo.position ..'\
| style="text-align:left;" | ' .. teamRowInfo.statusText .. '[[' .. teamRowInfo.teamSeasonPage .. '|' .. teamInfo.name .. ']]\
|| ' .. teamInfo.gamesplayed .. '\
|| ' .. teamInfo.wins .. '\
|| ' .. teamInfo.losses .. '\
|| ' .. teamInfo.ties .. '\
|| ' .. teamInfo.gf .. '\
|| ' .. teamInfo.ga .. '\
|| ' .. teamRowInfo.goaldiff ..'\
| style="font-weight:bold;" | ' .. teamInfo.points ..'\n'

end,  -- function generateTeamRow.default()

}   -- generateTeamRow object

local function parsestatus_list(status_listArg, status_list)
    local statusList = mw.text.split(status_listArg, '%s*,%s*')
    if (#statusList == 0) then
        return
    end

    for idx, status in ipairs(statusList) do
        local statusData = mw.text.split(status, '%s*:%s*')
        if (#statusData >= 2) then
            local statusNumber = mw.text.trim(statusData[1])
            local team = mw.text.trim(statusData[2])
            status_list[statusNumber] = team
            status_list[team] = statusNumber
        end
    end
end  -- function parsestatus_list()

local function parseHighlightArg(highlightArg, teamsToHighlight)
    local teamList = mw.text.split(highlightArg, '%s*,%s*')
    if (#teamList == 0) then
        return
    end

    for idx, team in ipairs(teamList) do
        teamsToHighlight[mw.text.trim(team)] = true
    end

end  -- function parseHighlightArg

local function parseTeamLinks(teamLinksArg, linkForTeam)
    local teamList = mw.text.split(teamLinksArg, '%s*,%s*')
    if (#teamList == 0) then
        return
    end

    for idx, teamLinkInfo in ipairs(teamList) do
        local teamData = mw.text.split(teamLinkInfo, '%s*:%s*')
        if (#teamData >= 2) then
            local team = mw.text.trim(teamData[1])
            local teamLink = mw.text.trim(teamData[2])
            linkForTeam[team] = teamLink
        end
    end
end  -- function parseTeamLinks

function me.generateStandingsTable(frame)
    local inputFormat = 'default'
    if (frame.args.input ~= nil) then
        local inputArg = mw.text.trim(frame.args.input)
        if (inputArg == 'current') then
            inputFormat = 'current'
        end
        if (inputArg == 'winsloss') then
        	inputFormat = 'winsloss'
        end
        if (inputArg == 'WLT') then
        	inputFormat = 'WLT'
    	end
    end

    local templateName = nil
    if (frame.args.template_name ~= nil) then
        templateName = frame.args.template_name
    end

    local outputFormat = defaultOutputForInput[inputFormat]
    local fDisplayNavbar = true
    local fDisplayTies = true
    if (frame.args.output ~= nil) then
        local outputArg = mw.text.trim(frame.args.output)
        if (outputArg == 'current') then
            outputFormat = 'current'
            fDisplayTies = false
        end
        if (outputArg == 'winsloss') then
            outputFormat = 'winsloss'
        end
        if (outputArg == 'WLT') then
        	outputFormat = 'WLT'
    	end
    	
	end
	
    local year = mw.text.trim(frame.args.year or '')
    local division = mw.text.trim(frame.args.division or '')
    local divisionLink = mw.text.trim(frame.args.division_link or division)
    local source = mw.text.trim(frame.args.source or '')

    local statusInfo = {}
    if (frame.args.status_list ~= nil) then
        parsestatus_list(frame.args.status_list, statusInfo)
    end

    local teamsToHighlight = {}
    if (frame.args.highlight ~= nil) then
        parseHighlightArg(frame.args.highlight, teamsToHighlight)
    end

    local linkForTeam = {}
    if (frame.args.team_links ~= nil) then
        parseTeamLinks(frame.args.team_links, linkForTeam)
    end

    local listOfTeams = {};
    local currentArgIdx = 1;

    while (frame.args[currentArgIdx] ~= nil) do
        local returnData = { }
        local teamInfo = readTeamInfo[inputFormat](frame.args, currentArgIdx, returnData);
        if (teamInfo == nil) then
            break
        end
        if (linkForTeam[teamInfo.name] ~= nil) then
            teamInfo.teamLink = linkForTeam[teamInfo.name]
        else
            teamInfo.teamLink = teamInfo.name
        end
        table.insert(listOfTeams, teamInfo)
        currentArgIdx = currentArgIdx + returnData.cIndicesRead
    end

    if (#listOfTeams == 0) then
        return ''
    end

    local outputBuffer = { }
    local t_footer = { }

    local tableHeaderInfo = {
        division = division,
        divisionLink = divisionLink,
        source = source,
    }

    if (fDisplayNavbar) then
        local divisionForNavbox = division
        if (nhlData.abbreviationForDivision[division] ~= nil) then
            divisionForNavbox = nhlData.abbreviationForDivision[division]
        end

        local standingsPage
        if (templateName ~= nil) then
            standingsPage = templateName
        else
            standingsPage = year .. ' ' .. divisionForNavbox .. ' standings'
        end
        tableHeaderInfo.navbarText =
            Navbar.navbar({
                standingsPage,
                mini = 1,
                style = 'float:right;',
            })
       
    end

    table.insert(outputBuffer,
        generateTableHeader[outputFormat](tableHeaderInfo)
    )

    local leadingHalfGames = nil;

    for idx, teamInfo in ipairs(listOfTeams) do
        local teamRowInfo = {
            teamSeasonPage = year .. ' ' .. teamInfo.teamLink .. ' season',
            statusText = '',
            rowStyle = '',
            position = idx,
            goaldiff = '',
            winpoints = 2,
            tiepoints = 1,
            otlpoints = 1,
        }
        
        teamRowInfo.goaldiff = teamInfo.gf - teamInfo.ga
        if teamRowInfo.goaldiff>0 then
        	teamRowInfo.goaldiff='<span style="color:green">+'..teamRowInfo.goaldiff..'</span>'
    	elseif teamRowInfo.goaldiff<0 then
    		teamRowInfo.goaldiff=teamRowInfo.goaldiff*-1
    		teamRowInfo.goaldiff='<span style="color:red">&minus;'..teamRowInfo.goaldiff..'</span>'
		end
		
        if (statusInfo[teamInfo.name] ~= nil) then
            teamRowInfo.statusText = '<span style="font-weight:bold">' .. string.lower(statusInfo[teamInfo.name]) .. ' –</span> '
            --teamRowInfo.rowStyle = ' style="background:#CCFFCC"'
        end

        if (teamsToHighlight[teamInfo.name]) then
            teamRowInfo.rowStyle =  ' style="background:#CCFFCC;font-weight:bold;"'
        end

        table.insert(outputBuffer,
            generateTeamRow[outputFormat](teamRowInfo, teamInfo)
        )

    end  -- end of looping over listOfTeams

    table.insert(outputBuffer, '|}\n')
    
    local update = mw.text.trim(frame.args.update or 'unknown')
    local start_date = mw.text.trim(frame.args.start_date or 'unknown')
    
    --local source = mw.text.trim(frame.args.source or '')
    
    if (source ~= nil) then
    	source = source
	else
		source = ''
	end
	
	local matches_text = mw.text.trim(frame.args.matches_text or 'games')
	if string.lower(update)=='complete' then
		table.insert(t_footer,'Final standings.'..tableHeaderInfo.source..'')
	elseif update=='' then
		-- Empty
		table.insert(t_footer,'Source'..tableHeaderInfo.source..'')
	elseif update=='future' then
		-- Future start date
		table.insert(t_footer,'First '..matches_text..' will be played on '..start_date..'. ')
	else
		table.insert(t_footer,'Updated to '..matches_text..' played on '..update..'.'..tableHeaderInfo.source..'')
	end
	
    return table.concat(outputBuffer), table.concat(t_footer)

end  -- function me.generateStandingsTable()

function me.generateStandingsTable_fromTemplate(frame)
    return me.generateStandingsTable(frame:getParent())
end  -- function me.generateStandingsTable_fromTemplate()

return me