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

Revision as of 03:23, 4 December 2019

--[[
{{#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