Documentația acestui modul poate fi creată la Modul:FootballMatch/doc

local StringUtils = require('Modul:StringUtils')
local getArgs = require('Modul:Arguments').getArgs
local wikidata = require('Modul:Wikidata')
local illWd = require('Modul:Ill-wd').fromArgs
local DateUtils = require('Modul:DateUtils')
local TableTools = require('Modul:TableTools')
local WDF_U = require('Modul:WikidataUtils/Football')
local NameAndImage = require('Modul:NameAndImage')
local FC = require('Modul:FootballClub')

local _br_ = tostring(mw.html.create('br'))
local EXTRATIME = "([[Prelungiri după timpul regulamentar 90 de minute|d.p.]])"
local ATTENDANCE = "Spectatori: "
local REFEREE = "Arbitru: "
local eventschema = "http://schema.org/SportsEvent"
local teamschema = "http://schema.org/SportsTeam"
local placeschema = "http://schema.org/Place"

local emptyToNil = StringUtils._emptyToNil

local p = {}

local SCORING_METHOD_INDEX = { Q18533 = 'aut.', Q279532 = 'pen.' }

local function fmtlist(s)
	s = mw.ustring.gsub(s or '', '%[%[ *([%?-]) *%]%]', '%1')
	s = mw.ustring.gsub(s, '%[%[ *[%?-] *| *(.-) *%]%]', '%1')
	if mw.ustring.sub(s, 1, 1) == '*' then
		return tostring(mw.html.create('div'):addClass('plainlist'):newline():wikitext(s))
	end
	return s
end

local function makelink(s,t)
	if s:match('^http') then
		return '[' .. s .. ' ' .. t .. ']'
	end
	return s
end

