Module:Sandbox/AB-me/Racing table2

From English Wikipedia @ Freddythechick
local p = {}
local getArgs = require('Module:Arguments').getArgs

local DEFAULT_CODE = 'default' .. os.time()

local data = {
	events = {},
	eventColumns = 1,
	participants = {},
	pointSystems = {},
	results = {},
	notes = {},
	texts = { pos = '<abbr title="Position">Pos.</abbr>', participant = 'Participant', points = 'Points' },
	styles = { pos = { '#FFFFBF', '#DFDFDF', '#FFDF9F' }, pts = '#DFFFDF', noPts = '#CFCFFF', notes = { Ret = '#EFCFFF', DNQ = '#FFCFCF', DNPQ = '#FFCFCF', DSQ = 'background-color:#000000;color:white', DNS = '#FFFFFF', C = '#FFFFFF' } }
}

--local debug = ''

function p.main(frame)
	local args = getArgs(frame)
	return p._main(args)
end

function p._main(args)
	p.handleArg('eventColumns', args.eventColumns, 'number')
	p.handleCsvArg('events', args.events)
	p.handleItemArgs('events', 'event', 'name', 'string', args)
	p.handleItemArgs('events', 'eventColumns', 'columns', 'number', args)

	p.handleCsvArg('participants', args.participants)

	p.handleCsvArg('notes', args.notes)
	p.handleItemArgs('notes', 'note', 'name', 'string', args)
    
    -- Handling of default pointSystem
	if (args.pointSystem ~= nil) then
		if (args.pointSystems == nil) then
			args.pointSystems = DEFAULT_CODE
		else
			args.pointSystems = DEFAULT_CODE .. ',' .. args.pointSystems
		end
		
		args['pointSystem_' .. DEFAULT_CODE] = args.pointSystem
    end

	if (args.pointSystems ~= nil) then
		p.handleCsvArg('pointSystems', args.pointSystems)
		p.handleItemArgsCsv('pointSystems', args.pointSystems, 'pos', 'number', args)
	end

	p.handleItemArgsCsv('events', 'eventPointSystems', 'pointSystems', 'string', args)

    p.handleItemArgs('participants', 'participant', 'name', 'string', args)

	p.handleItemArgs('texts', 'text', nil, 'string', args)

	local colCount = 0

	for i,v in ipairs(data.events) do
		for j = 1, v.columns do
			colCount = colCount + 1
			if (j == 1) then
                p.handleResult(colCount, (args['result_' .. v.code] or args['result_' .. v.code .. '_1']))
                
                for k,w in ipairs(data.notes) do
                    p.handleResultNotes(colCount, (args['resultNotes_' .. v.code .. '_' .. w.code] or args['resultNotes_' .. v.code .. '_1' .. '_' .. w.code]), w.code)
                end

			else
				p.handleResult(colCount, args['result_' .. v.code .. '_' .. j])

                for k,w in ipairs(data.notes) do
                    p.handleResultNotes(colCount, args['resultNotes_' .. v.code .. '_' .. j .. '_' .. w.code], w.code)
                end
			end
		end
	end

	--p.handleResult()

	-- Draw table
    local stack = {}

    --table.insert(stack, '<code><nowiki>' .. debug .. '</nowiki></code>\n\n')
	
	table.insert(stack, '{| class="wikitable" style="font-size:85%; text-align:center;"')
	
	p.writeTableHeader(stack)
	
	for i,v in ipairs(data['participants']) do
		p.writeTableRow(stack, v)
	end
	
	p.writeTableHeader(stack)

	table.insert(stack, '|}')
	
	return table.concat(stack)
end

function p.handleArg(key, value, type)
	if (value ~= nil) then
		data[key] = p.valueToType(value, type)
	end
end

