-- This module will implement 
--
 
local p = {}
 
local HtmlBuilder = require('Module:HtmlBuilder')
local Navbar = require('Module:Navbar')

local args
local frame
local tableRowAdded = false
local border
-- local listnums = {}

local listkeys = {}
local listinfo = {}
local listrows = 0

function trim(s)
 return (mw.ustring.gsub(s, "^%s*(.-)%s*$", "%1"))
end

function addTableRow(tbl)
 -- If any other rows have already been added, then we add a 2px gutter row.
 if tableRowAdded then
 tbl
 .tag('tr')
 .css
 .tag('td')
 end
 
 tableRowAdded = true
 
 return tbl.tag('tr')
end

--
-- Title row
--
function renderTitleRow(tbl)
 if not args.title then return end
 
 local titleRow = addTableRow(tbl)
 
 if args.titlegroup then
 titleRow
 .tag('th')
 .attr
 .addClass('navbox-group')
 .addClass(args.titlegroupclass)
 .cssText(args.basestyle)
 .cssText(args.groupstyle)
 .cssText(args.titlegroupstyle)
 .wikitext(args.titlegroup)
 end
 
 local titleCell = titleRow.tag('th').attr
 
 if args.titlegroup then
 titleCell
 .css
 .css
 end
 
 local titleColspan = 2
 if args.imageleft then titleColspan = titleColspan + 1 end
 if args.image then titleColspan = titleColspan + 1 end
 if args.titlegroup then titleColspan = titleColspan - 1 end
 
 titleCell
 .cssText(args.basestyle)
 .cssText(args.titlestyle)
 .addClass('navbox-title')
 .attr
 
 renderNavBar(titleCell)
 
 titleCell
 .tag('div')
 .addClass(args.titleclass)
 .css
 .newline
 .wikitext(args.title)
end