function p.fromArgs(match, aspect)
	local tbl
	if aspect.bg ~= '' then
		tbl = mw.html.create('table')
			:attr('cellspacing', '0')
			:addClass('collapsible'):addClass('collapsed'):addClass('vevent')
			--:addClass('mw-collapsible'):addClass('mw-made-collapsible')
			:addClass(aspect.class)
			:css('width', aspect.width or '100%')
			:css('background-color', aspect.bg)
			:css('border-top', '1px solid #999')
			:css('border-bottom', '1px solid #999')
			:css('margin-bottom', '-1px')
	else
		tbl = mw.html.create('table')
			:attr('cellspacing', '0')
			:addClass('collapsible'):addClass('collapsed'):addClass('vevent')
			--:addClass('mw-collapsible'):addClass('mw-made-collapsible')
			:addClass(aspect.class)
			:css('width', aspect.width or '100%')
			:css('border-top', '1px solid #999')
			:css('border-bottom', '1px solid #999')
			:css('margin-bottom', '-1px')
	end
	if not aspect.nobars then
		tbl:css('border-top', '1px solid #999999')
		if not aspect.stack then
			tbl:css('border-bottom', '1px solid #999999')
		end
	end
	
	local headRow = tbl:tag('tr'):css('vertical-align', 'top')
	local dateAndCompetitionCell  = headRow:tag('td'):css('width', '28%')
	if match.date or match.round then
		dateAndCompetitionCell:tag('span')
			:css('float', 'right')
			:css('white-space', 'nowrap')
			:css('margin-left', '0.5em')
		    :wikitext(match.date)
		if match.round then
			dateAndCompetitionCell:tag('small'):wikitext(match.round)
		end
	end
	
	local team1cell = headRow:tag('td')
			:addClass('vcard'):addClass('attendee')
			:css('width', '23%')
			:css('text-align', 'right')
			:tag('span')
				:addClass('fn'):addClass('org')
				:css('white-space', 'nowrap')
				:wikitext(StringUtils._encloseString({match.teams[1], "''' ", " '''"}))
	
	local scorecell = headRow:tag('td')
			:css('width', '12%')
			:css('text-align', 'center')
	local scorespan = scorecell:tag('span')
			:css('white-space', 'nowrap')
			:css('display', 'inline')
	scorespan:wikitext("''' " .. (match.score or 'v') .. " '''")
	if match.aet then
		scorespan:tag('span')
			:css('font-size', '85%')
			:wikitext(EXTRATIME)
	end
	if match.aggregatescore then
		scorecell:tag('br'):done()
			:tag('div')
				:css('font-size', '85%')
				:wikitext("('''", match.aggregatescore, "''' [[Scorul la general|gen.]])")
	end
	if match.penaltyscore then
		scorecell:tag('br'):done()
			:tag('div')
				:css('font-size', '85%')
				:wikitext("('''", match.penaltyscore, "''' [[Fotbal#Reprizele_de_prelungiri_.C8.99i_loviturile_de_departajare|d.l.d.]])")
	end
	
	local team2cell = headRow:tag('td')
			:addClass('vcard'):addClass('attendee')
			:css('width', '23%')
			:tag('span')
				:addClass('fn'):addClass('org')
				:css('white-space', 'nowrap')
				:wikitext(StringUtils._encloseString({match.teams[2], "''' ", " '''"}))
	
	local venuecell = headRow:tag('td')
			:css('width', '23%')
			:css('font-size', '85%')
			:addClass('location')
			:wikitext(match.location)
	
	headRow:tag('th')
		:attr('width', '4%')
		:attr('valign', 'top')
		:attr('rowspan', '2')
		:wikitext('')
		
	local scorersRow = tbl:tag('tr')
		:css('vertical-align', 'top')
		:css('font-size', '85%')
		
	local timeCell = scorersRow:tag('td')
		:css('text-align', 'right')
		:wikitext(match.time)
	
	local hostsGoalsTd = scorersRow:tag('td')
		:css('text-align', 'right')
		:wikitext(match.goalslists[1])
	local reportTd = scorersRow:tag('td')
		:css('text-align', 'center')
	reportTd:wikitext(makelink(match.report or '', 'Raport'))
	if match.qid then
		reportTd:wikitext(_br_ .. '[[:d:' .. match.qid .. '|Wikidata]]')
	end
	local guestsGoalsTd = scorersRow:tag('td')
		:css('text-align', 'left')
		:wikitext(match.goalslists[2])
	local detailsTd = scorersRow:tag('td')
	if match.stadium then
		detailsTd:wikitext('Stadion: '):wikitext(match.stadium):wikitext(_br_)
	end
	if match.attendance then
		detailsTd:wikitext(ATTENDANCE):wikitext(match.attendance):wikitext(_br_)
	end
	if match.referee then
		detailsTd:wikitext(REFEREE):wikitext(match.referee):wikitext(_br_)
	end
	if match.assistantreferees then
		detailsTd:wikitext('Arbitri asistenți: '):wikitext(match.assistantreferees):wikitext(_br_)
	end
	if match.goallineassistants then
		detailsTd:wikitext('Arbitri de linia porții: '):wikitext(match.goallineassistants):wikitext(_br_)
	end
	if match.fourthofficial then
		detailsTd:wikitext('Arbitru de rezervă: '):wikitext(match.fourthofficial):wikitext(_br_)
	end
	if match.motm then
		detailsTd:wikitext('Omul meciului: '):wikitext(match.motm):wikitext(_br_)
	end
	if match.penaltyLists and #(match.penaltyLists) > 1 then
		local penaltiesTitleRow = tbl:tag('tr')
		penaltiesTitleRow:tag('td'):attr('rowspan', '2')
		penaltiesTitleRow:tag('td'):attr('colspan', '3'):css('text-align', 'center'):wikitext(illWd('Q2691960', 'Penalty-uri de departajare', nil, true))
		penaltiesTitleRow:tag('td'):attr('rowspan', '2')
		
		local penaltiesRow = tbl:tag('tr')
		penaltiesRow:tag('td'):css('text-align', 'right'):wikitext(match.penaltyLists[1])
		penaltiesRow:tag('td')
		penaltiesRow:tag('td'):wikitext(match.penaltyLists[2])
	end
	return tostring(tbl)
end

local function grabFirstQual(quals)
	local theQual
	if quals then for _,eachQual in ipairs(quals) do
		if 'value' == eachQual.snaktype then
			theQual = eachQual
			break
		end
	end end
	return theQual
end

