Mô đun:Goalscorers

require('strict');
local yesno = require('Module:Yesno')
local p = {} 
local g = {}         -- for parameters with global scope in this module
g.goalscorers = {}   -- table where selected and sorted players will be place
g.args = {}
g.totalGoals = 0
local data = {}      -- module subpage data -- require('Module:Goalscorers/data/UEFA Euro 2016 qualifying'); 
p.errorString = ""
function p.error_msg()
	if p.errorString ~= "" then
		return 
	         -- '|_template='
	         .. p.errorString .. ;
	end
end
-- data for goals scored held in module subpages, e.g. "Module:Goalscorers/data/UEFA Euro 2016 qualifying"
-- parameters containing data help in three tables
						data.rounds = {}   -- group, play-off
						data.goalscorers = {}    -- player, country, goals in each round)
						data.owngoalscorers = {} -- player, country, goals in each round)
						data.updated = {}        -- date of latest update (month, day, year)
					--
-- ############################ Parameter handing  ###############################
p.getArgs() - gets arguments from frame (invoke) or parent frame (template)     
local function getArgs(frame)
	local parents = mw.getCurrentFrame():getParent()
		
	for k,v in pairs(parents.args) do
		--check content
		if v and v ~= "" then
			g.argsk=mw.text.trim(v) --parents.argsk
		end
	end
	for k,v in pairs(frame.args) do
		--check content
		if v and v ~= "" then
			g.argsk= mw.text.trim(v)  --parents.argsk
		end
	end
	-- allow empty caption to blank default
	--if parents.args'caption' then templateArgs'caption' = parents.args'caption' end
end
-- ############################## Main function and other functions ######################
p.main()                      - simple output of the data in the module in list form
p.addIntroductorySentence()   - add sentence on number of goals and matches, with goals per match
p.addFooterSentence()         - add footnote
p.getNumberMatches()
p.owngoals()                  - get own goals (no longer used?)
	 p._owngoals()                 - core functionality for p.owngoals()
function p.main(frame)
getArgs(frame)
local dataTarget =  g.args1 or  g.args'data'
if dataTarget then
data = require('Module:Goalscorers/data/'.. dataTarget) --or 'UEFA Euro 2016 qualifying' 
	return p.useModuleData(frame)  -- data on goals taken from module subpage
else
	return p.useTemplateData(frame)  -- data on goals/assists taken from template
end

end
function p.useModuleData(frame)
--p.goalscorers = {} -- table where selected and sorted players will be place
g.totalGoals = 0
local ok = p.selectGoalscorers() -- selected goalscorers meeting round and group criteris
if not ok then return p.error_msg() end

-- CHANGE: append own goals to list  (data will now include goals and own goals (negative))  
p.selectGoalscorers("OG")    

p.sortGoalscorers() -- sort selected goalscorers by number of goal, then country
local outputString = p.addIntroductorySentence() .. p.outputGoalscorers(frame) .. p.addFooterSentence()
--                      .. ""              --TODO add intermediate heading?
--                      .. p._owngoals(frame)  -- output list of goalscorers

return p.error_msg() or outputString
end
function p.addIntroductorySentence()          -- add introductory text
	
	local totalGoalString = "Tổng cộng có " .. g.totalGoals .. " bàn thắng đã ghi được."
	--Đã có #GOALS bàn thắng ghi được trong #MATCHES trận đấu, trung bình #GOALS/#MATCHES bàn thắng mỗi trận đấu.
	
	local matches, dateUpdated = p.getNumberMatches()
	local mdyFormat = yesno(g.args'dmy')
	
	local Date = require('Module:Date')._Date
	
	local pluralGoals = ""
	local text1 = ""
	if g.totalGoals == 1 then
		pluralGoals = ""
		if dateUpdated == 'complete' then text1 = "Đã" else text1 = "Đang" end
	else
		if dateUpdated == 'complete' then text1 = "Đã" else text1 = "Đang" end
	end
	local text = string.format("%s có %s bàn thắng%s ghi được", text1, mw.getLanguage('vi'):formatNum(g.totalGoals), pluralGoals)
	
	local pluralMatches = ""
	if matches==1 then pluralMatches = "" end
	if matches then
		local average = g.totalGoals/tonumber(matches)
		local precision = 3                        -- display d.dd (three significant disgits)
		if average ' .. footerSentence .. 
