Difference between revisions of "Module:Sandbox/Chao"

From BlazBlue Wiki
Jump to: navigation, search
m (count images for regular Gallery Sections correctly)
m (test classes)
 
Line 9: Line 9:
 
--]]
 
--]]
  
local p = {}
 
 
local cargo = mw.ext.cargo
 
local cargo = mw.ext.cargo
  
local galleryData = mw.loadData('Module:Sandbox/Chao/data')
+
-------------------------------------
local ordering = galleryData.ordering
+
-- Gallery Section Class
local sections = galleryData.sections
+
-------------------------------------
 +
 
 +
local GalleryTemplate = {}
 +
GalleryTemplate.__index = GalleryTemplate
 +
 
 +
GalleryTemplate.fields = {
 +
character = true,
 +
source = true,
 +
section = true,
 +
limit = true,
 +
widths = true,
 +
header = true,
 +
title = true,
 +
sort = true,
 +
see_all = true,
 +
see_cameos = true,
 +
--Gallery Section (BBRadio)
 +
season = true,
 +
episode = true,
 +
widths = true,
 +
--Gallery Section
 +
cat = true,
 +
cat2 = true,
 +
--Misc/Shared
 +
count_all = true,
 +
count_cameos = true,
 +
images_in_section = true,
 +
}
  
function p.render(frame)
+
GalleryTemplate.templateMethods = {
text = {}
+
['Gallery Section (Cargo)'] = 'makeGallerySectionCargo',
_char = frame.args['character'] or ''
+
['Gallery Section (BBRadio)'] = 'makeGallerySectionBBRadio',
+
['Gallery Section'] = 'makeGallerySection',
for i,v in ipairs (ordering) do
+
}
category = v
 
params = sections[v] or ''
 
  
if params == '' then
+
function GalleryTemplate.new(frame, templateType, params)
else
+
local self = setmetatable({}, GalleryTemplate)
t_section = {}
+
self.images_in_section = 0
t_galleries = {}
+
self.templateType= templateType
images_in_section = 0
+
self.frame = frame
current_subheader = ''
+
for field in pairs(GalleryTemplate.fields) do
+
self[field] = params[field] or ''
-- add a wrapper div if there's a class to apply to the section
+
end
class = params.class or ''
+
return self
if class ~= '' then
+
end
table.insert(t_section, '<div class="' .. class .. '">')
 
end
 
 
-- v is a table of templates in this section
 
for k2,v2 in pairs (params) do
 
 
template = v2.template or ''
 
params = {}
 
 
--fill in any missing template arguments
 
--Gallery Section (Cargo)
 
params.character = _char
 
params.source = v2.source or ''
 
params.section = v2.section or ''
 
params.limit = v2.limit or ''
 
params.widths = v2.widths or ''
 
params.header = v2.header or ''
 
params.title = v2.title or ''
 
params.sort = v2.sort or ''
 
params.see_all = v2.see_all or ''
 
params.see_cameos = v2.see_cameos or ''
 
--Gallery Section (BBRadio)
 
params.season = v2.season or ''
 
params.episode = v2.episode or ''
 
params.widths = v2.widths or ''
 
--Gallery Section
 
params.cat = v2.category or ''
 
params.cat2 = v2.category2 or ''
 
 
if template == 'Gallery Section (Cargo)' then
 
params.character = cargo_escape(params.character)
 
  
params.count_all = p._countImages_GallerySectionCargo(params, false) or 0
+
function GalleryTemplate:__tostring()
params.count_cameos = p._countImages_GallerySectionCargo(params, true) or 0
+
local method = GalleryTemplate.templateMethods[self.templateType]
total_images = params.count_all + params.count_cameos
+
if method then
+
mw.log("GalleryTemplate:__toString(" .. method .. ")")
if params.count_all > 0 then
+
--return self[method](self, self.frame)
params.see_all = 'y'
+
end
end
+
return ''
+
end
if params.count_cameos > 0 then
 
params.see_cameos = 'y'
 
end
 
 
if total_images > 0 then
 
expanded_template = p._expandTemplate_GallerySectionCargo(frame, params)
 
table.insert(t_galleries, expanded_template)
 
images_in_section = images_in_section + total_images
 
end
 
elseif template == 'Gallery Section (BBRadio)' then
 
params.character = cargo_escape(params.character)
 
params.count_all = p._countImages_GallerySectionBBRadio(params) or 0
 