local function grabFirstStatement(entityId, propId)
	local statementClaim = nil
	local statementClaimsList = wikidata.findBestClaimsForProperty(entityId, propId)
	if statementClaimsList then for _,eachStatementClaim in ipairs(statementClaimsList) do
		if 'statement' == eachStatementClaim.type and 'value' == eachStatementClaim.mainsnak.snaktype then
			statementClaim = eachStatementClaim
			break
		end
	end end
	return statementClaim
end

local function extractDataFromArray(array)
	local entityId = array.q or mw.wikibase.getEntityIdForCurrentPage()
	
	local aspect = {}
	aspect.class = array.class
	aspect.bars = nil == array.nobars
	aspect.stack = nil ~= array.stack
	aspect.width = array.width or '100%'
	aspect.bg = array.bg or ''
	
	local match = {}
	match.qid = array.q
	match.id = array.id or array.q
	match.round = array.round
	match.event = array.event or array.eveniment or wikidata.findOneValue('P361', array.q) or wikidata.findOneValue('P179', array.q)
	match.date = array.date or array['dată'] or ''
	local wdDateClaim = nil
	local matchDate = nil
	if not match.date then
		wdDateClaim = grabFirstStatement(entityId, 'P585')
		if wdDateClaim then
			matchDate = DateUtils.parseWikidataDate(wdDateClaim.mainsnak.datavalue.value.time, wdDateClaim.mainsnak.datavalue.value.precision)
			match.date = DateUtils.formatDate(matchDate, true, false)
		end
	end
	match.time = array.time
	match.teams = {}
	for _,eachTeamArg in ipairs({array.team1 or array.echipa1, array.team2 or array.echipa2}) do
		if eachTeamArg then table.insert(match.teams, eachTeamArg) end
	end
	local scoreElements = {}
	local teamIds = {}
	if 2 > #(match.teams) then
		local wdTeamClaims = wikidata.findBestClaimsForProperty(array.q, 'P1923')
		local thisIsFirstTeam = true
		if wdTeamClaims then for _,eachTeamClaim in ipairs(wdTeamClaims) do
			table.insert(teamIds, eachTeamClaim.mainsnak.datavalue.value.id)
			local isoTS = DateUtils.toISO8601(matchDate)
			local thisTeamLabel
			local thisTeamFlag
			if WDF_U.isNationalTeam(eachTeamClaim.mainsnak.datavalue.value.id) then
				thisTeamLabel = WDF_U.getNationalTeamName(eachTeamClaim.mainsnak.datavalue.value.id)
				thisTeamFlag = NameAndImage._imageFromOneOfProps(eachTeamClaim.mainsnak.datavalue.value.id, {'P41'}, matchDate)
			else
				thisTeamLabel = FC.labelFromArgs(eachTeamClaim.mainsnak.datavalue.value.id, isoTS)
				thisTeamFlag = FC.flagLinkFromArgs(eachTeamClaim.mainsnak.datavalue.value.id, isoTS)
			end
			local thisTeamLink = illWd(eachTeamClaim.mainsnak.datavalue.value.id, thisTeamLabel, nil, true)
			table.insert(match.teams, thisIsFirstTeam and (thisTeamLink .. ' ' .. thisTeamFlag) or (thisTeamFlag .. ' ' .. thisTeamLink))
			if eachTeamClaim.qualifiers and eachTeamClaim.qualifiers['P1351'] and eachTeamClaim.qualifiers['P1351'][1] and eachTeamClaim.qualifiers['P1351'][1].snaktype == 'value' then
				table.insert(scoreElements, math.abs(eachTeamClaim.qualifiers['P1351'][1].datavalue.value.amount))
			end
			thisIsFirstTeam = false
		end end
	end
	
	match.score = array.score or array.scor or emptyToNil({table.concat(scoreElements, mw.text.decode('–'))})
	match.aet = (nil ~= array.aet)
	match.aggregate = array.aggregatescore
	match.penaltyscore = array.penaltyscore
	match.referee = array.referee or array.arbitru or wikidata.findOneValue('P1652', array.q)
	match.report = array.report or array.raport or wikidata.findOneValueNoRef('P856', array.q)
	match.assistantreferees = array.assistantreferees
	match.goallineassistants = array.goallineassistants
	match.fourthofficial = array.fourthofficial
	match.attendance = array.attendance or array.spectatori or wikidata.findOneValue('P1110', array.q)
	match.location = array.location or array.loc
	match.stadium = array.stadium or array.stadion
	match.motm = array.motm or array.mvp
	match.notes = array.note or array.notes
	if array.penalties1 and array.penalties2 then
		match.penaltyLists = { array.penalties1, array.penalties2 }
	end
		
	if not match.stadium then
		local venueStatement = grabFirstStatement(array.q, 'P276')
		if venueStatement then
			match.stadium = wikidata.printSnak(venueStatement.mainsnak)
			local townSnak
			if venueStatement.qualifiers and venueStatement.qualifiers['P131'] then
				townSnak = grabFirstQual(venueStatement.qualifiers['P131'])
				if townSnak then 
					match.location = wikidata.printSnak(townSnak)
				end
			end
			if not townSnak then
				match.location = wikidata.findOneValue('P131', venueStatement.mainsnak.datavalue.value.id)
			end
		end
	end
				
	match.goalslists = {}
	if array.goals1 or array.goluri1 then match.goalslists[1] = array.goals1 or array.goluri1 end
	if array.goals2 or array.goluri2 then match.goalslists[2] = array.goals2 or array.goluri2 end
	if 1 > table.maxn(match.goalslists) and array.q then
		local wdGoalsClaims = wikidata.findBestClaimsForProperty(array.q, 'P1363')
		local goalsTables = { {}, {} }
		if wdGoalsClaims and #wdGoalsClaims > 0 then
			wdDateClaim = wdDateClaim or grabFirstStatement(entityId, 'P585')
			local matchDate = wdDateClaim and DateUtils.extractDateFromWikidataSnak(wdDateClaim.mainsnak) or matchDate
			local goalScorers = {}
			local goalScorersOrder = {}
			for _,eachGoalClaim in ipairs(wdGoalsClaims) do if 'statement' == eachGoalClaim.type and 'value' == eachGoalClaim.mainsnak.snaktype then
				local minute, addedTime, matchIntervalId, authorId, fromTeamId, scoringMethodId
				if eachGoalClaim.qualifiers then
					authorId = eachGoalClaim.mainsnak.datavalue.value.id
					if eachGoalClaim.qualifiers['P1390'] then
						local minuteSnak = grabFirstQual(eachGoalClaim.qualifiers['P1390'])
						if minuteSnak.snaktype == 'value' then
							minute = minuteSnak.datavalue.value.amount
						end
					end
					if eachGoalClaim.qualifiers['P6887'] then
						local matchIntervalSnak = grabFirstQual(eachGoalClaim.qualifiers['P6887'])
						if matchIntervalSnak.snaktype == 'value' then
							matchIntervalId = matchIntervalSnak.datavalue.value.id
						end
					end
					if eachGoalClaim.qualifiers['P54'] then
						local fromTeamSnak = grabFirstQual(eachGoalClaim.qualifiers['P54'])
						if fromTeamSnak then
							fromTeamId = fromTeamSnak.datavalue.value.id
						end
					end
					if eachGoalClaim.qualifiers['P1443'] then
						local scoringMethod = grabFirstQual(eachGoalClaim.qualifiers['P1443'])
						if scoringMethod then
							scoringMethodId = scoringMethod.datavalue.value.id
						end
					end
				end
				
				if matchIntervalId then
					local minuteNo = tonumber(minute)
					if matchIntervalId == 'Q62521848' and minuteNo > 45 then
						addedTime = minuteNo - 45
						minute = 45
					elseif matchIntervalId == 'Q62521875' and minuteNo > 90 then
						addedTime = minuteNo - 90
						minute = 90
					elseif matchIntervalId == 'Q186982' and minuteNo > 120 then
						addedTime = minuteNo - 120
						minute = 120
					end
				end
				
				local goalDirection = scoringMethodId == 'Q18533' and -1 or 1
				local goalScorerIndex = mw.text.jsonEncode({ scorerId = authorId, direction = goalDirection, teamId = fromTeamId})
				local crtScorerGoals
				if goalScorers[goalScorerIndex] then
					crtScorerGoals = goalScorers[goalScorerIndex]
				else 
					table.insert(goalScorersOrder, goalScorerIndex)
					crtScorerGoals = {}
				end
				crtScorerGoals.scorerId = crtScorerGoals.scorerId or authorId
				crtScorerGoals.teamId = crtScorerGoals.teamId or fromTeamId
				crtScorerGoals.direction = crtScorerGoals.direction or goalDirection
				crtScorerGoals.goals = crtScorerGoals.goals or {}
				table.insert(crtScorerGoals.goals, {goalTime = minute, addedTime = addedTime, goalMethod = scoringMethodId })
				goalScorers[goalScorerIndex] = crtScorerGoals
			end end
			
			table.sort(goalScorersOrder, function(scorerIndex1, scorerIndex2)
				local scorer1 = goalScorers[scorerIndex1]
				local scorer2 = goalScorers[scorerIndex2]
				if not scorer1 or not scorer1.goals or #scorer1.goals == 0 then return -1 end
				if not scorer2 or not scorer2.goals or #scorer2.goals == 0 then return 1 end
				local minGoal1 = tonumber(scorer1.goals[1].goalTime)
				for _,eachGoal in ipairs(scorer1.goals) do
					local thisGoalTime = tonumber(eachGoal.goalTime)
					if thisGoalTime < minGoal1 then minGoal1 = thisGoalTime end
				end
				local minGoal2 = tonumber(scorer2.goals[1].goalTime)
				for _,eachGoal in ipairs(scorer2.goals) do
					local thisGoalTime = tonumber(eachGoal.goalTime)
					if thisGoalTime < minGoal2 then minGoal2 = thisGoalTime end
				end
				if minGoal1 < minGoal2 then return true end
				return false
			end)
			
			for _,scorerIndex in pairs(goalScorersOrder) do
				local scorerGoals = goalScorers[scorerIndex]
				local goalText = illWd(scorerGoals.scorerId, nil, nil, true)
				local goalTemplateParams = {}
				for _,eachGoalData in ipairs(scorerGoals.goals) do
					table.insert(goalTemplateParams, StringUtils._removeStart({tostring(eachGoalData.goalTime), '+'}) .. (eachGoalData.addedTime and ('+' .. tostring(eachGoalData.addedTime)) or ''))
					table.insert(goalTemplateParams, SCORING_METHOD_INDEX[eachGoalData.goalMethod or ''] or '')
				end
				goalText = goalText .. ' ' .. mw.getCurrentFrame():expandTemplate{title = 'Gol', args = goalTemplateParams}
				if scorerGoals.teamId == teamIds[1] and scorerGoals.direction == 1
					or scorerGoals.teamId == teamIds[2] and scorerGoals.direction == -1 then
						table.insert(goalsTables[1], goalText)
				else
						table.insert(goalsTables[2], goalText)
				end
			end

			for eachGoalsTableIdx,eachGoalsTable in ipairs(goalsTables) do
				match.goalslists[eachGoalsTableIdx] = table.concat(eachGoalsTable, _br_)
			end
		end
	end
	return match, aspect
