Module:Medical cases chart/sandbox3

local getArgs = require('Module:Arguments').getArgs local yesno = require('Module:Yesno') local barBox = require('Module:Bar box')

local language = 'en-US' -- local default language

local i18n = require("Module:Medical cases chart/i18n")[language] local navbar = require('Module:Navbar')._navbar

local function is(v) return (v or ) ~=  end

local p = {}

function p._barColors(n) local colors = { '#A50026', --deaths 'SkyBlue', --recoveries 'Tomato', --cases or altlbl1 'Gold', --altlbl2 'OrangeRed' --altlbl3 }

return colors[n] end

function p._legend0(args) return ' ' .. '' .. '   ' .. ' ' .. ' ' .. (args[2] or '') .. ' ' end

function p._customBarStacked(args) barargs = {} barargs[1] = args[1]

local function _numwidth(nw) if nw == 'n' then return 0 elseif nw == 't' then return 2.45 elseif nw == 'm' then return 3.5 elseif nw == 'w' then return 4.55 elseif nw == 'x' then return 5.6 elseif nw == 'd' then return 3.5 end

return 3.5 end

width1 = 3.5 width2 = 3.5 if is(args.numwidth) then width1 = _numwidth(mw.ustring.sub(args.numwidth,1,1)) width2 = _numwidth(mw.ustring.sub(args.numwidth,2,2)) width3 = _numwidth(mw.ustring.sub(args.numwidth,3,3)) width4 = _numwidth(mw.ustring.sub(args.numwidth,4,4)) end

barargs[2] = ' ' .. (args[7] or '') .. ' ' ..		' ' .. (args[8] or '') .. ' '

if mw.ustring.len(args.numwidth) == 4 then local padding = '0.3em' if mw.ustring.sub(args.numwidth,3,3) == 'n' then padding = '0' end

barargs.note2 = ' ' .. (args[9] or '') .. ' ' ..			' ' .. (args[10] or '') .. ' '	end

for i=1,5 do		barargs[2*i + 1] = p._barColors(i) barargs[2*i + 2] = (tonumber(args[i+1]) or 0)/(tonumber(args.divisor) or 1) barargs['title' .. i] = args[i+1] end

barargs.align = 'cdcc' barargs.collapsed = args.collapsed barargs.id = args.id	barargs.rowstyle = is(tonumber(args.rowheight)) and ('line-height:'..args.rowheight..';') or nil

return barBox._stacked(barargs) end

function p._row(args) local barargs = {} local rowDate = args.prevDate or ''

if is(args[1]) then if pcall(function mw.getContentLanguage:formatDate('', args[1]) end) then barargs[1] = args[1] rowDate = args[1] else barargs[1] = ' ' .. i18n.invalidTime .. ' '		end else barargs[1] = '⋮' end barargs[1] = barargs[1] .. (args['note0'] or '')

barargs[2] = args[2] or 0 barargs[3] = args[3] or 0

if is(args['alttot1']) then barargs[4] = args['alttot1'] elseif args[4] then barargs[4] = (tonumber(args[4]) or 0) - (tonumber(barargs[2]) or 0) - (tonumber(barargs[3]) or 0) else barargs[4] = 0 end

barargs[5] = args[5] or 0

if is(args['alttot2']) then barargs[6] = args['alttot2'] elseif args[6] then barargs[6] = (tonumber(args[6]) or 0) - (tonumber(barargs[2]) or 0) - (tonumber(barargs[3]) or 0) else barargs[6] = 0 end

barargs[7] = args[7] or ''

local function changeArg(firstright, valuecol, changecol) local change = '' if yesno(args['firstright' .. firstright]) == true then change = '(' .. i18n.na .. ')' elseif yesno(args['firstright' .. firstright]) == false or not is(args['firstright' .. firstright]) then if not is(args[1]) and is(args[valuecol]) then change = '(' .. i18n['='] .. ')' else change = is(args[changecol]) and '(' .. args[changecol] .. ')' or '' end end change = change .. (args['note' .. firstright] or '')

return change end

barargs[8] = changeArg(1,7,8) barargs[9] = args[9] or '' barargs[10] = changeArg(2,9,10)

