----- Cell colors -----
local COL_FST = 'gold' -- 1st place
local COL_SND = 'silver' -- 2nd place
local COL_TRD = '#C96' -- 3rd place
local COL_LST = '#FE8080' -- Last place
local COL_SFQ = 'navajowhite' -- Semi-Final qualifier
local COL_BJQ = 'paleturquoise' -- Backup jury qualifier
local COL_DSQ = '#A4EAA9' -- Disqualifed / withdrawn entry
----- Text -----
local AQ = 'Automatic qualifier'
local NQ = 'Failed to qualify'
local NOSEMI = 'No semi-finals'
local NA = 'N/A'
local MILLSTREET = 'Kvalifikacija za Millstreet'
local ESC1996Q = 'Eurovision Song Contest 1996#Qualifying round'
----------------------------------------------------------------------------------------------------
local getArgs = require('Module:Arguments').getArgs
local p = {}
local amountOfEntries
local usedLanguages = {}
function p.entry(f) return main(f, 'entry') end
function p.year(f) return main(f, 'year') end
function p.country(f) return main(f, 'country') end
function p.list(f) return main(f, 'list') end
function main(f, reqOutput)
local args = getArgs(f)
local html = ''
local contest = getContest(args['cont'])
local id = args['id']
local country = args['cnty']
local year = args['y']
local show = args['s']
local entryNo = args['no']
local sortMethod = ''
if not show then show = 'gf' end
if not entryNo then entryNo = 1 end
if show == 'gf' then sortMethod = 'draw' end
local entries
if reqOutput == 'year' or reqOutput == 'list' then -- Get all entries from country
entries = getAllEntriesFrom{contest=contest.id, from='year', year=year, show=show, sortMethod=sortMethod}
elseif reqOutput == 'country' then -- Get all entries from year
entries = getAllEntriesFrom{contest=contest.id, from='country', country=country}
else end
amountOfEntries = tableLen(entries)
local function getEntryNo(entry)
local entryNo = 1
if entry.cntye then
entryNo = entry.cntye
end
return entryNo
end
if reqOutput == 'entry' then
if country and year then
html = table.concat(createEntryRow{reqOutput=reqOutput, contest=contest, entryNo=entryNo, country=country, year=year})
elseif id then
entryNo = getEntryNo(getEntry{contest=contest, id=id})
html = table.concat(createEntryRow{reqOutput=reqOutput, contest=contest, entryNo=entryNo, id=id})
end
else
for _, entry in ipairs(entries) do
entryNo = getEntryNo(entry)
html = html .. table.concat(createEntryRow{reqOutput=reqOutput, contest=contest, show=show, entryNo=entryNo, country=entry.cnty, year=entry.y})
end
end
return html
end
--------------------------------------------------
local row = 0
local spannedRows = {}
local spannedCols = {}
function createEntryRow(args)
local html = {}
local f = mw.getCurrentFrame()
local contest = args.contest
local year = args.year
local country = args.country
if country and country['name'] then
for i, name in ipairs(country['name']) do
if name[2] then
if contest.dates[tostring(year)] < name[2] then
country = name[1]
break
end
end
country = name[1]
end
end
local id = args.id
local entryNo = args.entryNo
local reqOutput = args.reqOutput
local show = args.show
local entry
if country and year then
entry = getEntry{contest=contest, country=country, year=year, entryNo=entryNo}
elseif id then
entry = getEntry{contest=contest, id=id}
end
if entry then
row = row + 1
spannedCols = {}
local id = entry.id
local year = f:expandTemplate{title = 'Escyr', args = {entry.y, entry.c.id}}
local draw
local sf_draw = insertZeroBeforeSingleDigit(entry.sf_d)
local gf_draw = insertZeroBeforeSingleDigit(entry.gf_d)
if not sf_draw then sf_draw = entry.sf_h end
if not gf_draw then gf_draw = entry.gf_h end
local pl, pt
local sf_pl = entry.sf_pl
local gf_pl = entry.gf_pl
local sf_pt = entry.sf_pt
local gf_pt = entry.gf_pt
if show then
if show == 'gf' then
draw = gf_draw
pl = gf_pl
pt = gf_pt
else
draw = sf_draw
pl = sf_pl
pt = sf_pt
end
else
if sf_draw then
if gf_draw then
-- Took part in both semi-final and grand-final
pl = gf_pl
pt = gf_pt
draw = gf_draw
else
-- Only took part in semi-final
pl = sf_pl
pt = sf_pt
draw = sf_draw
end
elseif gf_draw then
-- Only took part in grand final
pl = gf_pl
pt = gf_pt
draw = gf_draw
end
end
local flag
if entry.cnty['flag'] then
for _, version in ipairs(entry.cnty['flag']) do
if contest.dates[tostring(entry.y)] < version[2] then
flag = version[1]
break
end
end
end
country = f:expandTemplate{title = 'Esc', args = {country, flag, y = entry.y}}
local country_entry = getEntryNoFromCountry(contest, id)
local artist = entry.art
local song = entry.song
local lang = {}
local function createLangLink(songLang)
if songLang[2] then
songLang = '[[' .. songLang[1] .. '|' .. songLang[2] .. ']]'
else
songLang = '[[' .. songLang[1] .. ']]'
end
return songLang
end
for _, songLang in ipairs(entry.lang) do
if usedLanguages[1] then
local found = false
for _, usedLang in ipairs(usedLanguages) do
if songLang[1] == usedLang then
if songLang[2] then
table.insert(lang, songLang[2])
else
table.insert(lang, songLang[1])
end
found = true
end
end
if not found then
table.insert(lang, createLangLink(songLang))
table.insert(usedLanguages, songLang[1])
end
else
table.insert(lang, createLangLink(songLang))
table.insert(usedLanguages, songLang[1])
end
end
if reqOutput == 'entry' then
entryData = {artist, song}
entryDataText = {'artist', 'song'}
replaceNilValues(entryData, entryData)
elseif reqOutput == 'year' then
entryData = {draw, country, artist, song, lang, pl, pt}
entryDataText = {'draw', 'country', 'artist', 'song', 'lang', 'pl', 'pt'}
replaceNilValues(entryData, entryData)
elseif reqOutput == 'country' then
entryData = {year, artist, song, lang, gf_pl, gf_pt, sf_pl, sf_pt}
entryDataText = {'year', 'artist', 'song', 'lang', 'gf_pl', 'gf_pt', 'sf_pl', 'sf_pt'}
replaceNilValues(entryData, entryDataText)
elseif reqOutput == 'list' then
entryData = {id, draw, country, country_entry, artist, song, lang, pl}
entryDataText = {'id', 'draw', 'country', 'country_entry', 'artist', 'song', 'lang', 'pl'}
replaceNilValues(entryData, entryData)
end
local function isNil(row)
if entryData[row] == 'nil_' .. row then
return true
else
return false
end
end
local tr = '<tr>\n' -- Default no row styling
local rowStyling = ''
if reqOutput == 'year' then
if (show == 'gf') and gf_pl == 1 then
rowStyling = 'font-weight:bold; background:' .. COL_FST .. ';'
elseif (show == 'sf' or show == 'sf1' or show == 'sf2') and (gf_draw or entry.q) then
if entry.jury then
rowStyling = 'font-weight:bold; background:' .. COL_BJQ .. ';'
else
rowStyling = 'font-weight:bold; background:' .. COL_SFQ .. ';'
end
end
end
tr = '<tr style="' .. rowStyling .. '">\n'
table.insert(html, tr)
if entryData then
for i, data in ipairs(entryData) do
if not getIndex(spannedRows, row) and not getIndex(spannedCols, entryDataText[i]) then
local cellStyling = ''
if type(data) == 'string' and string.sub(data, 1, 4) == 'nil_' then -- If the value is nil
data = nil
if reqOutput == 'country' then
local gf_pl = getIndex(entryDataText, 'gf_pl')
local gf_pt = getIndex(entryDataText, 'gf_pt')
local sf_pl = getIndex(entryDataText, 'sf_pl')
local sf_pt = getIndex(entryDataText, 'sf_pt')
local colspan = 1
if not entry.id and entry.dq then
if entryDataText[i] == 'gf_pl' then
if entry.y == 2020 then
data = 'Contest cancelled'
else
data = entry.dq
end
data = data .. ' <b>X</b>'
colspan = 4
else break end
else
if gf_pt and isNil(gf_pt) then -- If no gf points
if not isNil(sf_pl) or not isNil(sf_pt) then
if entryDataText[i] == 'gf_pl' and gf_pl and isNil(gf_pl) then -- If no gf points and no gf placement
data = NQ
if contest.id == 'esc' then
if entry.y == 1993 then data = '[[' .. MILLSTREET .. '|' .. NQ .. ']] <b>X</b>' end
if entry.y == 1996 then data = '[[' .. ESC1996Q .. '|' .. NQ .. ']] <b>X</b>' end
end
colspan = 2
end
else
if entryDataText[i] == 'gf_pt' and not isNil(gf_pl) then -- If no gf points but there is placement (e.g. ESC 1956)
data = NA
end
end
elseif not gf_pt then
if entryDataText[i] == 'gf_pl' and gf_pl and isNil(gf_pl) then -- If no gf points and no gf placement
data = NQ
end
end
if entryDataText[i] == 'sf_pl' and sf_pl then
if isNil(sf_pl) then -- if no semi results
if contest.id == 'esc' and entry.y == 1993 then
data = f:expandTemplate{title = 'Nowrap', args = {'[[' .. MILLSTREET .. ']]'}}
colspan = 2
elseif contest.id == 'esc' and entry.y >= 2004 then
if (not isNil(gf_pl) and not isNil(gf_pt)) or entry.q then
data = AQ
colspan = 2
end
else
data = NOSEMI
colspan = 2
end
end
end
end
if data then
cellStyling = f:expandTemplate{title = 'N/a'}
else
data = ''
end
if colspan > 1 then
cellStyling = cellStyling .. '; colspan="' .. colspan .. '"'
if data == rowspanData then
cellStyling = cellStyling .. '; rowspan="' .. spannedRows .. '"'
--cellStyling = cellStyling .. '; colspan="2"'
table.insert(spannedRows, row + 1)
else
spannedRows = 1
end
table.insert(spannedCols, entryDataText[i + 1])
end
end
if not data then data = '' end
elseif entryDataText[i] == 'id' or entryDataText[i] == 'country_entry' then
cellStyling = 'text-align:right'
if show == 'gf' and sf_draw then
data = '<small><i>' .. data .. '</i></small>'
end
elseif entryDataText[i] == 'draw' then
if (show == 'gf' and not entry.gf_d and entry.gf_h) or (show == 'sf1' or show == 'sf2' or show == 'sf' and not entry.gf_d and entry.gf_h) then
if data == 1 then data = '<b>1st half</b>' end
if data == 2 then data = '<b>2nd half</b>' end
end
cellStyling = 'text-align:center'
elseif entryDataText[i] == 'year' then -- Year column
cellStyling = 'text-align:center'
elseif entryDataText[i] == 'song' then
local title = song
local og_title = ''
if entry.tlang then -- If it's a non-English song title
if entry.og then -- If it's a transliterated title
title = f:expandTemplate{title = 'Transl', args = {entry.tlang, title, italics = 'no'}}
og_title = '<small>(' .. f:expandTemplate{title = 'Lang', args = {entry.tlang, entry.og, italics = 'no'}} .. ')</small>'
else
title = f:expandTemplate{title = 'Lang', args = {entry.tlang, title, italics = 'no'}}
end
end
data = '"' .. title .. '" ' .. og_title
elseif entryDataText[i] == 'lang' then
if type(data) == 'table' then
data = processTable(data)
end
if entry.langm then -- If there are 'minor' languages
local function createNote(lang)
lang = createLangLink(lang)
data = data .. f:expandTemplate{title = 'Efn', args = {'Contains words or phrases in ' .. lang, name=lang}}
end
if type(entry.langm) == 'table' then
for _, v in ipairs(entry.langm) do
createNote(v)
end
else
createNote(langm)
end
end
elseif entryDataText[i] == 'pl' or entryDataText[i] == 'pt' or entryDataText[i] == 'gf_pl' or entryDataText[i] == 'gf_pt' or entryDataText[i] == 'sf_pl' or entryDataText[i] == 'sf_pt' then
cellStyling = 'text-align:right;'
if reqOutput == 'list' or reqOutput == 'country' then
if reqOutput == 'country' then
if entryDataText[i] == 'gf_pl' or entryDataText[i] == 'gf_pt' then
show = 'gf'
elseif entryDataText[i] == 'sf_pl' or entryDataText[i] == 'sf_pt' then
semi = getSemi(contest, entry.id)
if semi then
show = semi
end
end
end
if show then
calcAmountOfEntries(contest.id, entry.y, show)
end
if ((entryDataText[i] == 'sf_pl' or entryDataText[i] == 'sf_pt') and sf_pl == amountOfEntries) or
((entryDataText[i] == 'gf_pl' or entryDataText[i] == 'gf_pt') and gf_pl == amountOfEntries) or
((entryDataText[i] == 'pl' or entryDataText[i] == 'pt') and pl == amountOfEntries) then
cellStyling = cellStyling .. ' background:' .. COL_LST .. '"'
--data = tostring(data) .. ' ◁'
else
if show == 'gf' or reqOutput == 'country' then
local pl = gf_pl
if entryDataText[i] == 'sf_pl' or entryDataText[i] == 'sf_pt' then pl = sf_pl end
if pl == 1 then cellStyling = cellStyling .. ' background:' .. COL_FST .. '"' end
if pl == 2 then cellStyling = cellStyling .. ' background:' .. COL_SND .. '"' end
if pl == 3 then cellStyling = cellStyling .. ' background:' .. COL_TRD .. '"' end
elseif (show == 'sf' or show == 'sf1' or show == 'sf2') and (gf_pl or gf_pt) then
if entry.jury then
cellStyling = cellStyling .. ' background:' .. COL_BJQ .. '"'
--data = tostring(data) .. ' ‡'
else
cellStyling = cellStyling .. ' background:' .. COL_SFQ .. '"'
--data = tostring(data) .. ' †'
end
end
end
end
if data == 0 then data = '<b>' .. data .. '</b>' end -- Make digit bold if nul points
end
if reqOutput == 'country' and entryDataText[i] ~= 'year' and entryDataText[i] ~= 'sf_pl' and entryDataText[i] ~= 'sf_pt' then
calcAmountOfEntries(contest.id, entry.y, 'gf')
local x = amountOfEntries
if gf_pl == 1 then cellStyling = cellStyling .. ' background:' .. COL_FST end
if gf_pl == 2 then cellStyling = cellStyling .. ' background:' .. COL_SND end
if gf_pl == 3 then cellStyling = cellStyling .. ' background:' .. COL_TRD end
if gf_pl == x then cellStyling = cellStyling .. ' background:' .. COL_LST end
if entry.dq or entry.nq then cellStyling = cellStyling .. ' background:' .. COL_DSQ end
end
if i == 1 then
cell = '<th style="' .. rowStyling .. cellStyling .. '" scope="row">\n'
cellClose = '</th>\n'
else
cell = '<td style="' .. rowStyling .. cellStyling .. '">\n'
cellClose = '</td>\n'
end
table.insert(html, cell .. data .. '</td>\n')
end
end
table.insert(html, '</tr>\n')
end
end
return html
end
function getContest(x)
local contests = mw.loadData('Module:Sandbox/TheThomanski/Esc/data').contests
local reqContest = 'esc' -- Default ESC
if x then
reqContest = string.lower(x)
end
local result
for _, contest in ipairs(contests) do -- For every contest do
if contest.id == reqContest then
result = contest
end
end
return result
end
function getEntry(args)
local result
local contest = args.contest
local country = args.country -- Table, macedonia
local year = args.year
local id = args.id
local entryNo = args.entryNo -- For multiple entries per country in a year (e.g. ESC 1956)
if type(contest) == 'string' then
contest = getContest(contest)
end
for _, entry in ipairs(contest.values) do -- For every entry in the contest do
result = nil
if country and year then
if (hasValue(entry.cnty, country)) then -- If the entry is from the requested country
if (entry.y == year) then -- If the entry is from the requested year
result = entry
end
end
elseif id then
if (entry.id == tonumber(id)) then -- If the entry is the requested entry then
result = entry
end
end
if result then
if entryNo and entryNo > 1 then
entryNo = entryNo - 1
else
return result
end
end
end
return result
end
function getAllEntriesFrom(args)
local contest = getContest(args.contest)
local entries = {}
local draw = 1
local q_d = 0
local firstEntry = nil
for i, entry in ipairs(contest.values) do -- For every entry in the contest do
if args.from == 'year' and entry.y == tonumber(args.year) then -- Get all entries from year
if args.show then
if (args.show == 'sf' and entry.sf_d and not entry.sf) or -- Get all entries from Semi-Final
(args.show == 'sf1' and entry.sf == 1) or -- Get all entries from Semi-Final 1
(args.show == 'sf2' and entry.sf == 2) or -- Get all entries from Semi-Final 2
(args.show == 'gf' and (entry.gf_d or entry.q)) -- Get all entries from Grand Final
then
if args.show == 'gf' and args.sortMethod == 'draw' and entry.id then
local found = false
local oldEntry = entry.id
local newEntry = entry.id
if firstEntry == nil then
firstEntry = entry
end
local gf_d = entry.gf_d
while not found do
if entry.q then
q_d = q_d + 1
gf_d = q_d
end
if gf_d == draw then
table.insert(entries, entry)
draw = draw + 1
found = true
else
newEntry = newEntry + 1
entry = getEntry{contest=contest, id=newEntry}
if not entry or entry.y ~= firstEntry.y then
entry = firstEntry
newEntry = entry.id
end
gf_d = entry.gf_d
end
end
else
table.insert(entries, entry)
end
end
else
table.insert(entries, entry)
end
elseif args.from == 'country' and hasValue(entry.cnty, args.country) then -- Get all entries from country
table.insert(entries, entry)
end
end
return entries
end
function getEntryNoFromCountry(contest, id)
if id then
local entry = getEntry{contest=contest, id=id}
local country = entry.cnty
if country['name'] then country = country['name'][1][1] end
local entries = getAllEntriesFrom{contest=contest.id, from='country', country=country}
local extraEntries = {} -- For more than one entry in a year (e.g. ESC 1956)
for i, v in ipairs(entries) do
if extraEntries[v.y] then
extraEntries[v.y] = extraEntries[v.y] + 1
else
extraEntries[v.y] = 0
end
if v.id == entry.id then
local removal = 0
for _, v in pairs(extraEntries) do
removal = removal + v
end
local result = i - removal
if entry.cntye then
result = result .. ' <small>(' .. entry.cntye .. ')</small>'
end
return result
end
end
end
end
function getSemi(contest, id)
local entry = getEntry{contest=contest, id=id}
if entry then
if entry.sf then
return 'sf' .. tostring(entry.sf)
elseif entry.sf_d then
return 'sf'
end
end
return nil
end
function replaceNilValues(entryData, entryDataText)
local length = tableLen(entryDataText)
for i = 1, length do
if not entryData[i] then
entryData[i] = 'nil_' .. i
end
end
end
function calcAmountOfEntries(contest, year, show)
amountOfEntries = tableLen(getAllEntriesFrom{contest=contest, from='year', year=year, show=show})
end
--------------------------------------------------
function insertZeroBeforeSingleDigit(x)
if x then
if x < 10 then
x = '0' .. x
end
end
return x
end
function getIndex(tab, reqV)
if type(tab) == 'table' then
for i, v in ipairs(tab) do
if v == reqV then
return i
end
end
end
return nil
end
function processTable(tab)
local str = ''
if type(tab) == 'table' then
for i, v in ipairs(tab) do
str = str .. v
if i ~= tableLen(tab) then
str = str .. ', '
end
end
return str
else return tab end
end
function tableLen(tab)
local x = 0
if tab then
for _ in pairs(tab) do
x = x + 1
end
end
return x
end
function hasValue(tab, val)
if tab then
if type(tab) == 'table' then
for _, v in pairs(tab) do
if v == val or (type(v) == 'table' and hasValue(v, val)) then
return val
end
end
elseif type(tab) == 'string' then
if tab == val then
return val
end
end
end
return false
end
return p