p.sortGoalscorers -- sort selected goalscorers by number of goal, then country  
return p.outputGoalscorers(, "OG") -- output list of goalscorers  
end
function p.validateRound(round)
local validateRound = false
for k,v in pairs(data.rounds) do
if k == round then validateRound = true end -- data for this round exists
end
return validateRound
end  
-- ############################## functions to select goalscorers ######################
p.selectGoalscorers - select goals scoreers required for list (rounds, groups)
p.getRoundAndGroup
p.getGoalsCol(round) - get column containing round data or first data column if round = all
(country, possibleGroup)
p.getGoals (u, player)
p.parseComment(comment)
p.getPlayer(u)  
-- p.selectGoalscorers
- select players meeting round and group criteria from goalscoreres list
- gets goals and comments  
function p.selectGoalscorers(og)  
local round, group = p.getRoundAndGroup
if not round then return false end -- exit if no valid round  
local goalMinimum = tonumber(g.args['minimum']) or -5 -- assume 5 own goals is maximum
local goalsCol = p.getGoalsCol(round) -- first column for goals  
-- select players who have scored in rounds/groups requested
local goalscorerData = data.goalscorers
if og == "OG" then goalscorerData = data.owngoalscorers end  
for k,v in pairs(goalscorerData) do
local goals, comment = 0, "" -- goals > 0 is the flag to include the player
local playerName, playerAlias = p.getPlayer(v[1]) -- player name
local goalsByRound, commentByRound = 0, ""  
if round == "all" then -- goals in all rounds and all groups  
for i = goalsCol, #v, 1 do
if group and group ~= "all" and i == p.getGoalsCol("group") and group ~= p.getGroup(v[2], v[3]) then
goalsByRound = 0
commentByRound = ""
else
goalsByRound, commentByRound = p.getGoals( v[i] , playerName)
end  
goals = goals + goalsByRound --TODO use getGoals on round options
if commentByRound ~= "" then
if comment == "" then
comment = commentByRound
else
comment = comment .. "," .. commentByRound --TODO decide on comma or semi-colon
end
end
i = i+1
end
elseif round == "all2" and group ~= "all" then -- goals in all rounds but only from one group  
--TODO code to go through all rounds but only include goals in specified group [TODO merge with above option]
--mw.addWarning( g.args[1] .. ":Mix:round=all and group=" .. group .. "/" .. p.getGroup(v[2], v[3] ) )
for i = goalsCol, #v, 1 do
if i == p.getGoalsCol("group") and group ~= p.getGroup(v[2], v[3]) then
goalsByRound = 0
commentByRound = ""
else
goalsByRound, commentByRound = p.getGoals( v[i] , playerName)
end
goals = goals + goalsByRound
if commentByRound ~= "" then
if comment == "" then
comment = commentByRound
else
comment = comment .. "," .. commentByRound --TODO decide on comma or semi-colon
end
end
i = i+1
end
elseif round == "group" then -- group round only
if group == p.getGroup(v[2], v[3]) then -- single group only
goals, comment = p.getGoals( v[goalsCol] , playerName)
elseif group == "all" then -- any group
goals, comment = p.getGoals( v[goalsCol] , playerName)
else
-- do nothing for other groups
end
--elseif round == "playoffs" then -- playoff round (redunant?)
-- goals = v[goalsCol]
else -- any other round
goals, comment = p.getGoals( v[goalsCol] , playerName) -- should also handle playoffs
end
if goals >= goalMinimum and goals ~= 0 then
if comment ~= "" then
if og == "OG" then
comment = '<span> (' .. p.sortComment(comment) .. ')</span>'
else
comment = '<span>' .. comment .. '</span>' -- no parenthesis when using notes
end
end  
if og == "OG" then goals = -goals end -- make owngoals negative numbers  
g.goalscorers[#g.goalscorers+1] = { player=playerName, alias=playerAlias,
country=v[2],
goals=goals,
comment=p.parseComment(comment)}
--g.totalGoals = g.totalGoals + math.abs(goals) -- increment total goal counter
end
g.totalGoals = g.totalGoals + math.abs(goals) -- increment total goal counter
end
return true -- data collected for selected goalscorers
end
-- p.getRoundAndGroup  
function p.getRoundAndGroup
local round = g.args['round'] or "all" -- round = all(empty)|group|playoffs
local group = g.args['group'] or "all" -- group = all(empty), A,B,C etc  
local validateRound = false
local validateGroupRound = false
for k,v in pairs(data.rounds) do
if k == round then validateRound = true end -- data for this round exists
if k == "group" then validateGroupRound = true end -- there is a group round
end
if validateRound == false and round ~= "all" then
local message = 'Invalid round "' .. round .. '" specified. No data found for that round. '
mw.addWarning( message )
p.errorString = p.errorString .. message
round = nil
end
if validateGroupRound == false then group = false end -- there is no group round  
-- TODO add group error checking
-- Could merge with getGoalsCol and also return goalsCol
return round, group
end  
-- p.getGoalsCol(round)
- get column containing round data or first data column if round = "all"
- allows group column to be omitted from player table when group table provided  
function p.getGoalsCol(round)  
local minimum = 1000
if round == "all" then -- if all need column of first round
for k,v in pairs(data.rounds) do
if v < minimum then minimum = v end
--return v -- return the first one [this seemed to work reliably, but sometimes table order is not as listed]
end
return minimum
end
if data.rounds and data.rounds[round] then
return data.rounds[round] -- get column containing goals for that round
else
return 4 -- an old default when no data.round (may not be necessary)
end
end  
-- p.getGroup(country, possibleGroup)
- get group from group table or from player table
- possibleGroup is the column containing the Group (when no group table) or the first data column  
function p.getGroup(country, possibleGroup) -- row contain player name, country code, group if given, goals
if data.groups then
for k,v in pairs(data.groups) do -- iterate through the groups
--local = gotGroup = false
for j,u in pairs(v) do -- for each group
if u == country then
return k
end
end
end
return "no group found"
else
return possibleGroup -- no group table, so assume column three contains the group
end  
end
-- get number of goals and any associated comment
the goals can be a single number (the usual case)
or as an option table (e.g. for own goals): { number of own goals, comma-delimited list of opponents }
- if the entry is a table, we want the first entry (a number) and the second (comment string)
- otherwise, if a number, we just want the number and an empty string  
function p.getGoals (u, player)
if type(u) == 'table' and type(u[1]) == 'number' then
return u[1], u[2] -- return number of goals, comment
elseif type(u) == 'number' then
return u, "" -- return number of goals, empty string
else
p.errorString = p.errorString .. " Invalid goals entry for player " .. player
return 0, ""
end
end
function p.parseComment(comment)  
local = mw.getCurrentFrame  
-- we have something like ""
if string.find(comment, "efn" , 1 , true ) then -- if we have a comment with a note
g.notes = true -- set flag
end  
return :preprocess(comment)
end  
function p.getPlayer(u)
if type(u) == 'table' then
if type(u[1]) == 'string' and type(u[2]) == 'string' then
--[[if #u[2] >1 then
p.errorString = p.errorString .. "\n\nWe have u[1]=" .. u[1] .. " and u[2]=" .. u[2]
end]]
return u[1], u[2] -- return player name, player sorting alias
else
p.errorString = p.errorString .. " Invalid name entry for player " .. u[1] .. ", " .. u[2]
return "", "" --TODO errroer
end
elseif type(u) == 'string' then
return u, "" -- return player name
else
p.errorString = p.errorString .. " Invalid name entry for player " .. u or u[1] or "unknown"
return "", ""
end
end  
-- ############################## functions to sort goalscorers ######################
p.preprocessSortName (name)
p.getPlayerSortName (playerName, sortName, countryName)
p.sortComment(comment)
p.getCountryName(country)
p.sortGoalscorers -- the main sort funtion  
--[=[ function p.preprocessSortName