Module:MaroScale

From MTG Wiki
Revision as of 02:51, 8 January 2017 by >Corveroth
Jump to navigation Jump to search

Documentation for this module may be created at Module:MaroScale/doc

-- Little bit of Lua for building tables for the Storm and Rabiah scales.
-- Mechanics have been re-ranked in the past, and it's probably interesting to track their drift.
-- Rather than force editors to track the newest one, let's see if we can't do it in code.

local MaroScale = {}

local sub, match, gsub = mw.ustring.sub, mw.ustring.match, mw.ustring.gsub

-- A list of all sets which have been Standard-legal since the introduction of the Storm Scale (September 2012)
local LEGAL_EXPANSIONS = {
	["Return to Ravnica"]		= "2012-10-05",
	["Gatecrash"] 				= "2013-02-01",
	["Dragon's Maze"] 			= "2013-05-03",
	["Magic 2014"] 				= "2013-06-13",
	["Theros"] 					= "2013-09-27",
	["Born of the Gods"] 		= "2014-02-07",
	["Journey into Nyx"]		= "2014-05-02",
	["Magic 2015"] 				= "2014-07-18",
	["Khans of Tarkir"] 		= "2014-09-26",
	["Fate Reforged"] 			= "2015-01-23",
	["Dragons of Tarkir"] 		= "2015-03-17",
	["Magic Origins"] 			= "2015-07-15",
	["Battle for Zendikar"] 	= "2015-10-02",
	["Oath of the Gatewatch"] 	= "2016-01-22",
	["Shadows over Innistrad"] 	= "2016-04-08",
	["Eldritch Moon"] 			= "2016-06-22",
	["Kaladesh"] 				= "2016-09-30",
	["Aether Revolt"] 			= "2016-01-20",
	["Amonkhet"] 				= "2017-04-28",
	["Hour of Devastation"] 	= "2017-07-14",
}

local function generateLink(target, displayText)
	if displayText then
		return "[["..target.."|"..displayText.."]]"
	else
		return "[["..target.."]]"
	end
end

local function parseRatings(raw)
	local outputList = {}
	local newestDate, newestRating = 0, 0
	local rating, refDate, refString, t
	gsub(raw, "{(.-)}", function(a)
		rating, refDate, refString = match(a, "(%d+),([%d%-]+),(.+)")
		rating = tonumber(rating)
		
		-- Dates MUST be yyyy-mm-dd
		t = os.time({year=sub(refDate, 1,4), month=sub(refDate, 6,7), day=sub(refDate, 9,10),})
		if t > newestDate then
			newestDate = t
			newestRating = rating
		end
		
		table.insert(outputList, {text = rating..refString, t = t})
	end)
	
	return newestRating, outputList
end

local function addPrintings(timeline, printings)
	local releaseDate, t
	-- Comma-separated list
	gsub(printings, "([^,]+)", function(set)
		releaseDate = LEGAL_EXPANSIONS[set]
		
		-- The set name provided doesn't match a post-Storm Scale set
		if not releaseDate then return end
		
		-- Dates MUST be yyyy-mm-dd
		t = os.time({year=sub(releaseDate, 1,4), month=sub(releaseDate, 6,7), day=sub(releaseDate, 9,10),})
		
		table.insert(timeline, {text = generateLink(set), t = t})
	end)
	
	return timeline
end

local function sortHistory(events)
	-- Sort all events into chronological order
	table.sort(events, function(a,b) return a.t < b.t end)
	return events
end

	
function MaroScale.TableBuilder(frame)
	local args = frame:getParent().args -- coming from one layer up
	
	-- Imitating navbox, here. I trust they know what they're doing.
	-- Read the arguments in the order they'll be output in, to make references number in the right order.
    local _
    _ = args.type
    _ = args.above
    for i = 1, 200 do
        _ = args["name" .. tostring(i)]
        _ = args["entry" .. tostring(i)]
        _ = args["ratings" .. tostring(i)]
    end
	
	-- Seriously this loop is entirely too clever
	local listnums = {}
	for k, v in pairs(args) do
		local listnum = match('' .. k, '^ratings(%d+)$')
		if listnum then table.insert(listnums, tonumber(listnum)) end
	end
	table.sort(listnums)

	
	-- Build the table header row
	local type = args.type
	local tbl = mw.html.create("table"):addClass("wikitable"):addClass("sortable")
	tbl:tag("tr")
		:tag("th"):wikitext(type):done()
		:tag("th"):wikitext("Latest ranking"):done()
		:tag("th"):addClass("unsortable"):wikitext("Timeline"):done() -- Last column can't be sorted
	
	-- Reusable loop vars for performance
	local name, entry, ratings, printings
	local linkedEntry, lastRating, timeline
	local row, cellText
	for i, listnum in ipairs(listnums) do
		-- Retrieve the relevant args for this row
		name, entry, ratings, printings = args["name"..listnum], args["entry"..listnum], args["ratings"..listnum], args["printings"..listnum]
		
		-- Create a wikilink for the entry, using name as the target article if provided
		linkedEntry = generateLink(entry, name)
		
		-- Decode the ratings into a table
		lastRating, timeline = parseRatings(ratings)
		-- Add any printings
		timeline = addPrintings(timeline, printings)
		-- Sort chronologically
		timeline = sortTimeline(timeline)
		
		-- Make the row
		row = tbl:tag("tr")
		
		-- First cell
		row:tag("td"):wikitext(linkedEntry)
		
		-- Second cell
		row:tag("td"):wikitext(lastRating)
			
		-- Third cell
		row:tag("td"):tag("ul"):cssText("display:block; margin-top:0; margin-left:0;")
		
		for n, event in pairs(timeline) do
			if n ~= #timeline then
				list:tag("li"):cssText("display:inline-block;"):wikitext(event.text .. ",&nbsp;")
			else
				list:tag("li"):cssText("display:inline-block;"):wikitext(event.text)
			end
		end
	end
	return tbl
end

return MaroScale