Module:Formatting

local private = {} local public = {}

-- Removes leading and trailing spaces from strings function private.trimWhitespace(str) local _start = 1 while (str:sub(_start, _start) == " ") do       _start = _start + 1 end local _end = str:len while (str:sub(_end, _end) == " ") do       _end = _end - 1 end return str:sub(_start, _end) end

-- Checks if a table has a specific key function private.hasKey(_table, key) return _table[key] ~= nil end

-- Gets a specific item from a table, with a fallback if the table doesn't have that key function private.getValue(_table, key, fallback) if private.hasKey(_table, key) then return _table[key] else return fallback end end

-- Gets an array of difficulty objects from a difficulties string function private.deserialiseDifficulties(_difficulties) local difficulties = {} for d in _difficulties:gmatch("([^;]+)") do		local difficulty = {} local i = 0 for arg in d:gmatch("([^,]+)") do			local k = 1 if i == 0 then k = "name" end if i == 1 then k = "level" end if i == 2 then k = "notes" end if #arg > 2 and arg:sub(2, 2) == ":" then local kshort = arg:sub(1, 1) arg = arg:sub(3) if kshort == "c" then k = "charter" end if kshort == "r" then k = "rating" end end difficulty[k] = arg i = i + 1 end table.insert(difficulties, difficulty) end return difficulties end

-- Strips the decimal point off a number function public.truncateDecimal(num) local _type = type(num) if _type == "table" then return public.truncateDecimal(tonumber(private.trimWhitespace(num["args"][1]))) elseif _type == "number" then return math.floor(num) else return num end end

-- Returns the bottom row of a Song template function public.SongTemplateBottomRow(frame) local args = frame:getParent.args local retval = "" if private.hasKey(args, "difficulties") then -- Multi-charter setup local illustration_rowspan = 1 local charters = {} local fallback_label = "("       for _, d in ipairs(private.deserialiseDifficulties(args["difficulties"])) do        	if private.hasKey(d, "charter") then        		table.insert(charters, {"(" .. d["name"] .. ")", d["charter"]})        		illustration_rowspan = illustration_rowspan + 1        	else        		fallback_label = fallback_label .. "/" .. d["name"]        	end        end        fallback_label = fallback_label .. ")" if fallback_label == "" then illustration_rowspan = illustration_rowspan - 1 else if #charters == 0 then fallback_label = "" else fallback_label = "(" .. fallback_label:sub(3)           end            table.insert(charters, {fallback_label, private.getValue(args, "charter", "?")})        end        for i = 1, illustration_rowspan, 1 do            retval = retval .. "|-\n! width=\"25%\"|Chart designer " .. charters[i][1] .. "\n| width=\"25%\"|" .. charters[i][2]            if i == 1 then                retval = retval .. "\n! width=\"25%\" rowspan=\"" .. illustration_rowspan .. "\"|Illustration\n| width=\"25%\" rowspan=\"" .. illustration_rowspan .. "\"|" .. private.getValue(args, "illustration", "?")            end            retval = retval .. "\n"        end    else        -- Single charter setup        retval = "|-" .. "\n! width=\"25%\"|Chart designer\n| width=\"25%\"|" .. private.getValue(args, "charter", "?")        retval = retval .. "\n! width=\"25%\"|Illustrator\n| width=\"25%\"|" .. private.getValue(args, "illustration", "?") end return retval end

function public.SongTemplateDifficultyRow(frame) local args = frame.args if private.hasKey(args, 1) then local difficulties = private.deserialiseDifficulties(args[1]) local diff_names = {} local diff_levels = {} local diff_ratings = {} local diff_notes = {} for _, d in ipairs(difficulties) do			table.insert(diff_names, d["name"]) table.insert(diff_levels, private.getValue(d, "level", "?")) table.insert(diff_ratings, private.getValue(d, "rating", "?.?")) table.insert(diff_notes, private.getValue(d, "notes", "???")) end local row_width = tostring(100.0 / (#difficulties + 1)) .. "%"		local name_row = mw.html.create("tr") local level_row = mw.html.create("tr") local rating_row = mw.html.create("tr") local notes_row = mw.html.create("tr") name_row :tag("th") :css("border-left", "0px") :css("border-top", "0px") :css("width", row_width) :wikitext("Difficulty") :done for i, d in ipairs(diff_names) do			name_row :tag("th") :css("border-top", "0px") :css("width", row_width) :wikitext(d) :done end name_row:allDone level_row :tag("th") :css("border-left", "0px") :wikitext("Level") :done for i, d in ipairs(diff_levels) do			level_row :tag("td") :wikitext(d) :done end level_row:allDone rating_row :tag("th") :css("border-left", "0px") :wikitext("Rating") :done for i, d in ipairs(diff_ratings) do			rating_row :tag("td") :wikitext(d) :done end rating_row:allDone notes_row :tag("th") :css("border-left", "0px") :wikitext("Note count") :done for i, d in ipairs(diff_notes) do			notes_row :tag("td") :wikitext(d) :done end notes_row:allDone local retval = ' "		return retval	end end

function public.SongTemplateDifficultyCategories(frame) local args = frame:getParent.args local retval = "" if private.hasKey(args, "difficulties") then local difficulties = private.deserialiseDifficulties(args["difficulties"]) for _, difficulty in ipairs(difficulties) do			if private.hasKey(difficulty, "level") then retval = retval .. ""			end end end return retval end

return public