end
return footerSentence
end
function p.getNumberMatches()
	local matches = g.args'matches'
	local dateUpdated = data.updated'date' or "1700-01-01" --'complete' -- assume completed if missing

--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 round, group =  p.getRoundAndGroup()

local allGroupGames = 0
local latestGroupDate = "1800-01-01" 
if group and (round == "all" or group == "all") then           -- count all the group games
	for k,v in pairs(data.updated.group) do
		allGroupGames = allGroupGames + v1
		if v2 ~= "complete" and v2 > latestGroupDate then latestGroupDate = v2 end -- update if later date
	end
	if latestGroupDate == "1800-01-01" then latestGroupDate = "complete"  end -- no dates so must be complete
end
if group and (round == "all" and group ~= "all") then                   -- for totals of all rounds with only one group
allGroupGames     = data.updated.groupgroup1     -- number matches
latestGroupDate = data.updated.groupgroup2       -- update date or completed
	end
	if round == "all" then                                       -- all rounds and goals
matches=0
for k,v in pairs(data.updated) do 
if k == "group" then
		matches = matches + allGroupGames
	     	if latestGroupDate ~= "complete" and latestGroupDate > dateUpdated then 
	     		dateUpdated = latestGroupDate                -- update if later date
	        end 
	elseif p.validateRound(k) then
		matches = matches + v1
		    if v2 ~= "complete" and v2 > dateUpdated then dateUpdated = v2 end -- update if later date
	end
	
end 
	elseif round == "group" then                                  -- group round only
	    if group == "all" then                            
		   matches = allGroupGames
		   dateUpdated = latestGroupDate  
		else                                                      -- single group only
matches     = data.updated.groupgroup1                 -- number matches
dateUpdated = data.updated.groupgroup2                 -- update date or completed
		end
	else                                                          -- any other round
matches     = data.updatedround1                           -- number matches
dateUpdated = data.updatedround2                           -- update date or completed
end 

if dateUpdated == "1700-01-01" then dateUpdated = "complete"  end -- no dates so must be complete
	return matches, dateUpdated
end
function p.owngoals(frame) -- need to check parameters if external call
getArgs(frame)
data = require('Module:Goalscorers/data/'.. g.args1) --or 'UEFA Euro 2016 qualifying' 
local outputString = p._owngoals(frame)
return  p.error_msg() or outputString
end
function p._owngoals(frame) -- internal call for own goals
--p.goalscorers = {} -- table where selected and sorted players will be place

p.selectGoalscorers("OG") -- selected goalscorers meeting round and group criteris

