Module:Historical populations
--
 -- This template implements {{Historical populations}}
 --
 local p = {}
 local lang = mw.getContentLanguage()
 local Date -- lazy initialization
 
 local function ifexist(page)
     if not page then return false end
     if mw.title.new(page).exists then return true end
     return false
 end
 
 local function isempty( s )
 	return not s or s:match( '^%s*(.-)%s*$' ) == ''
 end
 
 local function splitnumandref( s )
 	s = s:match( '^%s*(.-)%s*$' )
 	local t1 = mw.text.unstrip(s)
         local t2 = s:match( '^([%d][%d,]*)' )
 	if( t1 == t2 ) then
 		local t3 = s:match( '^[%d][%d,]*(.-)$' )
 		return t1, t3
 	else
 		return s, ''
 	end
 end
 
 local function formatnumR(num)
 	return tonumber(lang:parseFormattedNumber(num))
 end
 
 local function formatnum(num)
 	return lang:parseFormattedNumber(num) and lang:formatNum(lang:parseFormattedNumber(num)) or num
 end
 
 -- this function creates an array with the {year, population, percent change}
 local function getpoprow(year, popstr, pyear, ppopstr, linktype, percentages, current_year)
 	local pop, popref = splitnumandref( popstr or '')
 	local ppop, ppopref = splitnumandref( ppopstr or '')
 	local percent = ''
 	local yearnum = formatnumR(mw.ustring.gsub(year or '', '^%s*([%d][%d][%.%d]+).*$', '%1') or '')
 	local pyearnum = formatnumR(mw.ustring.gsub(pyear or '', '^%s*([%d][%d][%.%d]+).*$', '%1') or '')
 	local popnum = formatnumR(pop)
 	local ppopnum = formatnumR(ppop)
 	if( linktype == 'US' or linktype == 'USA' ) then
 		if( (yearnum or 0) &gt;= 1790 and yearnum &lt;= current_year and math.fmod(math.floor(yearnum), 10) == 0) then
 			if( yearnum &lt; current_year ) then
 				year = '[[' .. tostring(yearnum) .. ' United States census|' .. year .. ']]'
   			elseif( ifexist(tostring(yearnum) .. ' United States census') ) then
 				year = '[[' .. tostring(yearnum) .. ' United States census|' .. year .. ']]'
 			end
 		end
 	end
 	if(percentages ~= 'off') then
 		local pstr = '—&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;'
 		if(popnum ~= nil and ppopnum ~= nil and (ppopnum &gt; 0)) then
 			if(percentages == 'pagr') then
 				pstr = mw.ustring.format('%.2f', 100*math.abs(math.pow(popnum/ppopnum,1/(yearnum-pyearnum)) - 1))
 			elseif(percentages == 'monthly') then
 				if Date == nil then Date = require('Module:Date')._Date end
 				local date1 = Date(year)
 				local date2 = Date(pyear)
 				local diff = date1 - date2
 				local months = (diff.age_days/(365.25/12))
 				pstr = mw.ustring.format('%.2f', 100*math.abs(math.pow(popnum/ppopnum,1/months) - 1))
 			else
 				pstr = mw.ustring.format('%.1f', 100*math.abs(popnum/ppopnum - 1))
 			end
 			if( popnum &lt; ppopnum ) then
 				pstr = '−' .. pstr .. '%'
 			else
 				pstr = '+' .. pstr .. '%'
 			end
 		elseif(popnum ~= nil and ppopnum ~= nil and (ppopnum == popnum)) then
 			pstr = mw.ustring.format('%.2f', 0) .. '%'
 		end
 		percent = pstr
 	end
 	-- strip the fractional part of the year, if there is one
 	year = mw.ustring.gsub(year or '', '^%s*([%d][%d][%d]+)%.[%d]*', '%1')
 	
 	return {year, formatnum(pop) .. popref, percent }
 end
 
 -- this function creates an array with table header labels
 local function getheadrow(percentages, popname, yearname, percentname)
 	-- year cell	
 	if(yearname == '') then
 		yearname = 'ஆண்டு'
 	end
 	-- population cell
 	if(popname == '') then
 		popname = '&lt;abbr title=&quot;மக்கள்தொகை&quot;&gt;ம.தொ.&lt;/abbr&gt;'
 	end
 
 	-- percentages cell
 	if( percentages ~= 'off' and percentname == '') then
 		if( percentages == 'pagr' ) then
 			percentname = '&lt;abbr title=&quot;ஆண்டுக்கு வளர்ச்சி விகிதம்&quot;&gt;ஆ. ±%&lt;/abbr&gt;'		
 		elseif( percentages == 'monthly' ) then	
 			percentname = '&lt;abbr title=&quot; மாதம் ஒன்றுக்கு வளர்ச்சி விகிதம்&quot;&gt;மா. ±%&lt;/abbr&gt;'
 		else
 			percentname = '&lt;abbr title=&quot;விழுக்காடு மாற்றம்&quot;&gt;±%&lt;/abbr&gt;'
 		end
 	end
 	return {yearname, popname, percentname}
 end
 
 -- this function builds the json for the population graph
 local function graphjson(data, gwidth, gheight, gtype)
 	local yearcount = #data
 	local graphargs = {
 		['width'] = gwidth,
 		['height'] = gheight,
 		['type'] = gtype or 'line',
 		['yAxisTitle'] = 'மக்கள்தொகை',
 		['yAxisMin'] = 0,
 		['xAxisTitle'] = 'ஆண்டு',
 		['xAxisAngle'] = '-45',
 		['yGrid'] = 'y',
 		['yAxisFormat'] = ',d',
 		['x'] = '',
 		['y'] = ''
 	}
 	local firstpoint = true
 	for offset = 1,yearcount do
 		local x,y = data[offset][1], data[offset][2]
 		-- delink if necessary
 		if x:match('^%s*%[%[[^%[%]]*%|([^%[%]]*)%]%]') then
 			x = x:match('^%s*%[%[[^%[%]]*%|([^%[%]]*)%]%]')
 		end
 		y = formatnumR(y)
 		if x and y then
 			graphargs['x'] = graphargs['x'] .. (firstpoint and '' or ', ') .. x
 			graphargs['y'] = graphargs['y'] .. (firstpoint and '' or ', ') .. y
 			firstpoint = false
 		end
 	end
 	local Graph = require('Module:Graph')
 	
 	return Graph.chart({args = graphargs})
 end
 
 local function rendergraph(frame, data, gwidth, gheight, gthumb, gtype)
 	local graph = frame:extensionTag{
 			name = 'templatestyles', 
 			args = { src = 'Graph:Chart/styles.css'} 
 		} .. frame:extensionTag{name = 'graph', content = graphjson(data, gwidth, gheight, gtype)}
 
 	if(gthumb ~= '') then
 		local graphdiv = mw.html.create('div')
 			:addClass('thumb')
 			:addClass(gthumb == 'right' and 'tright' or 'tleft')
 			:css('clear', 'none')
 		graphdiv
 			:tag('div')
 			:addClass('thumbinner')
 			:wikitext(graph)
 		return tostring(graphdiv)
 	end
 	
 	return '&lt;div class=&quot;center&quot;&gt;' .. graph .. '&lt;/div&gt;'
 end
 
 -- this function renders the population table in a vertical format
 local function rendervertical(data, head, title, footnote, alignfn, class, style, width, shading, percol, cols, graphpos, graph)
 	-- define a couple helper functions
 	local function addrowcell(trow, tag, text, align, shading, style)
 		cell = trow:tag(tag)
 		cell
 			:css('text-align', align)
 			:css('padding', '1px')
 			:wikitext(text)
 			:css('border-bottom', shading ~= 'off' and '1px solid #bbbbbb' or nil)
 			:cssText(style)
 	end
 	local function addheadcell(trow, text, align, width, pad)
 		cell = trow:tag('th')
 		cell
 			:css('border-bottom', '1px solid black')
 			:css('padding', pad and ('1px ' .. pad) or '1px')
 			:css('text-align', align)
 			:css('width', width)
 			:wikitext(text)
 	end
 
 	local colspan = 3
 	local yearcount = #data
 	local argcount = 2*yearcount
 	
 	if( isempty(width) ) then
 		width = '15em'
 	end
 	
 	-- override the value of cols if percol has been specified
 	if( percol &gt; 0 ) then
 		cols = math.floor( (yearcount - 1) / percol ) + 1
 	end
 	
 	-- compute the number of rows per col
 	local rowspercol = math.floor( (yearcount - 1) / cols ) + 1
 
 	-- specify the colspan for the title and footer lines
 	if( cols &gt; 1 ) then
 		colspan = cols
 	else
 		if (head[3] == '') then 
 			colspan = 2
 		else
 			colspan = 3
 		end
 	end
 
 	-- compute outer table width
 	local twidth = width
 	if( (cols &gt; 1) and width:match('^%s*[%d]+[%w]+%s*$') ) then
 		local widthnum = mw.ustring.gsub( width, '^%s*([%d]+)([%w]+)%s*$', '%1' )
 		local widthunit = mw.ustring.gsub( width, '^%s*([%d]+)([%w]+)%s*$', '%2' )
 		twidth = tostring(widthnum*cols) .. widthunit
 	end
 	
 	-- create the outer table
 	local root = mw.html.create('table')
 	root
 		:addClass(class)
 		:css('width', twidth)
 		:css('border-top-width', '0')
 		:cssText(style['table'])
 	-- add title
 	local caption = root:tag('caption')
 	caption
 		:css('border-top', '1px #aaa solid')
 		:css('border-left', '1px #aaa solid')
 		:css('border-right', '1px #aaa solid')
 		:css('background-color', 'lavender')
 		:css('padding', '0.25em')
 		:css('font-weight', 'bold')
 		:wikitext(title)
 		
 	-- add the graph line (if top graph)
 	if((graphpos == 'top' or graphpos == 't') and graph ~= '') then
 		row = root:tag('tr')
 		cell = row:tag('td')
 		cell
 			:attr('colspan', colspan)
 			:css('border-bottom', '1px solid black')
 			:wikitext(graph)
 		graph = ''
 	end
 	
 	-- loop over columns and rows within columns
 	local offset = 1
 	local t = root
 	for c = 1,cols do
 		-- add inner tables if we are rendering more than one column
 		if( cols &gt; 1) then
 			if (c == 1) then
 				row = root:tag('tr')
 				row:attr('valign', 'top')
 				cell = row:tag('td')
 				cell:css('padding', '0 0.5em')
 			else
 				cell = row:tag('td')
 				cell
 					:css('padding', '0 0.5em')
 					:css('border-left', 'solid 1px #aaa')
 			end
 			t = cell:tag('table')
 			t
 				:css('border-spacing', '0')
 				:css('width', width)
 		end
 		-- start column headers
 		local hrow = t:tag('tr')
 		hrow:css('font-size', '95%')
 		-- year header
 		addheadcell(hrow, head[1], nil, head[3] ~= '' and '3em' or 'auto', nil, nil)
 		-- population header
 		addheadcell(hrow, head[2], 'right', nil, '2px')
 		-- percentages header
 		if( head[3] ~= '' ) then
 			addheadcell(hrow, head[3], 'right', nil, nil)
 		end
 		-- end column headers
 		-- start population rows
 		for r = 1,rowspercol do
 			-- generate the row if we have not exceeded the rowcount
 			-- shade every fifth row, unless shading = off
 			local s = 'off'
 			if( math.fmod((c - 1)*rowspercol + r, 5) == 0 and r ~= rowspercol) then
 				s = shading
 			end
 			if(offset &lt;= yearcount) then
 				-- start population row
 				local prow = t:tag('tr')
 				-- year cell
 				addrowcell(prow, 'th', data[offset][1], 'center', s, style['year'])
 				-- population cell
 				addrowcell(prow, 'td', data[offset][2], 'right', s, style['pop'])
 				-- percentage cell
 				if( not isempty(head[3]) ) then
 					addrowcell(prow, 'td', data[offset][3], 'right', s, style['pct'])
 				end
 				-- end population row
 				offset = offset + 1
 			end
 		end
 	end
 
 	-- add the graph line (if bottom graph)
 	if((graphpos == 'bottom' or graphpos == 'b') and graph ~= '') then
 		row = root:tag('tr')
 		cell = row:tag('td')
 		cell
 			:attr('colspan', colspan)
 			:css('border-top', '1px solid black')
 			:wikitext(graph)
 		graph = ''
 	end
 	-- add the footnote line 	
 	if( footnote ~= '') then
 		row = root:tag('tr')
 		cell = row:tag('td')
 		cell
 			:attr('colspan', colspan)
 			:css('border-top', '1px solid black')
 			:css('font-size', '85%')
 			:css('text-align', alignfn)
 			:wikitext(footnote)
 	end
 	
 	return graph .. tostring(root)
 end
 
 -- this function renders the population table in a horizontal format
 local function renderhorizontal(data, head, title, footnote, alignfn, class, style, width, shading, perrow, rows, graphpos, graph)
 	local row
 	local cell
 	local yearcount = #data
 	local argcount = 2*yearcount
 	
 	-- override the value of rows if perrow has been specified
 	if( perrow &gt; 0 ) then
 		rows = math.floor( (yearcount - 1) / perrow ) + 1
 	end
 	
 	-- compute the number of cols per row
 	local colsperrow = math.floor( (yearcount - 1) / rows ) + 1
 
 	-- create the outer table
 	local root = mw.html.create('table')
 	root
 		:addClass(class)
 		:css('font-size', '90%')
 		:cssText(style['table'])
 	-- create title row
 	row = root:tag('tr')
 	cell = row:tag('th')
 	cell
 		:css('padding', '0.25em')
 		:attr('colspan', colsperrow + 1)
 		:wikitext(title)
 
 	-- add the graph line (if top graph)
 	if((graphpos == 'top' or graphpos == 't') and graph ~= '') then
 		row = root:tag('tr')
 		cell = row:tag('td')
 		cell
 			:attr('colspan', colsperrow + 1)
 			:css('border-bottom', '1px solid black')
 			:wikitext(graph)
 		graph = ''
 	end
 
 	-- loop over rows and columns within rows
 	local offset = 1
 	for r = 1,rows do
 		local rowoffset = offset
 		-- render the years
 		row = root:tag('tr')
 		cell = row:tag('th')
 		cell:wikitext(head[1])
 			:css('border-top', r &gt; 1 and '2px solid #000' or nil)
 		for c = 1,colsperrow do
 			cell = row:tag('td')
 			if(offset &lt;= yearcount) then
 				cell:wikitext(data[offset][1])
 					:css('text-align', 'center')
 					:css('border-top', r &gt; 1 and '2px solid #000' or nil)
 					:cssText(style['year'])
 			else
 				cell:css('border-width', r &gt; 1 and '2px 0 0 0' or 0)
 					:css('border-top', r &gt; 1 and '2px solid #000' or nil)
 			end
 			offset = offset + 1
 		end
 		-- render the pop
 		offset = rowoffset
 		row = root:tag('tr')
 		cell = row:tag('th')
 		cell:wikitext(head[2])
 		for c = 1,colsperrow do
 			cell = row:tag('td')
 			if(offset &lt;= yearcount) then
 				cell:wikitext(data[offset][2])
 					:css('text-align', 'right')
 					:css('padding-right', '2px')
 					:cssText(style['pop'])
 			else
 				cell:css('border-width', 0)
 			end
 			offset = offset + 1
 		end
 		-- render the percentages
 		if(head[3] ~= '') then
 			offset = rowoffset
 			row = root:tag('tr')
 			cell = row:tag('th')
 			cell:wikitext(head[3])
 			for c = 1,colsperrow do
 				cell = row:tag('td')
 				if(offset &lt;= yearcount) then
 					cell:wikitext(data[offset][3])
 						:css('text-align', 'right')
 						:css('padding-right', '2px')
 						:cssText(style['pct'])
 				else
 					cell:css('border-width', 0)
 				end
 				offset = offset + 1
 			end
 		end
 	end
 	
 	-- add the graph line (if bottom graph)
 	if((graphpos == 'bottom' or graphpos == 'b') and graph ~= '') then
 		row = root:tag('tr')
 		cell = row:tag('td')
 		cell
 			:attr('colspan', colsperrow + 1)
 			:css('border-top', '1px solid black')
 			:wikitext(graph)
 		graph = ''
 	end
 	
 	-- add the footnote line 	
 	if( footnote ~= '') then
 		row = root:tag('tr')
 		cell = row:tag('td')
 		cell
 			:css('border-top', '2px solid black')
 			:css('font-size', '85%')
 			:css('text-align', alignfn)
 			:attr('colspan', colsperrow + 1)
 			:wikitext(footnote)
 	end
 	
 	return graph .. tostring(root)
 end
 
 -- this is the main function
 function p.poptable(frame)
 	local data = {}
 	local style = {}
 	local args = frame.args[1] and frame.args or frame:getParent().args
 
 	local title			= args['title']			or ''
 	local align			= args['align']			or ''
 	local clear			= args['clear']			or ''
 	local direction		= args['direction']		or ''
 	local percentages	= args['percentages']	or ''
 	local state			= args['state']			or ''
 	local linktype		= args['type']			or ''
 	local shading		= args['shading']		or 'on'
 	local width			= args['width']			or ''
 	local subbox		= args['subbox']		or ''
 	local popname		= args['pop_name']		or ''
 	local yearname		= args['year_name']		or ''
 	local percentname   = args['percent_name']  or ''
 	local footnote		= args['footnote']		or ''
 	local alignfn		= args['align-fn']		or ''
 	local source		= args['source']		or ''
 	local graphpos      = args['graph-pos']     or ''
 	local graphwidth    = args['graph-width']   or ''
 	local graphheight   = args['graph-height']  or ''
 	local graphtype     = args['graph-type']    or 'line'
 	local percol = tonumber(args['percol'])	or 0
 	local cols	 = tonumber(args['cols'])	or 1
 	local perrow = tonumber(args['perrow'])	or 0
 	local rows	 = tonumber(args['rows'])	or 1
 	style['year'] = args['year_style']
 	style['pop']  = args['pop_style']
 	style['pct']  = args['pct_style']
 
 	-- setup classes and styling for outer table
 	local class = direction == 'horizontal' and 'wikitable' or 'toccolours'
 	if( state == 'collapsed' ) then
 		class = class .. ' collapsible collapsed'
 	end
 
 	if( isempty(title) ) then
 		title = 'மக்கள்தொகை வளர்ச்சி'
 	end
 
 	if( isempty(align) ) then
 		align = direction ~= 'horizontal' and 'right' or 'center'
 	end
 	
 	if( isempty(alignfn) ) then
 		alignfn = 'left'
 	end
 	
 	if( isempty(clear) ) then
 		clear = align == 'center' and '' or align
 	end
 	
 	local margin = '0.5em 0 1em 0.5em'
 	if( align == 'left' ) then
 		margin = '0.5em 1em 0.5em 0'
 	elseif( align == 'none' ) then
 		margin = '0.5em 1em 0.5em 0'
 	elseif( align == 'center' ) then
 		margin = '0.5em auto'
 		align = ''
 	end
 
 	if( isempty(subbox) ) then
 		style['table'] =
 			'border-spacing: 0;' ..
 			(align ~= '' and 'float:' .. align .. ';' or '') ..
 			(clear ~= '' and 'clear:' .. clear .. ';' or '') ..
 			'margin:' .. margin .. ';'
 	else
 		style['table'] =
 			'margin:0;' ..
 			'border-collapse:collapse;' ..
 			'border:none;'
 	end
 	
 	style['table'] = style['table'] .. (args['table_style'] or '')
 		
 	-- setup the footer text
 	if( source ~= '' ) then
 		source = 'ஆதாரம்: ' .. source
 		if( footnote ~= '' ) then
 			footnote = footnote .. '&lt;br/&gt;'
 		end
 	end
 	footnote = footnote .. source
 	
 	-- setup the data header cols/rows
 	local head = getheadrow(percentages, popname, yearname, percentname)
 	
 	-- count the total number of population rows
 	local argcount = 0
 	local rowcount = 0
 	for k, v in pairs( args ) do
 		if ( (type( k ) == 'number') and (not isempty(args[k])) ) then
 			if( k &gt;= 1 and math.floor(k) == k and k &gt; argcount) then
 				argcount = k
 			end
 			if( math.fmod(k - 1, 2) == 0 ) then
 				rowcount = rowcount + 1
 			end
 		end
 	end
 
 	-- here is where we build all the data for the table
 	-- loop over columns and rows within columns
 	local pyear = ''
 	local ppop = ''
 	local offset = 1
 	local current_year = tonumber(os.date(&quot;%Y&quot;, os.time()))
 	for r = 1,rowcount do
 		-- skip blank rows
 		while(isempty(args[offset]) and offset &lt;= argcount) do
 			offset = offset + 2
 		end
 		-- generate the row if we have not exceeded the rowcount
 		if(offset &lt;= argcount) then
 			table.insert(data, getpoprow(args[offset], args[offset + 1] or '', pyear, ppop, 
 				linktype, percentages, current_year) )
 			pyear = args[offset]
 			ppop = args[offset+1] or ''
 			offset = offset + 2
 		end
 	end
 
 	local graph = ''
 	graphpos = graphpos:lower()
 	-- now that we have the data for the table, render it in the requested format
 
 	if (direction == 'horizontal') then
 		if graphpos ~= '' then
 			local gwidth = tonumber(graphwidth) or 200
 			local gheight= tonumber(graphheight) or 170
 			local gthumb = 
 				(graphpos == 'r' or graphpos == 'right' and 'right') or
 				(graphpos == 'l' or graphpos == 'left' and 'left') or ''
 			graph = rendergraph(frame, data, gwidth, gheight, gthumb, graphtype)
 		end
 		return renderhorizontal(data, head, title, footnote, alignfn, class, style, width, shading, perrow, rows, graphpos, graph)
 	else
 		if graphpos ~= '' then
 			local gwidth = tonumber(graphwidth) or (170 * cols)
 			local gheight= tonumber(graphheight) or 170
 			local gthumb = 
 				(graphpos == 'r' or graphpos == 'right' and 'right') or
 				(graphpos == 'l' or graphpos == 'left' and 'left') or ''
 			graph = rendergraph(frame, data, gwidth, gheight, gthumb, graphtype)
 		end
 		return rendervertical(data, head, title, footnote, alignfn, class, style, width, shading, percol, cols, graphpos, graph)
 	end
 
 end