expanded_template = p._expandTemplate_GallerySectionBBRadio(frame, params)
 
table.insert(t_galleries, expanded_template)
 
images_in_section = images_in_section + params.count_all
 
elseif template == 'Gallery Section' then
 
params.count_all = p._countImages_GallerySection(params) or 0
 
expanded_template = p._expandTemplate_GallerySection(frame, params)
 
table.insert(t_galleries, expanded_template)
 
images_in_section = images_in_section + params.count_all
 
elseif template == 'Header' then
 
-- if this is not the first subheader in this section
 
if current_subheader ~= '' then
 
-- check if the previous subheader's galleries had images in them
 
if images_in_section > 0 then
 
-- insert the previous subheader into the section
 
table.insert(t_section, current_subheader)
 
 
-- insert the previous subheader's galleries into the section
 
g = table.concat(t_galleries)
 
if g ~= "" then
 
table.insert(t_section, g)
 
end
 
 
-- reset galleries and images for the next subsection
 
clear_table(t_galleries)
 
images_in_section = 0
 
end
 
end
 
-- save the new subheader and wait to see if the following galleries have any images in them
 
current_subheader = '<' .. params.header .. '>' .. params.title .. '</' .. params.header .. ">\n"
 
end
 
end
 
  
-- check the number of images in the section
+
function GalleryTemplate.makeGallerySectionCargo(frame)
mw.log(category .. " images_in_section = " .. images_in_section)
+
self.character = cargo_escape(self.character)
 
-- if there is a subheader to insert, then insert it
 
if current_subheader ~= "" and images_in_section > 0 then
 
table.insert(t_section, current_subheader)
 
end
 
 
-- if there are galleries to insert, then insert them
 
g = table.concat(t_galleries)
 
if g ~= "" then
 
table.insert(t_section, g)
 
else
 
mw.log("t_galleries is empty, with " .. images_in_section .. " images total in this section")
 
end
 
  
-- close the wrapping div if one was added
+
self.count_all = Gallery._countImages_GallerySectionCargo(false) or 0
if class ~= "" then
+
self.count_cameos = Gallery._countImages_GallerySectionCargo(true) or 0
table.insert(t_section, "</div>")
+
local total_images = self.count_all + self.count_cameos
end
+
+
if self.count_all > 0 then
s = table.concat(t_section)
+
self.see_all = 'y'
if s ~= "" then
+
end
-- insert the section, prepended by the section header, to the final text
+
table.insert(text, '<h2>' .. category .. '</h2>\n' .. s)
+
if self.count_cameos > 0 then
end
+
self.see_cameos = 'y'
end
+
end
 +
 +
if total_images > 0 then
 +
expanded_template = Gallery._expandTemplate_GallerySectionCargo(frame)
 +
--table.insert(t_galleries, expanded_template)
 +
self.images_in_section = self.images_in_section + total_images
 
end
 
end
 
 
gallery = table.concat(text)
+
return expanded_template
return gallery
+
end
 +
 
 +
function GalleryTemplate.makeGallerySectionBBRadio(frame)
 +
self.character = cargo_escape(self.character)
 +
self.count_all = Gallery._countImages_GallerySectionBBRadio() or 0
 +
expanded_template = Gallery._expandTemplate_GallerySectionBBRadio(frame)
 +
--table.insert(t_galleries, expanded_template)
 +
self.images_in_section = self.images_in_section + self.count_all
 +
return expanded_template
 +
end
 +
 
 +
function GalleryTemplate.makeGallerySection(frame)
 +
self.count_all = Gallery._countImages_GallerySection() or 0
 +
expanded_template = Gallery._expandTemplate_GallerySection(frame)
 +
--table.insert(t_galleries, expanded_template)
 +
self.images_in_section = self.images_in_section + self.count_all
 +
return expanded_template
 
end
 
end
  
 
-- counts the number of images with this character (or cameo) for sections using Template:Gallery Section (Cargo)
 
-- counts the number of images with this character (or cameo) for sections using Template:Gallery Section (Cargo)
 
-- countCameos: boolean
 
-- countCameos: boolean
function p._countImages_GallerySectionCargo(params, countCameos)
+
function GalleryTemplate._countImages_GallerySectionCargo(countCameos)
 
tables = 'Files'
 
tables = 'Files'
 
fields = 'COUNT(Files._pageName)'
 
fields = 'COUNT(Files._pageName)'
  