barargs.divisor = args.divisor or 1 barargs.numwidth = args.numwidth barargs.rowheight = args.rowheight

if yesno(args.collapsible) == true then local duration = tonumber(args.duration) or 15 if args.collapsed then barargs.collapsed = args.collapsed elseif args.rowsToEnd >= duration then barargs.collapsed = 'y'		else barargs.collapsed = '' end

if args.id then barargs.id = args.id		elseif args.nooverlap and args.rowsToEnd < duration then barargs.id = 'l' .. duration else barargs.id = mw.ustring.lower(mw.getLanguage('en'):formatDate('M', rowDate)) if args.rowsToEnd < duration then barargs.id = barargs.id .. '-l' .. duration end end else barargs.collapsed = '' barargs.id = '' end

return p._customBarStacked(barargs) end

function p._buildBars(args) local lines = mw.text.split(args.data, '\n') local frame = mw.getCurrentFrame local lang = mw.getContentLanguage

local bars, rows, months, prevRow, maxparam = {}, {}, {}, '', 1 for k, line in pairs(lines) do		local barargs, i = {}, 1 for parameter in mw.text.gsplit(line, ';') do			parameter = mw.text.trim(parameter) if string.find(parameter, '^%a') then parameter = mw.text.split(parameter, '=') if parameter[1] == 'alttot1' or parameter[1] == 'alttot2' then parameter[2] = tonumber(frame:callParserFunction('#expr', parameter[2])) if is(parameter[2]) then maxparam = math.max(maxparam, parameter[2]) end end barargs[parameter[1]] = parameter[2] else if is(parameter) then if i >= 2 and i <= 6 then parameter = tonumber(frame:callParserFunction('#expr', frame:callParserFunction('formatnum',parameter,'R'))) maxparam = math.max(maxparam, parameter or 1) end barargs[i] = parameter if i == 7 or i == 9 then parameter = tonumber(mw.ustring.match(frame:callParserFunction('formatnum',parameter,'R'), '^%d*')) maxparam = math.max(maxparam, parameter or 1) end end i = i + 1 end end

local function fillCols(col, change) local data = args['right' .. col .. 'data'] local changetype = args['changetype' .. col] local value, num, prevnum

if data == 'alttot1' then num = tonumber(barargs.alttot1 or barargs[4]) prevnum = tonumber(prevRow.alttot1 or prevRow[4]) elseif data == 'alttot2' then num = tonumber(barargs.alttot2 or barargs[6]) prevnum = tonumber(prevRow.alttot2 or prevRow[6]) elseif is(data) then num = tonumber(barargs[tonumber(data) + 1]) prevnum = tonumber(prevRow[tonumber(data) + 1]) end

if is(data) and num then -- nothing in column, source found, and data exists value = changetype == 'o' and '' or lang:formatNum(num) -- set value to num if changetype isn't 'o' if not change and yesno(barargs['firstright' .. col] ~= true) then if prevnum and prevnum ~= 0 then -- data on previous row if num - prevnum ~= 0 then --data has changed since previous row change = num-prevnum if changetype == 'a' then -- change type is "absolute" if change > 0 then change = '+' .. lang:formatNum(change) end else -- change type is "percent", "only percent" or undefined local percent = 100 * change / prevnum -- calculate percent local rounding = math.abs(percent) >= 10 and "%.0f" or math.abs(percent) >= 1 and "%.1f" or "%.2f" percent = tonumber(mw.ustring.format(rounding, percent)) -- round to two sigfigs if percent > 0 then change = '+' .. lang:formatNum(percent) .. '%'								elseif percent < 0 then change = lang:formatNum(percent) .. '%'								else change = i18n['='] end end else -- data has not changed since previous row change = i18n['='] end else -- no data on previous row barargs['firstright' .. col] = true -- set to (n.a.) end end end

return value, change end

