Module:Happy Homeroom Normal Courses Table

-- TODO: Use a module! local cargo = {} function cargo.query(args) for k, v in ipairs({'tables', 'fields', 'join'}) do		if type(args[v]) == 'table' then args[v] = table.concat(args[v], ',') end end if type(args.where) == 'table' then local t = {} for i, v in pairs(args.where) do			t[#t+1] = '('..v..')' end args.where = table.concat(t, ' AND ') end args.limit = args.limit or 5000 local rows = mw.ext.cargo.query(		args.tables,		args.fields,		args	) for i, row in ipairs(rows) do		for k, v in pairs(row) do			if v == '' then row[k] = nil end end end return rows end

local p = {} local h = {}

local LANG = mw.getContentLanguage

function p.main(frame) -- Note: Join on EntityPage instead of EntityName because ambiguous pages -- like "Round Pillow (Basic)" and "Round Pillow (Brown)" -- have the same EntityName, and Class.FurnReqAll relies on the EntityPage. local rows = cargo.query{ tables = { 'Class=C','Class__FurnReqAll=CFRA','Entities=E', 'Furniture=F1', 'Clothing=F2', },		join = { 'C._ID=CFRA._rowID','CFRA._value=E.EntityPage', 'E.EntityName=F1.Name', 'E.EntityName=F2.Name', },		fields = { 'C._pageName=C_PAGENAME', 'C.Image=C_Image', 'C.Name=C_Name', 'C.Class=C_Class', 'C.NumFurnReq=C_NumFurnReq', 'E.EntityType=EntityType', 'CFRA._position=F_position', 'COALESCE(F1._pageName,F2._pageName)=F_PAGENAME', 'COALESCE(F1.Name, F2.Name)=F_Name', 'COALESCE(F1.Image, F2.Image)=F_Image', 'COALESCE(F1.MaterialCost, F2.MaterialCost)=F_MaterialCost', 'COALESCE(F1.NumBells, F2.NumBells)=F_NumBells', 'COALESCE(F1.CraftTimeSec, F2.CraftTimeSec)=F_CraftTimeSec', 'COALESCE(F1.UnlockReq, F2.UnlockReq)=F_UnlockReq', 'COALESCE(F1.Obtain, F2.Obtain)=F_Obtain', 'SUBSTRING(CONCAT("0", Class), -4, 4)=ClassCourseSortKey', },		where = { 'C.type="Normal"', '(C.Class LIKE "%-%")', },		orderBy = 'ClassCourseSortKey', }	local t1 = {} for i, row in ipairs(rows) do		if row['F_MaterialCost'] then row['F_MaterialCost'] = string.gsub(row['F_MaterialCost'], ' ', ' ') end local classKey = row['C_Class'] t1[classKey] = t1[classKey] or { pagename = row['C_PAGENAME'], image = row['C_Image'], name = row['C_Name'], class = row['C_Class'], sortKey = row['ClassCourseSortKey'], numFurnReq = row['C_NumFurnReq'], furnitures = {}, }		local furnitures = t1[classKey].furnitures local furnitureKey = tonumber(row['F_position']) furnitures[furnitureKey] = furnitures[furnitureKey] or { pagename = row['F_PAGENAME'], name = row['F_Name'] or row['F_PAGENAME'], image = row['F_Image'], materialCost = row['F_MaterialCost'], numBells = row['F_NumBells'], craftTimeSec = row['F_CraftTimeSec'], unlockReq = row['F_UnlockReq'], obtain = row['F_Obtain'], }	end -- Group by courses local courses = {} for k, v in pairs(t1) do		local course_class = mw.text.split(v.class, '-', true) local course = tonumber(course_class[1]) local class = tonumber(course_class[2]) courses[course] = courses[course] or { id = course, classes = {}, }		courses[course].classes[class] = courses[course].classes[class] or v	end -- table.sort(t2, function(a, b) return a.sortKey < b.sortKey end)

local root = mw.html.create

for _, courseData in ipairs(courses) do		h.printCourse(root, courseData) end return tostring(root) end

function h.printCourse(root, courseData) root:tag('h2'):wikitext('Course '..courseData.id) local tbl = root:tag('table'):addClass('wikitable') local headers = { 'Course Name', 'Class', 'On-Point Item', 'Material Cost', 'Bell Cost', 'Craft Time', 'How to Unlock', }	h.printHeaders(tbl, headers) for i, classData in ipairs(courseData.classes) do		h.printClass(tbl, classData) end end

function h.printHeaders(tbl, headers) local tr = tbl:tag('tr') for i, txt in ipairs(headers) do		tr:tag('th'):wikitext(txt) end end

function h.printClass(tbl, data) local rowspan = #data.furnitures for i, furniture in ipairs(data.furnitures) do		local tr = tbl:tag('tr') local td		if i == 1 then local classIcon = string.format(				' %s%s',				data.image,				data.name,				data.pagename,				data.pagename,				data.pagename ~= data.name and '|'..data.name or ''			) tr:css('border-top', '3px solid #c1b695') tr:tag('td') :attr('rowspan', rowspan) :css('text-align', 'center') :css('padding', '0.5em') :wikitext(classIcon) tr:tag('td') :attr('rowspan', rowspan) :attr('data-sort-value', data.sortKey) :css('text-align', 'center') :wikitext(data.class) end local furnitureIcon = string.format(			' %s',			furniture.image or 'Error-image',			furniture.name or '???',			furniture.name or '???'		) tr:tag('td'):wikitext(furnitureIcon) if furniture.materialCost == 'N/A' or not furniture.numBells then tr:tag('td'):attr('colspan', 4):wikitext(furniture.obtain) else tr:tag('td'):wikitext(furniture.materialCost) tr:tag('td'):wikitext(h.bells(furniture.numBells)) tr:tag('td'):wikitext(h.duration(furniture.craftTimeSec) or '-') tr:tag('td'):wikitext(furniture.unlockReq) end end end

function h.bells(n) return ('%s '):format(n) end

function h.duration(seconds) local seconds = tonumber(seconds) if not seconds then return end

local hh = math.floor(seconds / 60 / 60) local mm = math.floor(seconds / 60 % 60) local ss = (seconds % 60)

local t = {} if hh > 0 then t[#t+1] = LANG:plural(hh, '%d hour', '%d hours'):format(hh) end if mm > 0 then t[#t+1] = LANG:plural(mm, '%d minute', '%d minutes'):format(mm) end if hh == 0 and mm == 0 or ss > 0 then t[#t+1] = LANG:plural(ss, '%d second', '%d seconds'):format(ss) end return table.concat(t, ' ') end

return p