function renderNavBar(titleCell)
 -- Depending on the presence of the navbar and/or show/hide link, we may need to add a spacer div on the left
 -- or right to keep the title centered.
 local spacerSide = nil

 if args.navbar == 'off' then
 -- No navbar, and client wants no spacer, i.e. wants the title to be shifted to the left. If there's
 -- also no show/hide link, then we need a spacer on the right to achieve the left shift.
 if args.state == 'plain' then spacerSide = 'right' end
 elseif args.navbar == 'plain' or args.navbar == 'off' or (not args.name and (border == 'subgroup' or border == 'child' or border == 'none')) then
 -- No navbar. Need a spacer on the left to balance out the width of the show/hide link.
 if args.state ~= 'plain' then spacerSide = 'left' end
 else
 -- Will render navbar (or error message). If there's no show/hide link, need a spacer on the right
 -- to balance out the width of the navbar.
 if args.state == 'plain' then spacerSide = 'right' end

 titleCell.wikitext(Navbar.navbar({ 
 args.name, 
 mini = 1, 
 fontstyle = (args.basestyle or '') .. ';' .. (args.titlestyle or '') .. ';background:none transparent;border:none;'
 end
 
 -- Render the spacer div.
 if spacerSide then
 titleCell
 .tag('span')
 .css
 .css
 .wikitext('&nbsp;')
 end
end

--
-- Above/Below rows
--
function renderAboveRow(tbl)
 if not args.above then return end
 
 addTableRow(tbl)
 .tag('td')
 .addClass('navbox-abovebelow')
 .addClass(args.aboveclass)
 .cssText(args.basestyle)
 .cssText(args.abovestyle)
 .attr
 .tag('div')
 .newline
 .wikitext(args.above)
end

function renderBelowRow(tbl)
 if not args.below then return end
 
 addTableRow(tbl)
 .tag('td')
 .addClass('navbox-abovebelow')
 .addClass(args.belowclass)
 .cssText(args.basestyle)
 .cssText(args.belowstyle)
 .attr
 .tag('div')
 .newline
 .wikitext(args.below)
end

function getAboveBelowColspan
 local ret = 2
 if args.imageleft then ret = ret + 1 end
 if args.image then ret = ret + 1 end
 return ret
end
 
 
--
-- List rows
--
function renderListRow
 local row = addTableRow(tbl)
 
 if listnum == 1 and args.imageleft then
 row
 .tag('td')
 .addClass('navbox-image')
 .addClass(args.imageclass)
 .css
 .css
 .cssText(args.imageleftstyle)
 .attr
 .tag('div')
 .newline
 .wikitext(args.imageleft)
 end
 
 if args['group' .. listnum] then
 local groupCell = row.tag('th')
 
 groupCell
 .attr
 .addClass('navbox-group')
 .addClass(args.groupclass)
 .cssText(args.basestyle)
 
 if args.groupwidth then
 groupCell.css
 end
 
 groupCell
 .cssText(args.groupstyle)
 .cssText(args['group' .. listnum .. 'style'])
 .wikitext(args['group' .. listnum])
 end
 
 local listCell = row.tag('td')

 if args['group' .. listnum] then
 listCell
 .css
 .css
 .css
 else
 listCell.attr
 end
 
 if not args.groupwidth then 
 listCell.css
 end
 
 local isOdd = (listnum % 2) == 1
 local rowstyle = args.evenstyle
 if isOdd then rowstyle = args.oddstyle end
 
 local evenOdd
 if args.evenodd == 'swap' then
 if isOdd then evenOdd = 'even' else evenOdd = 'odd' end
 else
 if isOdd then evenOdd = args.evenodd or 'odd' else evenOdd = args.evenodd or 'even' end
 end
 
 listCell
 .css
 .cssText(args.liststyle)
 .cssText(rowstyle)
 .cssText(args['list' .. listnum .. 'style'])
 .addClass('navbox-list')
 .addClass('navbox-' .. evenOdd)
 .addClass(args.listclass)
 .tag('div')
 .css('padding', (listnum == 1 and args.list1padding) or args.listpadding or '0em 0.25em')
 .newline
 .wikitext(args['list' .. listnum])

 if listnum == 1 and args.image then
 row
 .tag('td')
 .addClass('navbox-image')
 .addClass(args.imageclass)
 .css
 .css
 .cssText(args.imagestyle)
 .attr
 .tag('div')
 .newline
 .wikitext(args.image)
 end
end

--
-- Tracking categories
--
function renderTrackingCategories(builder)
 local frame = mw.getCurrentFrame
 
 if not frame then return end
 
 local s = frame:preprocess('||1|0}}')
 if mw.ustring.sub == '0' then return end -- not in template space
 local subpage = mw.ustring.lower(mw.ustring.sub)
 if subpage == 'doc' or subpage == 'sandbox' or subpage == 'testcases' then return end
 
 for i, cat in ipairs(getTrackingCategories) do
 builder.wikitext('Category:' .. cat .. '') 
 end
end

function getTrackingCategories
 local cats = {}
 if needsHorizontalLists then table.insert end
 if hasCustomListSpacing then table.insert end
 if hasBackgroundColors then table.insert end
 return cats
end

function needsHorizontalLists
 if border == 'child' or border == 'subgroup' or args.tracking == 'no' then return false end
 
 local listClasses = {'plainlist', 'hlist', 'hlist hnum', 'hlist vcard', 'vcard hlist'}
 for i, cls in ipairs(listClasses) do
 if args.listclass == cls or args.bodyclass == cls then
 return false
 end
 end

 return true
end

function hasCustomListSpacing
 return args.liststyle == 'padding: 0.25em 0; line-height: 1.3em;' or 
 args.liststyle == 'padding:0.25em 0; line-height:1.4em; width:auto;' or 
 args.liststyle == 'padding:0.4em 0; line-height:1.4em;'
end

function hasBackgroundColors
 return args.titlestyle or args.groupstyle
end

--
-- Main navbox tables
--
function renderMainTable
 local tbl = HtmlBuilder.create('table')
 .attr
 .addClass('nowraplinks')
 .addClass(args.bodyclass)
 
 if args.title and (args.state ~= 'plain' and args.state ~= 'off') then
 tbl
 .addClass('collapsible')
 .addClass(args.state or 'autocollapse')
 end
 
 tbl.css
 if border == 'subgroup' or border == 'child' or border == 'none' then
 tbl
 .addClass('navbox-subgroup')
 .cssText(args.bodystyle)
 .cssText(args.style)
 else -- regular navobx - bodystyle and style will be applied to the wrapper table
 tbl
 .addClass('navbox-inner')
 .css
 .css
 end
 tbl.cssText(args.innerstyle)
 
 renderTitleRow(tbl)
 renderAboveRow(tbl)
 for i, listnum in ipairs(listkeys) do
 renderListRow 
 end
 renderBelowRow(tbl)
 
 return tbl
end

function p._navbox(navboxArgs)
 args = navboxArgs
 
 for k, v in pairs(args) do
 -- Check list entry
 local listnum, listsub = ('' .. k):match('^list(%d+)(%l?)$')
 
 mw.log
 if listnum then
 listnum = tonumber(listnum)
 if listinfo[listnum] == nil then listinfo[listnum] = {} end
 if listsub == '' then
 listinfo[listnum].type = 'plain'
 elseif listinfo[listnum].type ~= 'plain' then
 listinfo[listnum].type = 'subgroup'
 if listinfo[listnum].childs == nil then listinfo[listnum].childs = {} end
 table.insert
 end
 end
 end

 for k, v in pairs(listinfo) do
 mw.log
 table.insert
 if v.type == 'plain' then
 v.numrows = 1
 else
 table.sort(v.childs)
 v.numrows = #v.childs
 end
 end

 table.sort(listkeys)
 
 for _, k in ipairs(listkeys) do
 mw.log
 listinfo[k].offset = listrows
 listrows = listrows + listinfo[k].numrows
 end
 
 border = trim(args.border or args[1] or '')

 -- render the main body of the navbox
 local tbl = renderMainTable

 -- render the appropriate wrapper around the navbox, depending on the border param
 local res = HtmlBuilder.create
 if border == 'none' then
 res.node(tbl)
 elseif border == 'subgroup' or border == 'child' then
 -- We assume that this navbox is being rendered in a list cell of a parent navbox, and is
 -- therefore inside a div with padding:0em 0.25em. We start with a  to avoid the
 -- padding being applied, and at the end add a 
 res
 .tag
 .done
 .node(tbl)
 .tag
 else
 res
 .tag('table')
 .attr
 .addClass('navbox')
 .css
 .cssText(args.bodystyle)
 .cssText(args.style)
 .tag('tr')
 .tag('td')
 .css
 .node(tbl)
 end
 
 renderTrackingCategories(res)
 
 return tostring(res)
end
 
function p.navbox(frame)
 -- ParserFunctions considers the empty string to be false, so to preserve the previous 
 -- behavior of , change any empty arguments to nil, so Lua will consider
 -- them false too.
 local args = {}
 local parent_args = frame:getParent.args;

 -- Out of order parsing bug.
 local temp;
 temp = parent_args.title;
 temp = parent_args.above;
 for i = 1, 20 do
 temp = parent_args["group" .. tostring(i)];
 temp = parent_args["list" .. tostring(i)];
 end 
 temp = parent_args.below;
 
 for k, v in pairs(parent_args) do
 if v ~= '' then
 args[k] = v
 end
 end
 return p._navbox(args)
end