if not is(barargs[7]) then barargs[7], barargs[8] = fillCols(1, barargs[8]) end if not is(barargs[9]) then barargs[9], barargs[10] = fillCols(2, barargs[10]) end if is(barargs[1]) then local e,f,g = pcall(				function 					return mw.getLanguage('en'):formatDate('M',barargs[1]),						mw.getLanguage('en'):formatDate('j',barargs[1])				end			) if e then months[#months+1] = {f,g} end end barargs.prevDate = prevRow[1] rows[#rows + 1] = barargs prevRow = barargs end

for i=1,#rows do -- build rows rows[i].divisor = tonumber(args.divisor) and tonumber(args.divisor) or maxparam / (0.95 * args.barwidth) rows[i].numwidth = args.numwidth rows[i].collapsible = args.collapsible rows[i].rowsToEnd = #rows - i		rows[i].rowheight = args.rowheight rows[i].duration = args.duration if #months>(args.duration or 0) then rows[i].nooverlap = args.nooverlap end bars[i] = p._row(rows[i]) end return table.concat(bars), months end

function p._monthToggleButton(args) local month = mw.ustring.lower(mw.ustring.sub(args.month[1] or '',1,3)) local outString = '' local newline = (args.nonewline or false) and '' or '\n' if is(month) then local collapsed = (args.active == ) and  or ' mw-collapsed' local uncollapsed = (args.active == ) and ' mw-collapsed' or  if args.nooverlap then outString = '%s \n' .. '%s ' .. newline if mw.ustring.sub(month,1,1) == 'l' and tonumber(mw.ustring.sub(month,2)) == args.duration then --"Last ## days" local lastDays = mw.ustring.format(i18n.lastDays, args.duration) outString = mw.ustring.format( outString,					collapsed, lastDays,					uncollapsed, lastDays ) else if i18n.m[month] then if is(args.month[2]) and is(args.month[3]) then if (args.month[2] ~= args.month[3]) then -- "Mmm ##–##" month = mw.ustring.gsub(i18n.toggleRange,'$.', {								['$m'] = i18n.m[month],								['$s'] = args.month[2],								['$e'] = args.month[3]}) else -- "Mmm ##""							month = mw.ustring.gsub(i18n.toggleSingleDate,'$.', {								['$m'] = i18n.m[month],								['$s'] = args.month[2]})						end					else --"Mmm"						month = i18n.m[month]					end				end				outString = mw.ustring.format( outString,					uncollapsed, month,					collapsed, month )			end		elseif mw.ustring.sub(month,1,1) == 'l' and tonumber(mw.ustring.sub(month,2)) == args.duration then			local customtoggles = {(' mw-customtoggle-l' .. args.duration)}			for k in pairs(i18n.m) do --list of months				customtoggles[#customtoggles + 1] = ' mw-customtoggle-' .. k .. '-l' .. args.duration			end			local lastDays = mw.ustring.format(i18n.lastDays, args.duration)			outString = '' .. lastDays .. ' \n' ..				'' .. lastDays .. ' ' .. newline		else			local customtoggles = ' mw-customtoggle-' .. month .. ' mw-customtoggle-' .. month .. '-l' .. args.duration			outString = '' .. (i18n.m[month] or month) .. ' \n' ..				'' .. (i18n.m[month] or month) .. ' '  .. newline		end	end	return outString end

function p._chart(args)

local barargs = {}

-- mappings and defaults moved to _getChartPams local numwidth = args.numwidthwidth local right1 = args.right1width local right2 = args.right2width local barwidth = args.barwidth barargs.width = args.sTotalWidth barargs.barwidth = args.sBarWidth barargs.float = args.float local duration = args.nDuration

local months, togglesbar, lastdate = –, '', nil if args.rows then barargs.bars = args.rows togglesbar = yesno(args.collapsible) and ( args.togglesbar or '' ) or nil elseif is(args.data) or is(args.datapage) then local buildargs = {} local nooverlap = yesno(args.nooverlap) buildargs.barwidth = tonumber(barwidth) or 280 buildargs.data = is(args.datapage) and require('Module:Medical cases chart/data')._externalData(args) or args.data buildargs.divisor = args.divisor buildargs.numwidth = args.numwidth buildargs.collapsible = args.collapsible buildargs.right1data = args.right1data or -- if no right1data and right1 title is default, use 3rd classification not args.right1 and 3 buildargs.right2data = args.right2data or -- if no right2data and right2 title is deaths, use 1st classification (args.right2 == i18n.noOfDeaths or args.right2 == i18n.noOfDeaths2) and 1 --buildargs.changetype1 = mw.ustring.sub(args.changetype1 or (args.changetype or ''),1,1) -- 1st letter --buildargs.changetype2 = mw.ustring.sub(args.changetype2 or (args.changetype or ''),1,1) -- 1st letter buildargs.changetype1 = args.changetype1 buildargs.changetype2 = args.changetype2 buildargs.rowheight = args.rowheight buildargs.duration = duration if is(args.togglesbar) then buildargs.nooverlap = false else buildargs.nooverlap = nooverlap end barargs.bars, monthList = p._buildBars(buildargs) local lastRow = #monthList if nooverlap == true then if #monthList <= duration then nooverlap = false else lastRow = #monthList - duration end end

for i=1,(lastRow) do -- deduplicate months if monthList[i][1] ~= months[#months][1] then --new month if #months > 1 and i > 1 then months[#months][3] = monthList[i-1][2] --store end of previous month end months[#months+1] = monthList[i] --store start of this month end end months[#months][3] = monthList[lastRow][2] --store end of final month -- automatically generate toggles if yesno(args.collapsible) == true then if is(args.togglesbar) then togglesbar = args.togglesbar else local toggles = {} for i=1,#months do					toggles[#toggles+1] = p._monthToggleButton({month=months[i], duration=duration, nooverlap=nooverlap}) end toggles[#toggles+1] = p._monthToggleButton({month={('l' .. duration)}, duration=duration, nooverlap=nooverlap}) togglesbar = ' \n' .. table.concat(toggles) .. ' '			end end end local location = mw.ustring.gsub(args.location, 'the ', '') location = mw.ustring.upper(mw.ustring.sub(location,1,1)) .. mw.ustring.sub(location,2)

local navbartitle = args.outbreak .. ' data/' .. (args.location3 and args.location3 .. '/' or '') .. (args.location2 and args.location2 .. '/' or '') .. location .. ' medical cases chart'

local title = {} title[1] = (args.pretitle and args.pretitle .. ' ' or '') .. args.disease .. ' ' .. i18n.casesIn .. ' ' .. args.location .. (args.location2 and ', ' .. args.location2 or '') .. (args.location3 and ', ' .. args.location3 or '') .. (args.posttitle and ' ' .. args.posttitle or '') .. ' (' ..		navbar({[1] = navbartitle, titleArg = ':' .. mw.getCurrentFrame:getParent:getTitle, mini = 1, nodiv = 1}) ..		') '	title[2] = p._legend0({[1] = p._barColors(1), [2] = 'Deaths'}) if args.recoveries then title[3] = '  ' .. p._legend0({[1] = p._barColors(2), [2] = args.reclbl or i18n.recoveries}) else title[3] = '' end title[4] = '  ' .. p._legend0({[1] = p._barColors(3), [2] = args.altlbl1 or i18n.activeCases}) if args.altlbl2 then title[5] = '  ' .. p._legend0({[1] = p._barColors(4), [2] = args.altlbl2}) else title[5] = '' end if args.altlbl3 then title[6] = '  ' .. p._legend0({[1] = p._barColors(5), [2] = args.altlbl3}) ..'\n' else title[6] = '\n' end title[7] = togglesbar barargs.title = table.concat(title)

barargs.left1 = ' ' .. -- 85-8 because of padding "'''" .. i18n.date .. "'''" ..		' '

barargs.right1 = ' ' ..			"'''" .. (args.right1 or i18n.noOfCases) .. "'''" ..		' '

if args.right2 then barargs.right2 = ' ' ..			"'''" .. args.right2 .. "'''" ..		' '	end

barargs.caption = args.caption barargs.css = 'Template:Medical_cases_chart/styles.css' return barBox._box(barargs) end

function p.chart(frame) local tRawPams = getArgs(frame)

local tChartPams = p._getChartPams(tRawPams) --local tRawRows, tChartPams = p._getChartPams(tRawPams) --local tBoxPams = p._getBoxPams(tRawPams)

--tBoxPams.bars = p._getDataRows(tRawRows, tChartPams)

--return barBox._box(tBoxPams)

return p._chart(tChartPams) end

function p._getChartPams(tRawPams) --local tRawRows = tRawPams.data

--local tChartPams = {}

-- numwidth local sNumwidthLower = tRawPams.numwidth and mw.ustring.lower(tRawPams.numwidth) or nil local tNumWidthMap = {['n'] = 0, ['t'] = 40, ['m'] = 55, ['w'] = 70, ['x'] = 85,  ['d'] = 55} local function _numwidth(p) local nw = mw.ustring.sub(sNumwidthLower or '',p,p) return tNumWidthMap[nw] or 0 end local numwidth = 120 local right1 = numwidth - 8 -- -8 because of padding if sNumwidthLower then numwidth = _numwidth(1) + 10 + _numwidth(2) if mw.ustring.len(sNumwidthLower) == 4 then numwidth = numwidth + _numwidth(3) + _numwidth(4) if mw.ustring.sub(sNumwidthLower,3,3) == 'n' then numwidth = numwidth + 6 else numwidth = numwidth + 10 end end right1 = _numwidth(1) + 2 + _numwidth(2) if not tRawPams.right2 and mw.ustring.len(sNumwidthLower) == 4 then right1 = right1 + _numwidth(3) + _numwidth(4) if mw.ustring.sub(sNumwidthLower,3,3) == 'n' then numwidth = numwidth + 6 else numwidth = numwidth + 10 end end end tRawPams.numwidthwidth = numwidth tRawPams.right1width = right1 if tRawPams.right2 then local right2 = _numwidth(3) + _numwidth(4) if mw.ustring.sub(tRawPams.numwidth,3,3) == 'n' then right2 = right2 - 2 else right2 = right2 + 2 end tRawPams.right2width = right2 end -- barwidth and width local tBarWidthMap = {['thin'] = 120, ['medium'] = 280, ['wide'] = 400, ['auto'] = 'auto'} local sBarWidthLower = tRawPams['barwidth'] and mw.ustring.lower(tRawPams['barwidth']) or nil tRawPams.barwidth = tBarWidthMap[sBarWidthLower] or 280 if tonumber(tRawPams.barwidth) then tRawPams.sTotalWidth = (85 + tRawPams.barwidth + numwidth) .. 'px' tRawPams.sBarWidth = tRawPams.barwidth .. 'px' else tRawPams.sTotalWidth = 'auto' tRawPams.sBarWidth = 'auto' end

-- recoveries, defaults to true for undefined or unrecognised values tRawPams.recoveries = not (yesno(tRawPams.recoveries) == false)

-- changetype[|1|2] local sChangeType = tRawPams.changetype and mw.ustring.lower(mw.ustring.sub(tRawPams.changetype, 1, 1)) or '' tRawPams.changetype1 = tRawPams.changetype1 and mw.ustring.lower(mw.ustring.sub(tRawPams.changetype1, 1, 1)) or sChangeType tRawPams.changetype2 = tRawPams.changetype2 and mw.ustring.lower(mw.ustring.sub(tRawPams.changetype2, 1, 1)) or sChangeType

-- float tRawPams.float = tRawPams.float or 'right'

-- duration (togglesbar) local bCanSetDur = yesno(tRawPams.collapsible) and not tRawPams.togglesbar tRawPams.nDuration = bCanSetDur and tonumber(tRawPams.duration) or 15

--return tRawRows, tChartPams return tRawPams end

function p.barColors(frame) return p._barColors(tonumber(frame:getParent.args[1])) end

function p.buildBars(frame) local bars = p._buildBars(frame.args) return bars end

function p.monthToggleButton(frame) local args = {} args.month = {frame:getParent.args.month or frame:getParent.args[1] or 'l15'} args.active = frame:getParent.args.active or 'true' args.duration = frame:getParent.args.duration or 15 args.nonewline = true return p._monthToggleButton(args) end

return p