character = params.character or ''
+
character = self.character or ''
source = params.source or ''
+
source = self.source or ''
section = params.section or ''
+
section = self.section or ''
  
 
where_clause_parts = {}
 
where_clause_parts = {}
Line 182: Line 140:
 
end
 
end
  
function p._countImages_GallerySectionBBRadio(params)
+
function GalleryTemplate._countImages_GallerySectionBBRadio()
 
tables = 'Files,BBRadio_Cuts'
 
tables = 'Files,BBRadio_Cuts'
 
fields = 'COUNT(Files._pageName)'
 
fields = 'COUNT(Files._pageName)'
 
join_on = 'Files._pageName=BBRadio_Cuts._pageName'
 
join_on = 'Files._pageName=BBRadio_Cuts._pageName'
 
_character = params.character or ''
 
_season = params.season or ''
 
 
 
mw.log(_character)
+
mw.log("Count images for " .. self.character .. ' season ' .. self.season)
mw.log(_season)
 
  
where_clause = 'Files.Characters HOLDS "' .. _character .. '" AND BBRadio_Cuts.Season="' .. _season .. '"'
+
where_clause = 'Files.Characters HOLDS "' .. self.character .. '" AND BBRadio_Cuts.Season="' .. self.season .. '"'
  
 
local args = {
 
local args = {
Line 206: Line 160:
 
end
 
end
  
function p._countImages_GallerySection(params)
+
function GalleryTemplate._countImages_GallerySection()
+
cat1 = self.character or ''
cat1 = params.character or ''
+
cat2 = self.cat or ''
cat2 = params.cat or ''
+
cat3 = self.cat2 or ''
cat3 = params.cat2 or ''
 
  
 
local query = {}
 
local query = {}
Line 221: Line 174:
  
 
return count
 
return count
 
 
end
 
end
  
function p._expandTemplate_GallerySectionCargo(frame, params)
+
function GalleryTemplate._expandTemplate_GallerySectionCargo(frame)
_character = params.character or ''
+
_limit = tonumber(self.limit) or 4
_source = params.source or ''
+
 
_section = params.section or ''
+
if frame[expandTemplate] == nil then
_limit = tonumber(params.limit) or 4
+
mw.log("NIL FRAME: _expandTemplate_GallerySectionCargo " .. self.title .. " could not be executed")
_title = params.title or ''
+
return ''
_header = params.header or ''
+
end
_see_all = params.see_all or ''
+
 
_see_cameos = params.see_cameos or ''
 
_count_all = params.count_all or ''
 
_count_cameos = params.count_cameos or ''
 
 
 
gallery = frame:expandTemplate{ title = 'Gallery Section (Cargo)', args = {  
 
gallery = frame:expandTemplate{ title = 'Gallery Section (Cargo)', args = {  
character = _character,
+
character = self.character,
source = _source,
+
source = self.source,
section = _section,
+
section = self.section,
 
limit = _limit,
 
limit = _limit,
title = _title,
+
title = self.title,
header = _header,
+
header = self.header,
see_all = _see_all,
+
see_all = self.see_all,
see_cameos = _see_cameos,
+
see_cameos = self.see_cameos,
count_all = _count_all,
+
count_all = self.count_all,
count_cameos = _count_cameos
+
count_cameos = self.count_cameos
 
}}
 
}}
  
Line 252: Line 200:
 
end
 
end
  
function p._expandTemplate_GallerySectionBBRadio(frame, params)
+
function GalleryTemplate._expandTemplate_GallerySectionBBRadio(frame)
_character = params.character or ''
+
_limit = tonumber(self.limit) or 4
_season = params.season or ''
+
_widths = tonumber(self.widths) or 250
_episode = params.episode or ''
+
 
_header = params.header or ''
+
if frame[expandTemplate] == nil then
_title = params.title or ''
+
mw.log("NIL FRAME: _expandTemplate_GallerySectionBBRadio " .. self.title .. " could not be executed")
_limit = tonumber(params.limit) or 4
+
return ''
_widths = tonumber(params.widths) or 250
+
end
_count_all = params.count_all or ''
 
  
 
gallery = frame:expandTemplate { title = 'Gallery Section (BBRadio)', args = {
 
gallery = frame:expandTemplate { title = 'Gallery Section (BBRadio)', args = {
_character,
+
self.character,
_season,
+
self.season,
_episode,
+
self.episode,
_header,
+
self.header,
_title,
+
self.title,
 
widths = _widths,
 
widths = _widths,
 
limit = _limit,
 
limit = _limit,
count_all = _count_all
+
count_all = self.count_all
 
}}
 
}}
  
Line 276: Line 223:
 
end
 
end
  
function p._expandTemplate_GallerySection(frame, params)
+
function GalleryTemplate._expandTemplate_GallerySection(frame)
_character = params.character or ''
+
_limit = tonumber(self.limit) or 4
_cat = params.cat or ''
+
_widths = tonumber(self.widths) or 250
_cat2 = params.cat2 or ''
+
_count_all = self.count_all or 0
_header = params.header or ''
+
 
_title = params.title or ''
+
if frame[expandTemplate] == nil then
_limit = tonumber(params.limit) or 4
+
mw.log("NIL FRAME: _expandTemplate_GallerySection " .. _title .. " could not be executed")
_widths = tonumber(params.widths) or 250
+
return ''
_count_all = params.count_all or 0
+
end
  
 
gallery = frame:expandTemplate { title = 'Gallery Section', args = {
 
gallery = frame:expandTemplate { title = 'Gallery Section', args = {
_character,
+
self.character,
_cat,
+
self.cat,
_cat2,
+
self.cat2,
_header,
+
self.header,
_title,
+
self.title,
 
widths = _widths,
 
widths = _widths,
 
limit = _limit,
 
limit = _limit,
Line 299: Line 246:
 
return gallery
 
return gallery
 
end
 
end
 +
 +
function GalleryTemplate:getNumberOfImages()
 +
return self.images_in_section
 +
end
 +
 +
-------------------------------------
 +
-- Gallery Class
 +
-------------------------------------
 +
 +
local Gallery = {}
 +
Gallery.__index = Gallery
 +
 +
function Gallery.new(data, frame)
 +
local self = setmetatable({}, Gallery)
 +
self.galleryData = mw.loadData(data)
 +
self.ordering = self.galleryData.ordering
 +
self.sections = self.galleryData.sections
 +
self.frame = frame
 +
return self
 +
end
 +
 +
function Gallery:__tostring()
 +
local frame = self.frame
 +
text = {}
 +
_char = frame.args['character'] or ''
 +
 +
for i,v in ipairs (self.ordering) do
 +
category = v
 +
local params = self.sections[v] or ''
 +
 +
if params == '' then
 +
else
 +
local t_section = {}
 +
local t_galleries = {}
 +
local images_in_section = 0
 +
local current_subheader = ''
 +
 +
-- add a wrapper div if there's a class to apply to the section
 +
class = params.class or ''
 +
if class ~= '' then
 +
table.insert(t_section, '<div class="' .. class .. '">')
 +
end
 +
 +
-- v is a table of templates in this section
 +
for k2,v2 in pairs(params) do
 +
template = v2.template or ''
 +
 +
local title = params.title or 'TITLE PLACEHOLDER'
 +
mw.log(title .. ": " .. template)
 +
 +
if template == 'Header' then
 +
-- if this is not the first subheader in this section
 +
if current_subheader ~= '' then
 +
-- check if the previous subheader's galleries had images in them
 +
if images_in_section > 0 then
 +
-- insert the previous subheader into the section
 +
table.insert(t_section, current_subheader)
 +
-- insert the previous subheader's galleries into the section
 +
g = table.concat(t_galleries)
 +
if g ~= "" then
 +
table.insert(t_section, g)
 +
end
 +
-- reset galleries and images for the next subsection
 +
clear_table(t_galleries)
 +
images_in_section = 0
 +
end
 +
end
 +
-- TODO fix placeholder text
 +
local header = params.header or 'HEADER PLACEHOLDER'
 +
-- save the new subheader and wait to see if the following galleries have any images in them
 +
current_subheader = '<' .. header .. '>' .. title .. '</' .. header .. ">\n"
 +
elseif template ~=  '' then
 +
images_in_section = images_in_section
 +
temp = GalleryTemplate.new(frame, template, params)
 +
table.insert(t_galleries, tostring(temp))
 +
images_in_section = tonumber(temp:getNumberOfImages()) or 0
 +
end
 +
end
 +
 +
-- check the number of images in the section
 +
mw.log(category .. " images_in_section = " .. images_in_section)
 +
 +
-- if there is a subheader to insert, then insert it
 +
if current_subheader ~= "" and images_in_section > 0 then
 +
table.insert(t_section, current_subheader)
 +
end
 +
 +
-- if there are galleries to insert, then insert them
 +
g = table.concat(t_galleries)
 +
if g ~= "" then
 +
table.insert(t_section, g)
 +
else
 +
mw.log("t_galleries is empty, with " .. images_in_section .. " images total in this section")
 +
end
 +
 +
-- close the wrapping div if one was added
 +
if class ~= "" then
 +
table.insert(t_section, "</div>")
 +
end
 +
 +
s = table.concat(t_section)
 +
if s ~= "" then
 +
-- insert the section, prepended by the section header, to the final text
 +
table.insert(text, '<h2>' .. category .. '</h2>\n' .. s)
 +
end
 +
end
 +
end
 +
 +
gallery = table.concat(text)
 +
return gallery
 +
end
 +
 +
-------------------------------------
 +
-- Main
 +
-------------------------------------
 +
local p = {}
 +
 +
function p.main(frame)
 +
data = frame.args.data or 'Module:Sandbox/Chao/data'
 +
gallery = Gallery.new(data, frame)
 +
 +
--mw.log(dump(gallery))
 +
--mw.log("rendered: \n" .. gallery:makeGallery())
 +
return tostring(gallery)
 +
end
 +
 +
-------------------------------------
 +
-- Tests
 +
-------------------------------------
  
 
function p.testExpandTemplate_1(frame)
 
function p.testExpandTemplate_1(frame)
Line 351: Line 427:
 
end
 
end
 
end
 
end
 +
 +
-------------------------------------
 +
-- Utility Functions
 +
-------------------------------------
  
 
-- clear a table
 
-- clear a table

Latest revision as of 03:23, 4 December 2019

Main Visuals

... further results

Character Crest

Chibi

Gameplay

Arcade

BlazBlue: Calamity Trigger

see cameos (6)

BlazBlue: Continuum Shift

see cameos (2)

BlazBlue: Chrono Phantasma

see cameos (10)

BlazBlue: Central Fiction

see all 7
see cameos (13)

Story

Portraits

... further results

Short Stories

BlazBlue: Calamity Trigger

see all 15
see cameos (5)

BlazBlue: Continuum Shift

see all 12
see cameos (4)

BlazBlue: Chrono Phantasma

see all 13

BlazBlue: Central Fiction

see all 11

BlazBlue: Cross Tag Battle

BlazBlue: Clone Phantasma

see cameos (1)

Novels

BlazBlue: Calamity Trigger - Part 1

BlazBlue: Calamity Trigger - Part 2

... further results

BlazBlue: Continuum Shift - Part 1

BlazBlue: Continuum Shift - Part 2

Manga

BlazBlue: Remix Heart

... further results

BlazBlue: Variable Heart

Radio Show

Chibi Portraits

see all 51

Blazblue Radio

see all 117

Blazblue Radio Continued

see all 151

Blazblue Radio Wide

see all 130

Blazblue Radio Hyper

see all 70

Blazblue Radio Ace

see all 57

Blazblue Radio Quick

see all 51

Blazblue Radio Dynamic

see all 42

Blazblue Radio NEO

see all 30

Blazblue Radio Repeat

see all 5

Blazblue Radio Repeat 2

see all 1

Artwork

Staff Extras

... further results

Pre-order Bonuses

... further results

Wallpapers

... further results

Stickers

... further results

Production Art

Model Sheets

... further results

Early Designs

Storyboards

... further results

Collaborations

Destiny Child

... further results

Girls' Frontline

... further results

Lord of Vermilion Re:2

... further results

Mabinogi Duel

Unlimited VS

... further results
--[[
{{#invoke:Sandbox/Chao|GallerySection|character=Noel Vermillion|section=Portraits}}
simulate passing a frame to the function in the console with:
myFrame = { args = { character='Noel Vermillion', section='Portraits' } }
=p.GallerySection ( myFrame )
=p.testExpandTemplate( myFrame )
=p.render(myFrame)

--]]

local cargo = mw.ext.cargo

-------------------------------------
-- Gallery Section Class
-------------------------------------

local GalleryTemplate = {}
GalleryTemplate.__index = GalleryTemplate

GalleryTemplate.fields = {
	character = true,
	source = true,
	section = true,
	limit = true,
	widths = true,
	header = true,
	title = true,
	sort = true,
	see_all = true,
	see_cameos = true,
	--Gallery Section (BBRadio)
	season = true,
	episode = true,
	widths = true,
	--Gallery Section
	cat = true,
	cat2 = true,
	--Misc/Shared
	count_all = true,
	count_cameos = true,
	images_in_section = true,
}

GalleryTemplate.templateMethods = {
	['Gallery Section (Cargo)'] = 'makeGallerySectionCargo',
	['Gallery Section (BBRadio)'] = 'makeGallerySectionBBRadio',
	['Gallery Section'] = 'makeGallerySection',
}

function GalleryTemplate.new(frame, templateType, params)
	local self = setmetatable({}, GalleryTemplate)
	self.images_in_section = 0
	self.templateType= templateType
	self.frame = frame
	for field in pairs(GalleryTemplate.fields) do
		self[field] = params[field] or ''
	end
	return self
end

function GalleryTemplate:__tostring()
	local method = GalleryTemplate.templateMethods[self.templateType]
	if method then
		mw.log("GalleryTemplate:__toString(" .. method .. ")")
		--return self[method](self, self.frame)
	end
	return ''
end

function GalleryTemplate.makeGallerySectionCargo(frame)
	self.character = cargo_escape(self.character)

	self.count_all = Gallery._countImages_GallerySectionCargo(false) or 0
	self.count_cameos = Gallery._countImages_GallerySectionCargo(true) or 0
	local total_images = self.count_all + self.count_cameos
	
	if self.count_all > 0 then
		self.see_all = 'y'
	end
	
	if self.count_cameos > 0 then
		self.see_cameos = 'y'
	end
	
	if total_images > 0 then
		expanded_template = Gallery._expandTemplate_GallerySectionCargo(frame)
		--table.insert(t_galleries, expanded_template)
		self.images_in_section = self.images_in_section + total_images
	end
	
	return expanded_template
end

function GalleryTemplate.makeGallerySectionBBRadio(frame)
	self.character = cargo_escape(self.character)
	self.count_all = Gallery._countImages_GallerySectionBBRadio() or 0
	expanded_template = Gallery._expandTemplate_GallerySectionBBRadio(frame)
	--table.insert(t_galleries, expanded_template)
	self.images_in_section = self.images_in_section + self.count_all
	return expanded_template
end

function GalleryTemplate.makeGallerySection(frame)
	self.count_all = Gallery._countImages_GallerySection() or 0
	expanded_template = Gallery._expandTemplate_GallerySection(frame)
	--table.insert(t_galleries, expanded_template)
	self.images_in_section = self.images_in_section + self.count_all
	return expanded_template
end

-- counts the number of images with this character (or cameo) for sections using Template:Gallery Section (Cargo)
-- countCameos: boolean
function GalleryTemplate._countImages_GallerySectionCargo(countCameos)
	tables = 'Files'
	fields = 'COUNT(Files._pageName)'

	character = self.character or ''
	source = self.source or ''
	section = self.section or ''

	where_clause_parts = {}
	if countCameos then
		table.insert(where_clause_parts, "Files.Cameos HOLDS '" .. character .. "'")
	else
		table.insert(where_clause_parts, "Files.Characters HOLDS '" .. character .. "'")
	end
	
	if source == '' then else table.insert(where_clause_parts, "Files.Source HOLDS '" .. source .. "'")	end
	if section == '' then else table.insert(where_clause_parts, "Files.Gallery_Sections HOLDS '" .. section .. "'")	end
	where_clause = concatvalues(where_clause_parts, " AND ")

	local args = {
		where = where_clause
	}

	result = cargo.query( tables, fields, args )
	count = result[1][fields] or '0'

	return tonumber(count)
end

function GalleryTemplate._countImages_GallerySectionBBRadio()
	tables = 'Files,BBRadio_Cuts'
	fields = 'COUNT(Files._pageName)'
	join_on = 'Files._pageName=BBRadio_Cuts._pageName'
	
	mw.log("Count images for " .. self.character .. ' season ' .. self.season)

	where_clause = 'Files.Characters HOLDS "' .. self.character .. '" AND BBRadio_Cuts.Season="' .. self.season .. '"'

	local args = {
		where = where_clause,
		join = join_on
	}

	result = cargo.query( tables, fields, args )
	count = result[1][fields] or '0'

	return tonumber(count)
end

function GalleryTemplate._countImages_GallerySection()
	cat1 = self.character or ''
	cat2 = self.cat or ''
	cat3 = self.cat2 or ''

	local query = {}
	if cat1 ~= '' then table.insert(query, '[[Category:' .. cat1 .. ']]') end
	if cat2 ~= '' then table.insert(query, '[[Category:' .. cat2 .. ']]') end
	if cat3 ~= '' then table.insert(query, '[[Category:' .. cat3 .. ']]') end
	
	local result = mw.smw.getQueryResult( query )
	count = result.meta.count or 0

	return count
end

function GalleryTemplate._expandTemplate_GallerySectionCargo(frame)
	_limit = tonumber(self.limit) or 4

	if frame[expandTemplate] == nil then
		mw.log("NIL FRAME: _expandTemplate_GallerySectionCargo " .. self.title .. " could not be executed")
		return ''
	end

	gallery = frame:expandTemplate{ title = 'Gallery Section (Cargo)', args = { 
		character = self.character,
		source = self.source,
		section = self.section,
		limit = _limit,
		title = self.title,
		header = self.header,
		see_all = self.see_all,
		see_cameos = self.see_cameos,
		count_all = self.count_all,
		count_cameos = self.count_cameos
	}}

	return gallery
end

function GalleryTemplate._expandTemplate_GallerySectionBBRadio(frame)
	_limit = tonumber(self.limit) or 4
	_widths = tonumber(self.widths) or 250

	if frame[expandTemplate] == nil then
		mw.log("NIL FRAME: _expandTemplate_GallerySectionBBRadio " .. self.title .. " could not be executed")
		return ''
	end

	gallery = frame:expandTemplate { title = 'Gallery Section (BBRadio)', args = {
		self.character,
		self.season,
		self.episode,
		self.header,
		self.title,
		widths = _widths,
		limit = _limit,
		count_all = self.count_all
	}}

	return gallery
end

function GalleryTemplate._expandTemplate_GallerySection(frame)
	_limit = tonumber(self.limit) or 4
	_widths = tonumber(self.widths) or 250
	_count_all = self.count_all or 0

	if frame[expandTemplate] == nil then
		mw.log("NIL FRAME: _expandTemplate_GallerySection " .. _title .. " could not be executed")
		return ''
	end

	gallery = frame:expandTemplate { title = 'Gallery Section', args = {
		self.character,
		self.cat,
		self.cat2,
		self.header,
		self.title,
		widths = _widths,
		limit = _limit,
		count_all = _count_all,
	}}

	return gallery
end

function GalleryTemplate:getNumberOfImages()
	return self.images_in_section
end

-------------------------------------
-- Gallery Class
-------------------------------------

local Gallery = {}
Gallery.__index = Gallery

function Gallery.new(data, frame)
	local self = setmetatable({}, Gallery)
	self.galleryData = mw.loadData(data)
	self.ordering = self.galleryData.ordering
	self.sections = self.galleryData.sections
	self.frame = frame
	return self
end

function Gallery:__tostring()
	local frame = self.frame
	text = {}
	_char = frame.args['character'] or ''
	
	for i,v in ipairs (self.ordering) do
		category = v
		local params = self.sections[v] or ''
		
		if params == '' then
		else
			local t_section = {}
			local t_galleries = {}
			local images_in_section = 0
			local current_subheader = ''
			
			-- add a wrapper div if there's a class to apply to the section
			class = params.class or ''
			if class ~= '' then
				table.insert(t_section, '<div class="' .. class .. '">')
			end

			-- v is a table of templates in this section
			for k2,v2 in pairs(params) do
				template = v2.template or ''

				local title = params.title or 'TITLE PLACEHOLDER'
				mw.log(title .. ": " .. template)

				if template == 'Header' then
					-- if this is not the first subheader in this section
					if current_subheader ~= '' then
						-- check if the previous subheader's galleries had images in them
						if images_in_section > 0 then
							-- insert the previous subheader into the section
							table.insert(t_section, current_subheader)
							-- insert the previous subheader's galleries into the section
							g = table.concat(t_galleries)
							if g ~= "" then
								table.insert(t_section, g)
							end
							-- reset galleries and images for the next subsection
							clear_table(t_galleries)
							images_in_section = 0
						end
					end
					-- TODO fix placeholder text
					local header = params.header or 'HEADER PLACEHOLDER'
					-- save the new subheader and wait to see if the following galleries have any images in them
					current_subheader = '<' .. header .. '>' .. title .. '</' .. header .. ">\n"
				elseif template ~=  '' then
					images_in_section = images_in_section
					temp = GalleryTemplate.new(frame, template, params)
					table.insert(t_galleries, tostring(temp))
					images_in_section = tonumber(temp:getNumberOfImages()) or 0
				end
			end

			-- check the number of images in the section
			mw.log(category .. " images_in_section = " .. images_in_section)
			
			-- if there is a subheader to insert, then insert it
			if current_subheader ~= "" and images_in_section > 0 then
				table.insert(t_section, current_subheader)
			end
			
			-- if there are galleries to insert, then insert them
			g = table.concat(t_galleries)
			if g ~= "" then
				table.insert(t_section, g)
			else
				mw.log("t_galleries is empty, with " .. images_in_section .. " images total in this section")
			end

			-- close the wrapping div if one was added
			if class ~= "" then
				table.insert(t_section, "</div>")
			end
			
			s = table.concat(t_section)
			if s ~= "" then
				-- insert the section, prepended by the section header, to the final text
				table.insert(text, '<h2>' .. category .. '</h2>\n' .. s)
			end
		end
	end
	
	gallery = table.concat(text)
	return gallery
end

-------------------------------------
-- Main
-------------------------------------
local p = {}

function p.main(frame)
	data = frame.args.data or 'Module:Sandbox/Chao/data'
	gallery = Gallery.new(data, frame)

	--mw.log(dump(gallery))
	--mw.log("rendered: \n" .. gallery:makeGallery())
	return tostring(gallery)
end

-------------------------------------
-- Tests
-------------------------------------

function p.testExpandTemplate_1(frame)
	
	v = {
		character = 'Noel Vermillion',
		source = 'BlazBlue: Central Fiction', 
		section = '', 
		limit = 8, 
		title = 'title', 
		header = 'h3', 
		see_all = 'y', 
		see_cameos = 'y', 
		count_all = '7'
	}
	text = p._expandTemplate_GallerySectionCargo(frame, v)
	
	return text
end

function p.testExpandTemplate_2(frame)
	
	v = {
		character = 'Noel Vermillion',
		season = 'NEO', 
		limit = 8, 
		title = 'title', 
		header = 'h3', 
		see_all = 'y', 
		count_all = '7',
	}
	text = p._expandTemplate_GallerySectionBBRadio(frame, v)
	
	return text
end

function p.testOrdering()
	for i,v in ipairs (ordering) do
		section = v
		k = sections[v] or ''

		mw.log('\n' .. i .. ': ' .. section)
		if k == '' then
			mw.log('no parameters found')
		else
			mw.log(k.class)
			for k2,v2 in pairs (k) do
				mw.log(k2)
			end
		end
		
	end
end

-------------------------------------
-- Utility Functions
-------------------------------------

-- clear a table
function clear_table(t)
	for k in pairs (t) do
    	t [k] = nil
	end
end

-- concat all the strings in table s together with the given delimiter
function concatvalues(s,delimiter)
    local t = { }
    for k,v in ipairs(s) do
        t[#t+1] = tostring(v)
    end
    return table.concat(t,delimiter)
end

-- concat all the strings in table s together with the given delimiter
-- skips blank entries (where value v = "")
function concatvaluesonly(s,delimiter)
    local t = { }
    for k,v in ipairs(s) do
    	if not (v == '') then
    		t[#t+1] = tostring(v)
    	end
    end
    return table.concat(t,delimiter)
end

function cargo_escape(s)
	return (string.gsub(s, "[']", {
		["'"] = "",
		['"'] = "",
	}))
end

function quote_escape(s)
	return (string.gsub(s, "[\"']", {
		["\'"] = "\\'",
		['\"'] = '\\"'
	}))
end

function html_escape(s)
    return (string.gsub(s, "[<>\"'/ ,]", {
        ["<"] = "%3C",
        [">"] = "%3E",
        ['"'] = "%22",
        ["'"] = "%27",
        ["/"] = "%2F",
        [" "] = "+",
        [","] = "%2C"
    }))
end

-- helpful for printing tables
function dump(o)
   if type(o) == 'table' then
      local s = '{ '
      for k,v in pairs(o) do
         if type(k) ~= 'number' then k = '"'..k..'"' end
         s = s .. '['..k..'] = ' .. dump(v) .. ','
      end
      return s .. '} '
   else
      return tostring(o)
   end
end

return p