Module:Release

local p = {} local h = {}

local utilsArg = require("Module:UtilsArg") local utilsCargo = require("Module:UtilsCargo") local utilsMarkup = require("Module:UtilsMarkup") local utilsRegion = require("Module:UtilsRegion") local utilsString = require("Module:UtilsString") local utilsTable = require("Module:UtilsTable")

local data = mw.loadData("Module:Releases/Data") local regionsByParam = utilsTable.keyBy(data.regions, "param") local systemsByCode = utilsTable.keyBy(data.Games.systems, "code") local systemCodes = utilsTable.map(data.Games.systems, "code") local TABLES = { Games = "GameReleases" } local FIELDS = { Games = { title = "String", system = "String", service = "String", program = "String", region = "String", date = "Date", reference = "Wikitext", } }

function p.CargoDeclare(frame) local medium = frame.args[1] return utilsCargo.declare(TABLES[medium], FIELDS[medium]) end

function p.CargoStore(frame) local medium = frame.args[1] local args, err = h.evaluateArgs(medium, frame:getParent.args) if err then return utilsMarkup.categories(err) end local rows = {} for _, regionDate in ipairs(args.regionDates) do		local row = utilsTable.merge({}, args, regionDate) row.regionDates = nil row.regions = nil utilsCargo.store(TABLES[medium], row) table.insert(rows, row) end return h.printReleases(medium, rows) end

function p.Releases(frame) return p.printReleases(frame.args[1], frame:getParent.args[1]) end

function p.printReleases(medium, title) local releases = h.fetchReleases(medium, title) local result = h.printReleases(medium, releases) return result end

function h.evaluateArgs(medium, frameArgs) frameArgs = utilsTable.mapValues(frameArgs, utilsString.trim) frameArgs = utilsTable.mapValues(frameArgs, utilsString.nilIfEmpty) local regions = utilsTable.filter(utilsTable.stringKeys(frameArgs), function(arg)		return not utilsString.endsWith(arg, "R")	end) local regionDates = utilsTable.map(regions, function(region)		return {			region = regionsByParam[region].code,			date = frameArgs[region],			reference= frameArgs[region .. "R"],		}	end) local mediumArgs, mediumValidators = h.argEvaluators[medium](frameArgs) local args = utilsTable.merge(mediumArgs, {		regions = regions,		regionDates = regionDates	}) local validators = utilsTable.merge(mediumValidators, {		regions = {			enum = utilsTable.map(data.regions, "param")		}	}) local err = utilsArg.validate(args, validators) return args, err end

function h.fetchReleases(medium, title) local tbl = TABLES[medium] local fields = utilsTable.keys(FIELDS[medium]) local query = { where = utilsCargo.allOf({ title = title }) }	local queryResults = utilsCargo.query(tbl, table.concat(fields, ","), query) return queryResults end

function h.evaluateReleases(medium, releases) local releasesByName = utilsTable.groupBy(releases, h.labelers[medium]) local sortedReleasesByName = {} for k, v in pairs(releasesByName) do		local sortedIndex = h.sorters[medium](v[1]) sortedReleasesByName[sortedIndex] = { name = k,			regionDates = v		} end return utilsTable.compact(sortedReleasesByName) end

function h.printReleases(medium, releases) releases = h.evaluateReleases(medium, releases) for i, release in ipairs(releases) do		local dates = {} local regionDates = utilsTable.keyBy(release.regionDates, "region") for _, region in ipairs(data.regions) do			local regionCode = regionsByParam[region.param].code local regionDate = regionDates[regionCode] if regionDate then local formattedDate = mw.language.getContentLanguage:formatDate("M d, Y", regionDate.date) local date = utilsRegion.flag(regionCode) .. " " .. formattedDate if not utilsString.isEmpty(regionDate.reference) then date = date .. mw.getCurrentFrame:extensionTag("ref", regionDate.reference) end table.insert(dates, date) end end releases[i] = utilsTable.concat({release.name}, dates) end return utilsMarkup.definitionList(releases, {		class = "releases"	}) end

-- GAMES

function h.gameArgs(frameArgs) local args = { title = frameArgs[1], system = frameArgs[2], service = frameArgs[3], program = frameArgs[4], }	local validators = { title = { nonEmpty = true, },		system = { enum = systemCodes },		service = { enum = utilsTable.keys(data.Games.services[args.system] or {}) },		program = { enum = utilsTable.keys(data.Games.programs[args.system] or {}) },	}	return args, validators end

function h.labelGameRelease(release) local label if not utilsString.isEmpty(release.service) then label = data.Games.services[release.system][release.service].displayName else label = systemsByCode[release.system].name end if not utilsString.isEmpty(release.program) then label = label .. (" (%s)"):format(data.Games.programs[release.system][release.program]) end return label end

function h.sortGameRelease(release) return utilsTable.keyOf(systemCodes, release.system) end

h.argEvaluators = { Games = h.gameArgs, } h.labelers = { Games = h.labelGameRelease, } h.sorters = { Games = h.sortGameRelease, }

return p