p.sortGoalscorers() -- sort selected goalscorers by number of goal, then country
return p.outputGoalscorers(frame, "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(v1)                -- 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(v2, v3)  then 
		    	   goalsByRound = 0
		    	   commentByRound = ""
		    	else
		    		goalsByRound, commentByRound = p.getGoals( vi , 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.args1 .. ":Mix:round=all and group=" .. group .. "/" .. p.getGroup(v2, v3 ) )
		    for i = goalsCol, #v, 1 do        
		    	if i == p.getGoalsCol("group") and group ~= p.getGroup(v2, v3)  then 
		    	   goalsByRound = 0
		    	   commentByRound = ""
		    	else
		    		goalsByRound, commentByRound = p.getGoals( vi , 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(v2, v3) then                         -- single group only 
				goals, comment = p.getGoals( vgoalsCol , playerName)
			elseif group == "all" then                                 -- any group
				goals, comment = p.getGoals( vgoalsCol , playerName)
			else   
				-- do nothing for other groups
			end
		--elseif round == "playoffs" then                                   -- playoff round (redunant?)
		--	   goals = vgoalsCol
		else                                                              -- any other round
			goals, comment = p.getGoals( vgoalsCol , playerName)        -- should also handle playoffs
	    end 
	    if goals >= goalMinimum and goals ~= 0 then
	    	   if comment ~= "" then 
	    	   	  if og == "OG" then 
	    	   	  	comment = ' (' .. p.sortComment(comment) .. ')' 
	    	   	  else
	    	   	  	comment =  .. comment ..    -- 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=v2, 
			   	                                   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 1 then 
				p.errorString = p.errorString  .. "\n\nWe have u1=" .. u1 .. " and u2=" .. u2
			end
			return u1, u2            -- return player name, player sorting alias
		else
			p.errorString = p.errorString .. " Nhập tên không hợp lệ cho cầu thủ " .. u1 .. ", " .. u2 
			return "", ""     --TODO errroer
		end
	elseif type(u) == 'string' then
		return u, ""                 -- return player name
	else
		p.errorString = p.errorString .. " Nhập tên không hợp lệ cho cầu thủ " .. u or u1 or "chưa biết"
		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()
stripp off wikitext  and 
force to lowercase
change special characters to standard letters
**
function p.preprocessSortName (name)
	name = string.gsub(name, "%%", "")              -- strip off  and 
	name = string.gsub(name, "%%", "")
--name =string.lower(name)                          -- force lower case and return
name = mw.ustring.lower(name)                       -- use unicode function
	local specialChars = {                            -- list of special characters and replacement pairs
		                   { "ı", "i" } , { "İ", "i" } , { "ß", "ss" },
		                   { "ý", "y" } , { "ř", "r" } , { "ő", "o" },
		                   { "é", "e" } , { "è", "e" } , { "þ", "th" },
		                   { "ē", "e" } , { "ņ", "n" } , { "č", "c" },
		                   { "ū", "u" } , { "ž", "z" } , { "æ", "ae" },
		                   { "å", "a" } , { "ø", "o" } , { "ą", "a" },
		                   { "ń", "n" } , { "ł", "l" } , { "ã", "a" },
		                   { "ș", "s" } , { "š", "s" } , { "í", "i" },
		                   { "á", "a" } , { "ä", "a" } , { "ć", "c" },
		                   { "ç", "c" } , { "ğ", "g" } , { "ö", "o" },
		                   { "ë", "e" } , { "ú", "u" } , { "ó", "o" },
		                   { "ð", "d" } , { "ü", "u" } , { "ű", "u" },
		                   { "ā", "a" } , { "ī", "i" } , { "đ", "d" },
		                   { "ă", "a" } , { "â", "a" } , { "ż", "z" },
		                   { "ț", "t" } , { "ş", "s" } , { "ś", "s" },
		                   { "ǎ", "a" } , { "ě", "e" } , { "ů", "u" },
		                   { "ĕ", "e" } , { "ñ", "n" } , { "ď", "d" },
		                   { "ï", "i" } , { "ź", "z" } , { "ô", "o" },
		                   { "ė", "e" } , { "ľ", "l" } , { "ģ", "g" },
		                   { "ļ", "l" } , { "ę", "e" } , { "ň", "n" },
		                   { "ò", "o" }
}
for k,v in pairs(specialChars) do                 -- replace special characters from supplied list
	name = string.gsub(name, v1, v2)
end
	return name                     
end
-- return the name for sorting 
return supplied alias name for sorting
otherwise
checks for pipe (redirect) and uses name after pipe
splits name into words
returns first name if only name (e.g. Nani)
otherwise returns name in format second_name .. last name, firstname
function p.getPlayerSortName (playerName, sortName, countryName)
	
			--dewikify all names before sorting, also forces lowercase
	playerName = p.preprocessSortName(playerName)
	sortName = p.preprocessSortName(sortName)
	
	if sortName ~= "" then                           -- if we have a sort name supplied
		return sortName                              --            then return it
	end
	
	-- players from certain countries will use name in order supplied
	local noSort = { "CAM", "CHN", "TPE", "MYA", "PRK", "KOR", "VIE" }
	for k,v in pairs(noSort) do 
		if v == countryName then
			return playerName
		end
	end
	
	
	-- else work it out from the supplied player name
		
-- we don't want to test the name in a redirect, so get name after pipe if there is one
if string.find (playerName, "|") then                 -- test for redirect
	local names = mw.text.split( playerName, "|")    
	playerName = names2                               -- get name after pipe
end
local names = mw.text.split( playerName, " ") -- we don't want to sort on first name
	
	if #names == 1 then
		return names1                             -- return name of single name player
	else
		-- we will assume the second name is the sort name e.g, Joe Bloggs, Jan van Bloggen
		local name = names2                   -- set name to second name e.g. Bloggs or van
		local i=3
		while i  b.goals) then                -- primary sort on 'goals' -> a before b
		        return true
		    elseif (a.goals  b before a
		        return false
		    else -- a.goals == b.goals 		           -- primary sort tied, 
		        
		        --return a.country  country_b) then    -- secondary sort on 'country'
			        return false
			    else -- a.country == b.country 		   -- secondary sort tied, 
			        --return a.player ' .. p.addLinkedIcon(frame, u'country')    -- linked flag icon    
	if playerActive and g.args'bold'~='no' then
		goalscorerString = goalscorerString  .. " " .. u'player' .. ""    -- bolded name
	else
		    goalscorerString = goalscorerString  .. " " .. u'player'                  -- name
	end
	goalscorerString = goalscorerString  .. u'comment'   ..              -- comment for o.g.
	                              
	outputString = outputString .. goalscorerString   --  .. " " .. tostring(u'goals')
end -- reached end of list of goalscorers
	if outputString ~= "" then
	    outputString = outputString .. p.closeList(frame)
		return outputString
	else
		return ("Không có bàn thắng nào khớp với tiêu chí được yêu cầu.")
	end
end
-- output icon linked to national team page
function p.addLinkedIcon(frame, country)
	local icon = data.templates'flag_icon_linked'         -- fbicon etc set in data module
	local level = data.templates'youth_level'  or ""           -- parameter for youth level, ie under-21
-- equivalent to  country     
local flagVariant = ""
if data.templates.flagvar and data.templates.flagvarcountry then
	flagVariant = data.templates.flagvarcountry 
end
if level ~= "" then 
	return frame:expandTemplate{ title = icon , args = { level, country, flagVariant } }   
else
	return frame:expandTemplate{ title = icon , args = { country, flagVariant } }     -- flag icon
end
end
-- formatting of list under each number of goals
function p.openList(frame,og)
	return mw.getCurrentFrame():extensionTag{
		name = 'templatestyles', args = { src = 'Div col/styles.css' }
	} ..  -- perhaps add "column-count:3;"" to limit max number of columns?
end
function p.closeList(frame)
return 
end
function p.firstToUpper(str)
return (str:gsub("^%l", string.upper))
end
-- handles parameters bold, further, extra
function p.addAdditionHeaderText(text, dateUpdated)
if g.args'inlineref' then
	text = text .. g.args'inlineref'
end
if g.args'bold' and g.args'bold'~='no' then
	text = text .. " Các cầu thủ được thể hiện bằng chữ đậm vẫn đang thi đấu ở giải."
end
if g.args'further' then
	if text ~= "" then text = text .. " " end
	text = text .. g.args'further'
end
if g.args'extra' then
	text = text .. "\n\n" .. g.args'extra'
end
return text
end
-- count number of goals for data in template
function p.countGoals(list, number, totalGoals)
local split = mw.text.split( list, "\n", true )  -- split the list for number of goals scorers with N goals
local count = #split  * math.abs(number)         -- calculate number of goals (including own goals)
totalGoals = totalGoals + count

--mw.addWarning( "Nhập: " .. list  .. "" .. count .. "")
	return totalGoals 
end
-- use data supplied by template 
--function p.list(frame)
function p.useTemplateData(frame)
--getArgs(frame)

--