Module:Sandbox/User:4madness/ParamSum

From WIDEVERSE Wiki
Jump to navigation Jump to search

Documentation for this module may be created at Module:Sandbox/User:4madness/ParamSum/doc

-- 
-- Accepts data in the format "param=pval1|param2=pval2!param=pval2|param2=pval2!..." and sums each value together
-- <nowiki>
--

local yesno = require( 'Module:Yesno' )
local hc = require('Module:Paramtest').has_content

p = {}

function p.table(frame)
	local args = frame:getParent().args
	local data = args[1] or args.data or nil
	local selected = args[2] or args.selected or nil
	
	args.html = yesno(args.html)
	
	if (data == nil) then
		return '<span class="error">No data provided.</span>'
	end
	if (selected == nil) then
		return 	'<span class="error">No selected value list provided.</span>'
	elseif (not hc(selected)) then
		return 	'<span class="error">Selected value list cannot be empty.</span>'
	end
	
	return p._table(data,selected,args)
end

function p._table(data,selected,args)
	args = args or {}
	local sum_table = {}
	
	selected = mw.text.trim(selected)
	
	-- initialize sums to zero
	-- keys not in this table are skipped
	for k in mw.text.gsplit(selected, '%s*,%s*') do
		sum_table[k] = 0
	end
	
	local rowcount = 0
	for oneRawRow in string.gmatch(data, '([^!]+)') do -- split by '!' symbols
		oneRawRow = mw.text.trim(oneRawRow)
		if (hc(oneRawRow)) then
			rowcount = rowcount + 1
			for k, v in string.gmatch(oneRawRow, '([^|]*)=([^|]*)') do
				k = mw.text.trim(k)
				if (sum_table[k] ~= nil) then
					sum_table[k] = sum_table[k] + tonumber(v)
				end
			end
		end
	end
	-- save rowcount to special ID
	sum_table['#'] = rowcount
	
	if (args.html) then
		return p._table_html(sum_table,selected,args)
	else
		return p._table_wikitable(sum_table,selected,args)
	end
end

function p._table_html(sum_table,selected,args)
	local html = mw.html.create('tr')
	local classes = ''
	
	for k in mw.text.gsplit(selected, '%s*,%s*') do
		classes = p._parse_conditional_classes(sum_table[k], args[k .. " class"], sum_table['#']) or ''
		if (classes ~= '') then
			html = html:tag('td'):addClass(classes):wikitext(sum_table[k]):done()
		else
			html = html:tag('td'):wikitext(sum_table[k]):done()
		end
	end
	
	return html:done()
end

function p._table_wikitable(sum_table,selected,args)
	local ret = ''
	
	for k in mw.text.gsplit(selected, '%s*,%s*') do
		local classes = p._parse_conditional_classes(sum_table[k], args[k .. " class"], sum_table['#']) or ''
		ret = ret .. (ret ~= '' and '||' or '')
			.. (classes ~= '' and (' class="' .. classes .. '" |') or '')
			.. sum_table[k]
	end
	
	return ret
end

function p._parse_conditional_classes(val, classdefs, count)
	if (not hc(classdefs)) then
		return '' -- shortcut for no content
	elseif (not string.find(classdefs, ':', 1, true)) then
		return classdefs -- shortcut if no conditionals found
	end
	
	local ret = ''
	for class in mw.text.gsplit(classdefs, '%s+') do
		local parts = mw.text.split(class, ':')
		-- if class has a condition, add only if condition is met
		if (#parts > 1) then
			if (p._meets_condition(parts[1], val, count)) then
				ret = ret .. parts[2] .. ' '
			end
		else
			ret = ret .. parts[1] .. ' ' -- add conditionless classes
		end
	end
	return ret
end


-- condtions are of format "<operation><compare-value>"
-- conditions of format "<compare-value>", assume "eq" for the operation
-- if "<compare-value>" is "#", the count will be used as the compare value
function p._meets_condition(condition, val, count)
	if (condition == nil or val == nil) then
		return nil
	elseif (condition == '') then
		return true
	end
	
	local op = string.match(condition, '^[^%d#]+')
	local compare = string.sub(condition, #op+1)
	if (compare == '#') then
		if (count == nil) then
			return nil
		end
		compare = count	
	end
	if (op == 'eq' or op == '') then
		return val == tonumber(compare)
	elseif (op == 'gt') then
		return val > tonumber(compare)
	elseif (op == 'lt') then
		return val < tonumber(compare)
	elseif (op == 'neq') then
		return val ~= tonumber(compare)
	elseif (op == 'gteq') then
		return val >= tonumber(compare)
	elseif (op == 'lteq') then
		return val <= tonumber(compare)
	end
	
	return false
end

return p