end

function p.fromArray(array)
	local match, aspect = extractDataFromArray(array)
	return p.fromArgs(match, aspect)
end

function p.fromFrame(frame)
	return p.fromArray(getArgs(frame))
end

function p.uncollapsibleFromArgs(match, aspect)
	-- Start box
	local root = nil
	if aspect.bg ~= '' then
		root =
			mw.html.create('div')
				:attr('itemscope', '')
				:attr('itemtype', eventschema)
				:addClass('footballbox')
				:css('width', aspect.width)
				:css('background-color', aspect.bg)
				:attr('id', match.id)
	else
		root =
			mw.html.create('div')
				:attr('itemscope', '')
				:attr('itemtype', eventschema)
				:addClass('footballbox')
				:css('width', aspect.width)
				:attr('id', match.id)
	end
	root:newline()
	if match.round then
		root:tag('div')
			:addClass('ftitle')
			:wikitext(match.round)
	end
	
	-- Start left block
	block = root:tag('div')
		:addClass('mobile-float-reset')
		:addClass('fleft')
	
	local timetag = block:tag('time')
		:attr('itemprop', d and 'startDate' or nil)
		:attr('datetime', d)
		
	timetag:tag('div')
		:addClass('mobile-float-reset')
		:addClass('fdate')
		:wikitext(match.date)
	
	if match.time then
		timetag:tag('div')
			:addClass('mobile-float-reset')
			:addClass('ftime')
			:wikitext(match.time)
	end
	
	if match.round then
		block:tag('div')
			:addClass('mobile-float-reset')
			:addClass('frnd')
			:wikitext(match.round)
	end
	-- End block
	
	-- Start table
	local rtable = root:tag('table')
		:addClass('fevent')
	local row = rtable:tag('tr')
		:attr('itemprop', 'name')
	row:newline()
	row:tag('th')
		:addClass('fhome')
		:attr('itemprop', 'homeTeam')
		:attr('itemscope', '')
		:attr('itemtype', teamschema)
		:tag('span')
			:attr('itemprop', 'name')
			:wikitext(match.teams[1])
	row:tag('th')
		:addClass('fscore')
		:wikitext(StringUtils._appendToString(match.score, StringUtils._prependIfMissing((match.aet or match.penaltyscore) and EXTRATIME or nil, ' ')))
	row:tag('th')
		:addClass('faway')
		:attr('itemprop', 'awayTeam')
		:attr('itemscope', '')
		:attr('itemtype', teamschema)
		:tag('span')
			:attr('itemprop', 'name')
			:wikitext(match.teams[2])

	row = rtable:tag('tr')
		:addClass('fgoals')
		:newline()
	row:tag('td')
		:addClass('fhgoal')
		:wikitext(fmtlist(match.goalslists[1]))
	row:newline()
	row:tag('td')
		:wikitext(makelink(match.report or '', 'Raport'))
		:wikitext(match.qid and (_br_ .. '[[:d:' .. match.qid .. '|Wikidata]]') or '')

	row:newline()
	row:tag('td')
		:addClass('fagoal')
		:wikitext(fmtlist(match.goalslists[2]))
	row:newline()
	
	if match.penaltyscore then
		row = rtable:tag('tr')
			:addClass('fgoals')
		row:newline()
		row:tag('td')
			:addClass('fhgoal')
			:wikitext(match.penaltyLists and fmtlist(match.penaltyLists[1]) or '')
		row:newline()
		row:tag('th')
			:wikitext(match.penaltyscore)
		row:newline()
		row:tag('td')
			:addClass('fagoal')
			:wikitext(match.penaltyLists and fmtlist(match.penaltyLists[2]) or '')
		row:newline()
	end
	-- End table
	
	-- Start right block
	block = root:tag('div')
		:addClass('mobile-float-reset')
		:addClass('fright')
	
	if match.stadium then
		local sdiv = block:tag('div')
			:attr('itemprop', 'location')
			:attr('itemscope', '')
			:attr('itemtype', placeschema)
		if match.location then
			sdiv:tag('span')
				:attr('itemprop', 'name')
				:wikitext(match.stadium)
			sdiv:wikitext(', ')
			sdiv:tag('span')
				:attr('itemprop', 'address')
				:wikitext(match.location)
		else
			sdiv:tag('span')
				:attr('itemprop', 'name address')
				:wikitext(match.stadium)
		end
	end
	
	if match.attendance then
		block:tag('div'):wikitext(ATTENDANCE ..' ' .. match.attendance)
	end
	if match.referee then
		block:tag('div'):wikitext(REFEREE .. ' ' .. match.referee)
	end
	
	return mw.getCurrentFrame():extensionTag{ name = 'templatestyles', args = { src = 'Football box/styles.css'} } .. tostring(root)
end

function p.uncollapsibleFromArray(array)
	local match, aspect = extractDataFromArray(array)
	return p.uncollapsibleFromArgs(match, aspect)
end
function p.uncollapsibleFromFrame(frame)
	return p.uncollapsibleFromArray(getArgs(frame))
end
return p