function p.handleCsvArg(key, value)
	if (value ~= nil) then
		local split = mw.text.split(value, ',')
		
		if (data[key] == nil or #data[key] == 0) then
		
			for i,v in ipairs(split) do
				data[key][i] = p.handleCsvArgItem(key, v, i)
			end

		end
	end
end

function p.handleCsvArgItem(key, v, i)
	if (key == 'events') then
		return { code = v, name = v, columns = data['eventColumns'], pointSystems = { DEFAULT_CODE } }
	elseif (key == 'participants') then
		return { code = v, name = v, pos = i, results = {}, resultNotes = {}, points = {} }
	elseif (key == 'pointSystems') then
		return { code = v, pos = {}, notes = {} }
	else
		return { code = v, name = v }
	end
end

function p.handleItemArgs(key, argPrefix, property, type, args)
	local arg = {}

	for k,v in pairs(data[key]) do
        
        arg = args[argPrefix .. '_' .. (v['code'] or k)]

		if (arg ~= nil) then
			if (property ~= nil) then
				v[property] = p.valueToType(arg, type)
			else
				data[key][k] = p.valueToType(arg, type)
			end
		end

	end
end

function p.handleItemArgsCsv(key, argPrefix, property, type, args)
	local arg = {}

	for k,v in pairs(data[key]) do

		arg = args[argPrefix .. '_' .. (v['code'] or k)]

		if (arg ~= nil) then
			local split = mw.text.split(arg, ',')

			for j,w in ipairs(split) do
				v[property][j] = p.valueToType(w, type)
			end
		end

	end

end

function p.handleResult(column, csv)
	if (csv ~= nil) then
		--debug = debug .. 'Handling column ' .. column .. ' with content ' .. csv .. '\n\n'

		local split = mw.text.split(csv, ',')

		local res = {}

		for i,v in ipairs(split) do
			res[v] = i
		end

		for i, v in ipairs(data.participants) do
			if v.results[column] ~= nil then
				v.results[column].pos = res[v.code]
			else
				v.results[column] = { pos = res[v.code], pts = tonumber(res[v.code]), notes = { } }
			end
		end
	end
end

function p.handleResultNotes(column, csv, noteCode)
	if (csv ~= nil) then
		local split = mw.text.split(csv, ',')
		
        local res = {}

        for i,v in ipairs(split) do
            res[v] = 1
        end
		
        for i,v in ipairs(data.participants) do
            if res[v.code] ~= nil then
                if v.results[column] ~= nil then
                    table.insert(v.results[column].notes, noteCode)
                else
                    v.results[column] = { pos = nil, pts = 0, notes = { noteCode } }
                end
            end
        end
	end
end


function p.valueToType(value, type)
	if (type == 'number') then
		return tonumber(value)
	else
		return value
	end
end

-- Render functions

function p.writeTableHeader(stack)
	table.insert(stack, '|-\n')
	table.insert(stack, '! ' .. data.texts.pos .. '\n')
	table.insert(stack, '!' .. data.texts.participant .. '\n')
	if (#data['events'] > 0) then
		for i,v in ipairs(data['events']) do
			table.insert(stack, '!colspan="' .. v.columns .. '"|' .. v.name .. '\n')
		end
	end
	table.insert(stack, '!' .. data.texts.points .. '\n')
end

function p.writeTableRow(stack, participant)
	table.insert(stack, '|-\n')
	table.insert(stack, '!' .. (participant['pos'] or '&ndash;') .. '\n')
	table.insert(stack, '|style="text-align:left;"|' .. participant['name'] .. '\n')
	
	local colCount = 0

	for i,v in ipairs(data['events']) do
		
		for j=1,v['columns'] do
			colCount = colCount + 1

			--table.insert(stack, '|' .. (participant.results[colCount] or '') .. '\n')
			if participant.results[colCount] ~= nil then
				p.writeTableCellResult(stack, participant.results[colCount].pos, participant.results[colCount].notes)
			else
				p.writeTableCellResult(stack, nil, nil)
			end
		end
	end
	
	--table.insert(stack, '!' .. '0' .. '\n')
	
	p.writeTableCellSum(stack, participant)
	
end

function p.writeTableCellResult(stack, pos, notes)
	p.writeTableCellResultStyle(stack, pos)
	
	if (pos ~= nil and notes ~= nil and #notes > 0) then
		table.insert(stack, pos)
        for i,v in ipairs(notes) do
            table.insert(stack, '<span style="margin:0 0 0 0.1em;"><sup>' .. v .. '</sup></span>')
        end
	elseif pos ~= nil then
		table.insert(stack, pos)
	elseif notes ~= nil and #notes > 0 then
        local firstNote = true
        for i,v in ipairs(notes) do
            if firstNote then
                table.insert(stack, v)
            else
                table.insert(stack, '<span style="margin:0 0 0 0.1em;"><sup>' .. v .. '</sup></span>')
            end
            
            firstNote = false
        end
	end
	
	table.insert(stack, '\n')
end

function p.writeTableCellSum(stack, participant)
	table.insert(stack, '!')
	
	sum = 0
	
	for i,v in ipairs(participant.results) do
		sum = sum + (v.pts or 0)
	end
	
	table.insert(stack, sum)
	
	table.insert(stack, '\n')
end

function p.writeTableCellResultStyle(stack, pos)
	if data.styles.pos[pos] ~= nil then
		table.insert(stack, '|style="' .. p.getStyle(data.styles.pos[pos]) .. '"')
	end
	
	table.insert(stack, '|')
end

function p.getStyle(styleString)
	if not string.find(styleString, ':', 1, true) then
		return 'background-color:' .. styleString
	end
	
	return styleString
end

--debug
function p.dump(o)
    if type(o) == 'table' then
       local s = '{ '
       for k,v in pairs(o) do
          if type(k) ~= 'number' then k = '"'..k..'"' end
          s = s .. '['..k..'] = ' .. p.dump(v) .. ','
       end
       return s .. '} '
    else
       return tostring(o)
    end
 end

return p;