inkbound
Module:Items
Data
Trinkets
Navboxes

Module for Vestiges and various ways to display them.


local p = {}
local ItemData = mw.loadData [[Module:Items/Data]]
local TrinketData = mw.loadData [[Module:Items/Trinkets]]
local NavData = mw.loadData [[Module:Items/Navboxes]]
local Shared = require [[Module:Utils]]
local Icons = require [[Module:Icons]]
local rarityOrder = {'Common','Uncommon','Rare','Epic','Legendary'}
local warnObsolete = true --warns on pages that data is obsolete p.plaqueWarning()

local classNames = {
	'Magma Miner',
	'Mosscloak',
	'Weaver',
	'Obelisk',
	'Clairvoyant',
	'Star Captain',
	'Chainbreaker',
	'Godkeeper',
}

function toNil(thing)
	if thing==nil or thing=='' then return nil else return thing end
end

function p.t2()
	return	p.getNavboxesByItemName('Inkritto')
end

function p.findItems(frame)
	local a, b = p.getFilteredTableStack(frame)
	a.Unsorted=b
	return p.drawTableByNames(a,{Header=true})
end

function p.findTrinkets(frame)
	local a, b = p.getFilteredTableStack(frame, nil, TrinketData)
	a.Unsorted=b
	return p.drawTableByNames(a,{Header=true, isTrinket=true, colNames={'Trinket',''}})
end

function p.t3(frame)
--	local SkillData = mw.loadData [[Module:Bindings/Data]]
--	local Bindings = require [[Module:Bindings]]
	local a, b = p.getFilteredTableStack('Rarity',Shared.importStackFromTemplate(frame))
--	local c, d = p.getFilteredTableStack('Class',Shared.importStackFromTemplate(frame),SkillData)
	
	local count = 1
	local function ohio(tab)
		if count == 1 then count=count+1 return p.drawTableByNames(tab)
		end
		return p.drawTableByNames(tab,nil,nil,Bindings.drawBindingRow)
	end
	
	a.Unsorted=b
	return p.drawTableByNames(a,{Header=true})
--	c.Unsorted=d
 --mw.logObject(c)
--	return Shared.drawTabber({Vestiges=a,Bindings=c}, ohio, {'Vestiges','Bindings'}, true)
end

function p.t4()
	local varImported =
		{ Stats ={	["Burn Damage"] = true	}
			--Tags ={	["Burn"] = true	}
			--Rarity= { Rare = true }
		}
	local curator = 'Rarity'
	
	local a, b = p.getFilteredTableStack(curator, varImported)
	
end

--Фильтрует базу данных по запрошенным параметрам и возвращает две таблицы
--Первая разделена на подтаблицы в соответствии с curator-параметром
--Вторая просто существует. Содержит все фильтрованные, но не прошедшие курацию моды.
--Когда не указано куратора, все фильтрованные моды помещаются во вторую таблицу.
function p.getFilteredTableStack(curator, varImported, Database)
	return Shared.getFilteredTableStack(curator, varImported, Database or ItemData)
end





--------------------------------------------------------------------------------
----------------------------------Infobox Functions-----------------------------
--------------------------------------------------------------------------------
function p.drawVestigePage(frame)
	local Name = toNil(frame.args[1])
	local doTrinketInstead = toNil(frame.args[2])
		doTrinketInstead = doTrinketInstead=='+' and true or false
	if not Name then return "Error: No Vestige Name have been passed." end
	local Item = p.getItem(Name, doTrinketInstead)
	mw.logObject(Item)
	local box = mw.html.create():node(Item.Exclude and p.plaqueWarning() or nil)
	local tabl = mw.html.create('table')
	if Item.Unlocked then
		tabl
		:tag('tr'):tag('td'):addClass('vestige-page-unlock-quest')
			:wikitext(Item.Unlocked==true and "Unlocked by dafault" or nil)
			:wikitext(type(toNil(Item.Unlocked))=='string' and "Unlocked via: [[Quests#"..Item.Unlocked..'|'..Item.Unlocked..']]' or nil)
			:wikitext(toNil(Item.Unlocked)==nil and "Unlocked via: ???" or nil)
			:done():done()
	end
	
	function checkForExclisivity()
		if type(Item.Tags)~='table' then return end
		local classFound = false
		local stack = mw.html.create('span')
			:wikitext(' exclusive to ')
		for _, className in pairs(classNames) do
			if Item.Tags[className] then
				if classFound then stack:wikitext(' and ') end
				stack:node(Icons.Main(className,className))
				classFound = classFound or true
				end
			end
		if classFound == false then return end
		return stack
	end
--	if not doTrinketInstead then
	tabl		
		:tag('tr'):tag('td'):addClass('vestige-page-table-stats')
			:tag('span')
				:node(doTrinketInstead and '' or Icons.Main(Item.Rarity or 'Common',Item.Rarity or 'Common'))
				:wikitext(doTrinketInstead and (Item.Locked and 'Unlockable' or 'Starter')..' [[Trinket]]' or ' [[Vestige]]')
				:node(checkForExclisivity())
				:done()
			--:tag('span'):css('display','none')--displayed only on mobile
			--	:wikitext(' introduced in '):done()
			--:tag('span'):addClass('vestige-page-version')
			--	:wikitext(Item.Introduced or 'VANILLA'):done()
		:allDone()
--	end 
	local tagWhitelist = {}
	
	if Item.Sets then
		local row = mw.html.create()	
		for Set, val in Shared.skpairs(Item.Sets or {}) do
			row:tag('span'):node(Icons.Main(Set,Set)):done()
		end
		tabl:tag('tr'):tag('td'):addClass('vestige-page-table-stats')
			:node(row):allDone()
	end
	
	if Item.Stats and Item.Stats[1] then
		local row = mw.html.create()	
		for _, Stat in pairs(Item.Stats) do
			tagWhitelist[Stat[1]]=true
			local sign = type(Stat[2])=='number' and Stat[2]>=0 and ' +' or ' '
			row:tag('span'):wikitext(sign, Stat[2],' '):node(Icons.Main(Stat[1],Stat[1])):done()
		end
		tabl:tag('tr'):tag('td'):addClass('vestige-page-table-stats')
			:node(row):allDone()
	end
	
	tabl:tag('tr'):tag('td'):addClass('vestige-page-table-desc')
		:css('text-align',toNil(Item.Desc)==nil and 'center' or nil)
		:node(toNil(Item.Desc) and Icons.convertTooltipText(Item.Desc,true) or 'Has no active effect')
		:allDone()
	
	function addExplainer(Icon)
		if not toNil(Icon.TooltipText) then return end
		tabl:tag('tr'):tag('td'):addClass('vestige-page-table-explainer')
				:node(Icons.Main(Icon,nil,30))
				:tag('span'):wikitext("'''",Icon.Name,"''' ")
				:node(Icons.convertTooltipText(Icon.TooltipText,true))
				:allDone()	
	end
	
	for statName in Shared.skpairs(tagWhitelist) do
		local Icon = Icons.getIcon(statName)
			addExplainer(Icon)
	end
	for tagName, val in Shared.ordpairs(Item.Tags or {}, Item.Order or {}) do
		if val==true and tagWhitelist[tagName]==nil then
			local Icon = Icons.getIcon(tagName)
			addExplainer(Icon)
		end
	end
	local ttlo = mw.title.new(Item.Image or Item.Name.." wiki.png", "File")
	local imageExists = ttlo.exists

	box:tag('div'):addClass('vestige-page-wrapper')
		:tag('div'):addClass('vestige-page-image')
			:wikitext("[[File:"..(imageExists and (Item.Image or Item.Name.." wiki.png") or "Unknown Vestige wiki.png").."|link=]]")
			:done()
		:tag('div'):addClass('vestige-page-table'):node(tabl)
		
		:allDone()
	return box
			:wikitext('__NOTOC__')
			:wikitext(doTrinketInstead and '[[Category:Trinket]]' or p.getVestigeCategories(Name))
			:tag('div'):attr('style',"text-align:center; margin-top: 8px; font-style: italic; font-family: 'Inknut Antiqua';")
			:wikitext('Top section contains errors? Edit it via [[Module:Items/Data]] or check [https://factubsio.github.io/TheBindery/ Factubsio git page] if it\'s updated there.'):done()
end


--returns warning that current Vestige Data is out of date
function p.plaqueWarning()
	local Mbox = require( "Module:Mbox" )
	if warnObsolete then
		return Mbox.main({
header = "'''Hey Needless!'''",
text = "Please note that current vestige info is out-of-date, as it was sourced from '''Steam Next Fest''' Demo version. If you have up-to-date data, please [[Message_Wall:Zero_Leaf|contact the admin]] or update [[Module:Items/Data]] (Lua) manually."
		})
	end
	return ''
end

--Returns Template:Vestige infobox/Tab prefilled with information based on Items Database
function p.vestigeInfobox(frame)
	local Name = toNil(frame.args['Name']) or toNil(frame.args[1])
	local Data = p.getItem(Name)
	local Image = toNil(frame.args['Image']) or Data.Image or (Data.Name or Name)..' wiki.png'
	local Rarity = toNil(frame.args['Rarity']) or Data.Rarity or 'unknown'
	local Stats = toNil(frame.args['Stats']) or p.drawItemStats(Data.Stats) or nil
	local Quest = toNil(frame.args['Quest']) or Data.Quest
	local Description = toNil(frame.args['Description'])
	 
	
	local ttlo = mw.title.new(Image, "File")
	local imageExists = ttlo.exists
	
	return frame:expandTemplate{ title = 'Vestige infobox/Tab', args = { 
		Name = Name or Data.Name,
		Image = imageExists and Image or Rarity.." placeholder wiki.png",
		Rarity = Rarity,
		Stats = Stats,
		Quest = Ques ,
		AutoCategories = p.getVestigeCategories(Name)..tostring(p.plaqueWarning()),
		Description = Description or tostring(p.vestigePageText(Name)),
		AlterForPlaceholder = tostring(imageExists)
	} }
end

--shell function for external call
function p._getVestigeCategories(frame)
	return p.getVestigeCategories(frame.args(1))
end

--returns string of Vestige Categories based on Module:Items/Infoboxes
function p.getVestigeCategories(Name)
	local Data = p.getItem(Name)
	local catsUsed, Categories = {}, {}
	table.insert(Categories,'[[Category:Vestiges]]')
	table.insert(Categories,'[[Category:'..(Data.Rarity or 'Error')..' Vestiges]]')
	if type(Data.Tags)=='table' then
		for tagName, val in Shared.skpairs(Data.Tags) do
			if val==true then
				local _, catName = p.getTags(tagName)
				if catName and catsUsed[catName]~=true then
					catsUsed[catName]=true
					table.insert(Categories,'[[Category:'..catName..' Vestiges]]')
				end
			end
		end
	end
	return table.concat(Categories,' ')
end

--shell function for external call
function p._vestigePageText(frame)
	return p.vestigePageText(frame.args[1])
end

--returns HTML description for Vestige page.
function p.vestigePageText(Name)
	Name = Name or "Token of Regret"
	local Data = p.getItem(Name)
	local upStats = {{}, {}}
	local Page = mw.html.create()
	Page:wikitext( "'''"..Name.."''' — is a", (Data.Rarity=='Epic' and 'n ' or ' '),
		(Data.Rarity and Data.Rarity:lower() or 'unknown'), ' [[Vestige]] with ',
		(toNil(Data.Desc) and "following effect: " or "no active effect, "))
	if toNil(Data.Desc) then Page:node(Icons.convertTooltipText(Data.Desc,true)) end
	
	--splits positive and negative stats into the different tables
	if type(Data.Stats)=='table' then
		for _,Stat in pairs(Data.Stats) do
			if type(Stat)=='table' and type(Stat[2]=='number') then
				table.insert(upStats[Stat[2]>=0 and 1 or 2],Stat)
			end
		end
	end
	--returns correct separator based on number of elements remaining.
	function separator(tab,i)
		if tab[i+1] and tab[i+2] then return ', '
		elseif tab[i+1] then return ' and '
		else return ' '
		end
	end
	--returns either positive(1) or negative(2) stats transformed into text
	--i.e. "Crit Chance by +10%, Crit Damage by 50% and Max HP by +10"
	function renStats(num)
		local toText = mw.html.create()
		for i, Stat in pairs(upStats[num]) do
			if type(Stat)=='table' then
				local pref = type(Stat[1])=='string' and (Stat[1]:find('Chance') or Stat[1]:find('Crit')) and '%' or ''
				local sign = type(Stat[2])=='number' and Stat[2]>=0 and '+' or ''
				toText:node(Icons.Main(Stat[1],Stat[1]):css('display','inline-block'))
					:wikitext(" by '''", sign, Stat[2], pref, "'''", separator(upStats[num],i))
			end
		end
		return toText
	end
	--returns the whole stat part of text for both positive and negative stats
	function returnText()
		local text = mw.html.create()
		if not (#upStats[1]>0 or #upStats[2]>0) then return text end
		text:wikitext(toNil(Data.Desc) and '<br>It also passively ' or 'that passively ',
			#upStats[1]>0 and 'increases your ' or 'reduces your ')
			:node(renStats(#upStats[1]>0 and 1 or 2))
		if not (#upStats[1]>0 and #upStats[2]>0) then return text:wikitext('.') end
		text:wikitext('while reducing '):node(renStats(2))
		return text:wikitext('.')
	end
	return Page:node(returnText())

end




--------------------------------------------------------------------------------
----------------------------Template:Vestige_navbox functions-------------------
--------------------------------------------------------------------------------

function p.trinketNavbox(skipShell)
	local Shell = mw.html.create('div'):addClass('navbox tpl-navigation')
	if skipShell==true then Shell = mw.html.create() end
	local Box=mw.html.create('table'):addClass('wikitable binding-navbox')
	local fit, shelved = Shared.getFilteredTableStack({args={}}, nil, TrinketData)
	
	function drawB(stack)
		local cart = mw.html.create()	
		for i, Name in pairs(stack) do
			--cart:node(p.drawBinding(Name))
			cart:wikitext('[['..Name..']]')
			if i~=#stack then cart:wikitext(' • ') end
		end
		return cart
	end
	
	Box:tag('tr'):tag('td'):attr('colspan',2):node(drawB(shelved)):allDone()

	return Shell:tag('div'):addClass('navbox-head mw-customtoggle-all-bindings')
			:attr('style','font-size: larger; cursor:pointer;'):wikitext('Trinkets'):done()
			:tag('div'):addClass('mw-collapsible mw-collapsed'):attr('id','mw-customcollapsible-all-bindings')
				:node(Box):allDone()
end


--shell function for external call. used in Template:Vestige_navbox
function p._getNavboxesByItemName(frame)
	return p.getNavboxesByItemName(frame.args[1])
end

--fork of the original p.getNavboxesByItemName
--recieves item name. Returns stack of navboxes generated for each positive item tag
--For use in Template:Vestige_navbox
function p.getNavboxesByItemName2(Name, scanMore)
	local Data = p.getItem(Name)
	local BindingData
	if type(Data.Tags)~='table' then return end
	local Box = mw.html.create('div'):addClass('navbox tpl-navigation')
	local tagStack,itemsByTag, itemsByRarity = {}, {}, {}
	--extracts tags from Item
	for tagName, val in Shared.skpairs(Data.Tags) do
		if val==true then
			local catStack, catName = p.getTags(tagName)
			if catName and itemsByTag[catName]==nil then
				itemsByTag[catName]={}
				--extracts all tags required to be in a navbox
				for _, tagName in pairs(catStack) do
					tagStack[tagName] = tagStack[tagName] or catName
					if 	itemsByTag[catName][tagName]==nil then itemsByTag[catName][tagName]={} end
				end
			end
		end
	end
	
	function addToItemsByRarity()
		if itemsByRarity[Data.Rarity]==nil then itemsByRarity[Data.Rarity]={} end
		table.insert(itemsByRarity[Data.Rarity],Name) 	
	end
	
	for i=1,2 do
		if i==2 and scanMore==true then BindingData = mw.loadData [[Module:Bindings/Data]] end
		--scans DB, adds items to itemsByTag
		for Name, Data in Shared.skpairs(BindingData or ItemData) do
			if i==1 then --creates all-items table
				addToItemsByRarity()
			end
			
			if type(Data.Tags)=='table' then for tagName, tagVal in pairs(Data.Tags) do
				if tagVal == true and tagStack[tagName] then
					--здесь добавтьб [i]
					if itemsByTag[tagStack[tagName]][tagName][Data.Rarity]==nil then
						itemsByTag[tagStack[tagName]][tagName][Data.Rarity]={}
					end
					table.insert(itemsByTag[tagStack[tagName]][tagName][Data.Rarity], Name)
				end
			end end
		end
	end
	--Draws navbox with All items
	Box:node(p.createNavCollapsible('All',
		Shared.drawTabber(itemsByRarity, p.fetchNavTable, rarityOrder, true)
	))
	--Draws nevboxes based on extracted tags
	for catName, catStack in Shared.skpairs(itemsByTag) do
		if Shared.tableCount(catStack)~=0 then
			Box:node(p.createNavCollapsible(catName,
				p.navboxByTag2(catName, catStack)
			))
		end
	end
	return Box
end


--recieves item name. Returns stack of navboxes generated for each positive item tag
--For use in Template:Vestige_navbox
function p.getNavboxesByItemName(Name)
	local Data = p.getItem(Name)
	if type(Data.Tags)~='table' then return end
	local Box = mw.html.create('div'):addClass('navbox tpl-navigation')
	local tagStack,itemsByTag, itemsByRarity = {}, {}, {}
	--extracts tags from Item
	for tagName, val in Shared.skpairs(Data.Tags) do
		if val==true then
			local catStack, catName = p.getTags(tagName)
			if catName and itemsByTag[catName]==nil then
				itemsByTag[catName]={}
				--extracts all tags required to be in a navbox
				for _, tagName in pairs(catStack) do
					tagStack[tagName] = tagStack[tagName] or catName
					if 	itemsByTag[catName][tagName]==nil then itemsByTag[catName][tagName]={} end
				end
			end
		end
	end
	--scans DB, adds items to itemsByTag
	for Name, Data in Shared.skpairs(ItemData) do
		if itemsByRarity[Data.Rarity]==nil then itemsByRarity[Data.Rarity]={} end
		table.insert(itemsByRarity[Data.Rarity],Name)
		
		if type(Data.Tags)=='table' then for tagName, tagVal in pairs(Data.Tags) do
			if tagVal == true and tagStack[tagName] then
				if itemsByTag[tagStack[tagName]][tagName][Data.Rarity]==nil then
					itemsByTag[tagStack[tagName]][tagName][Data.Rarity]={}
				end
				table.insert(itemsByTag[tagStack[tagName]][tagName][Data.Rarity], Name)
			end
		end end
	end
	--Draws navbox with All items
	Box:node(p.createNavCollapsible('All',
		Shared.drawTabber(itemsByRarity, p.fetchNavTable, rarityOrder, true)
	))
	--Draws nevboxes based on extracted tags
	for catName, catStack in Shared.skpairs(itemsByTag) do
		if Shared.tableCount(catStack)~=0 then
			Box:node(p.createNavCollapsible(catName,
				p.navboxByTag2(catName, catStack)
			))
		end
	end
	return Box
end

--creates collapsible shell for navboxes
function p.createNavCollapsible(catName,Content)
	local sysName = catName:gsub(' ','_')
	return mw.html.create():tag('div'):addClass('navbox-head mw-customtoggle-'..sysName)
			:attr('style','font-size: larger; cursor:pointer;'):wikitext((catName or tagName),' vestiges'):done()
			:tag('div'):addClass('mw-collapsible mw-collapsed'):attr('id','mw-customcollapsible-'..sysName)
				:node(Content):allDone()
end


--shell function, since Shared.drawTabber won't pass anything but the table
function p.fetchNavTable(stack)
	return p.drawTableByNames(stack,{mini=true})
end

function p.navboxByTag2(catName,navRender)
	local navReg = p.getTags(catName)
	if not navReg then return end
	if type(navRender)~='table' then
		navRender = {}
		for _, tabName in pairs(navReg) do
			navRender[tabName]=tabName
		end
	end
	return Shared.drawTabber(navRender, p.fetchNavTable, navReg, true)
end






--Shell-function for p.navboxByTag for external calls
function p._navboxByTag(frame)
	return	p.navboxByTag(frame.args[1])
end

function p.navboxByTag(catName,navRender)
	local navReg = p.getTags(catName)
	if not navReg then return end
	if type(navRender)~='table' then
		navRender = {}
		for _, tabName in pairs(navReg) do
			navRender[tabName]=tabName
		end
	end
	return Shared.drawTabber(navRender,p.createNavTabByTag,navReg,true)
end

function p._createNavTabByTag(frame)
	return	p.createNavTabByTag(frame.args[1])
end

function p.createNavTabByTag(target)
	local stack = {}
	if type(target)=='table' then
		stack = target
	elseif type(target)=='string' then
		for Name, Data in Shared.skpairs(ItemData) do
			if Data.Tags[target]==true then
				if Data.Rarity and not stack[Data.Rarity] then stack[Data.Rarity] = {} end
				table.insert(stack[Data.Rarity], Name)
				end
		end
	else return mw.html.create()
	end
	function createRow(row,tabName)
		local col = mw.html.create('td')
		for i, Name in Shared.skpairs(row) do
			col:node(p.drawItem(Name, Name, true))
			if i~=#row then col:wikitext(' • ') end
		end
			
		return mw.html.create('tr')
			:tag('th'):wikitext(tabName):done()
			:node(col):done()
	end
	local cart = mw.html.create('table'):addClass('wikitable')
	
	for rarityName, row  in Shared.ordpairs(stack,rarityOrder) do
		cart:node(createRow(row,rarityName))	
	end
	return cart:allDone()
end

--Draws a tabber sorted by rarities with all items in the database
function p.drawTabberRarities()
	local stack = {}
	for Name, Data in Shared.skpairs(ItemData) do
		if Data.Rarity and not stack[Data.Rarity] then stack[Data.Rarity] = {} end
		table.insert(stack[Data.Rarity], Name)
	end

	return Shared.drawTabber(stack,p.drawTableByNames,rarityOrder,true)
end

--draws a table of items with a specific rarity. 
function p.extPartTableRarities(frame)
	local targetRarity=toNil(frame.args[1])
	if not targetRarity then return "Error:No rarity provided. To use this function you must specify Common, Uncommon, Rare, Epic or Legendary." end
	local stack = {}
	
	for Name, Data in Shared.skpairs(ItemData) do
		if Data.Rarity==targetRarity then 
			table.insert(stack, Name)
		end
	end
	return p.drawTableByNames(stack,{Header=false})

end

--shell-function for drawTableTags for external calls
function p.extTableTags(frame)
	return p.drawTableTags(frame.args[1])
end

--Draws a tabber sorted by rarities with all items that contained requested tag
function p.drawTabberTags(target)
	local stack = {}
	for Name, Data in Shared.skpairs(ItemData) do
		if Data.Tags[target]==true then
			if Data.Rarity and not stack[Data.Rarity] then stack[Data.Rarity] = {} end
			table.insert(stack[Data.Rarity], Name)
			end
	end
	return Shared.drawTabber(stack,p.drawTableByNames,rarityOrder,true)
end


--------------------------------------------------------------------------------
--------------------------Core tables functions---------------------------------
--------------------------------------------------------------------------------
function p._drawTableByNames(frame)
	return p.drawTableByNames(frame.args,{Header=true})
end
function p.drawTableByNames(itemNames, args)--onlyRows,mini,customFunction)
	args = args or {}
	args.RowFunction = p.drawItemRow
	args.HeaderClass = 'wikitable navtable with-image vestige-table'
	args.NestedOrder = rarityOrder
	if args.Header==true then 
		args.Header = mw.html.create('table'):addClass('article-table navtable with-image vestige-table mw-collapsible'):tag('tr')
			:tag('th'):attr('colspan','2'):wikitext(args.colNames and args.colNames[1] or 'Vestige'):done()
			:tag('th'):wikitext(args.colNames and args.colNames[2] or'Sets'):done()
			:tag('th'):wikitext(args.colNames and args.colNames[3] or'Effect'):addClass('mobile-hidden'):done()
			:allDone()
	end
	return Shared.drawNavTable(itemNames,args)
end



--wraws one row for vestige-table containing Vestige image, Name, Stats and description
function p.drawItemRow(Name,args)
	local Data
	if type(Name)=='table' then
		Data = Name
		else
		Data = p.getItem(Name,args.isTrinket)
	end
	
	return mw.html.create('tr'):addClass(Data.Rarity)
				:addClass(Data.Updated==false and 'not-updated' or nil)
			:tag('td')
				:tag('span'):css('display','none'):wikitext('[[', Data.Link or Data.Name or Name or '', ']]<br>'):done()
				:wikitext('[[File:', Data.Image or (Data.Name or Name or '')..' wiki.png', '|',
				args.mini and '65px' or '100px',
				'|link=', Data.Link or Data.Name or Name or '', ']]')
			:done()
			:tag('td'):node(p.drawItem(Data,nil,true)):addClass('mobile-hidden'):done()
			:tag('td'):node(args.isTrinket and (Data.Locked==true and "Unlockable" or "Starter") or
							p.drawItemSets(Data.Sets,args.mini)):done()
			:tag('td')
				:tag('div'):addClass('version-reminder')
					:wikitext(Data.Updated==false and '[may not be updated for the latest patch] ' or nil):done()
				:node(Icons.convertTooltipText(Data.Desc,true)):done()
			:allDone()
end

--returns a line of item stats as icons, separated by <br>
function p.drawItemSets(Sets,skipNames)
	local temp = mw.html.create()
	if type(Sets)~='table' or Shared.tableCount(Sets)==0 then return '—' end
	for setName, val in Shared.skpairs(Sets) do
		if val == true then
			temp:node(Icons.Main(setName,setName)):css('display','inline-block')
				:newline()
		end
	end
	return temp
end

function p.drawItemStats(stats,skipNames)
	local temp = {}
	if type(stats)~='table' or Shared.tableCount(stats)==0 then return '—' end
	for _, Stat in pairs(stats) do
		if type(Stat)=='table' then
			local sign = type(Stat[2])=='number' and Stat[2]>=0 and '+' or ''
			table.insert(temp, sign..Stat[2]..' '..tostring(Icons.Main(Stat[1], skipNames and '' or Stat[1])))	
		end
	end
	return table.concat(temp,'<br>')
end

--------------------------------------------------------------------------------
------------------------------Core functions------------------------------------
--------------------------------------------------------------------------------

--takes tag name. Returns table with all tagNames of corresponding category
--as well as category name
function p.getTags(tagName)
	if NavData[tagName] and NavData[tagName][1] then
		return  NavData[tagName], tagName
	elseif (NavData[NavData[tagName]] and NavData[NavData[tagName]][1]) then
		return NavData[NavData[tagName]], NavData[tagName]
	elseif type(NavData[tagName])=='string' then
		return tagName, tagName
	else mw.log(tagName,'p.getTags - Not Found')
	end	
	return
end

--Returns Vestige from the database or creates a blank table
function p.getItem(Name,isTrinket)
	local Data = isTrinket and TrinketData or ItemData
	if Name then
		if not Data[Name] then
			Name = mw.text.decode(Name) --converts &#39; in PAGENAME into ' 
			Name = Shared.trim(Name) 
		end
		if not Data[Name] and Data[Shared.titleCase(Name)] then 
			Name = Shared.titleCase(Name)
		end
	end
	local Item = {Name=Name}
	setmetatable(Item, {__index = Data[Name]})
	--Name =  rawget(Item, 'Name')
	return Item
end

--Shell-function for p.drawItem for external calls
function p._drawItem(frame)
	return p.drawItem(toNil(frame.args[1]),toNil(frame.args[2]),toNil(frame.args[3])~=nil)
end

--Draws an inline string with item rarity icon, item name and tooltip
function p.drawItem(Name,displayName,noRarity)
	local Item
	if type(Name)=='table' then Item = Name else Item = p.getItem(Name) end
	return 	mw.html.create('span')
			:addClass('vestige-tooltip')
			:attr('data-param', Item.Name)
			:attr('data-param2', Item.Image or nil)
			:wikitext(noRarity~=true and Item.Rarity and ( '[[File:'..Item.Rarity..' icon.svg|20px|link=]] ') or nil)
				:tag('span'):addClass('dottedText')
				:wikitext('[[', Item.Link or Item.Name, '|', displayName or Item.Name, ']]'):allDone()
end

--------------------------------------------------------------------------------
---------------------------Miscellaneous functions------------------------------
--------------------------------------------------------------------------------

--drafts and bakes Vestiges into editable tables.
--call with {{subst:#invoke:Items|bakedTable}}
function p.bakedTable()
	local stack ={'<pre><nowiki>'}
	local order = {'Common','Uncommon','Rare','Epic','Legendary'}
	function ins(thing) table.insert(stack,thing) end
	function addHeader(rarity)
		ins('=='..rarity..'==')
		ins('{| class = "wikitable navtable with-image vestige-table"')
		ins('! colspan=2| Vestige')
		ins('! Stats')
		ins('! Effect')
	end
	function singlerow(Name)
		ins('|-')
		ins('{{VestHeader|'..Name..'}}')
		ins('| ')
		ins('| ')
	end
	local Items = {}
	for Name, Data in Shared.skpairs(ItemData) do
		if Data.Rarity and not Items[Data.Rarity] then Items[Data.Rarity] = {} end
		table.insert(Items[Data.Rarity], Name)
	end
	for _, Rarity in pairs(order) do
		addHeader(Rarity)	
		for _, Name in pairs(Items[Rarity]) do
			singlerow(Name)
		end
		ins('|}')
	end
	table.insert(stack,'</nowiki></pre>')
	return table.concat(stack,'\n')
end

--returns Vestige database report. Used on  Module:Items/Data/doc
function p.databaseStats()
	local itemCount = 0
	local tagList, Tags = {}, {}
	local itemList = {}
	
	function renderNames(nameStack,Rarity)
		local cart = mw.html.create('div'):addClass('mw-collapsible-content')
			
		for i, Name in pairs(nameStack) do
			cart:wikitext('[[',ItemData[Name].Link and ItemData[Name].Link..'|' or '', Name,']]')
			if i~=#nameStack then cart:wikitext(' • ') end
		end
		return mw.html.create('div'):addClass('mw-collapsible mw-collapsed')
				:tag('h2'):wikitext(Rarity):done()
				:node(cart):allDone()
	end
		
	for Name, Data in Shared.skpairs(ItemData) do
		if type(Data)=='table' then
			itemCount = itemCount + 1
			if itemList[Data.Rarity]==nil then itemList[Data.Rarity]={} end
			table.insert(itemList[Data.Rarity],Name)
			--tags
			for tagName in pairs(Data.Tags or {}) do
				if not tagList[tagName] then
					tagList[tagName] = 1
					else 
					tagList[tagName] = tagList[tagName] +1
				end
			end
		end
	end
	
	
	
	local cart = mw.html.create():wikitext('Database [[Module:Items/Data]] contains <b>'..itemCount..'</b> items and <b>'..Shared.tableCount(Tags)..'</b> tags.')
	for Rarity, nameStack in Shared.ordpairs(itemList,rarityOrder) do
		cart:node(renderNames(nameStack,Rarity))
	end
	
	local temp = mw.html.create()
	for tagName, count in Shared.skpairs(tagList) do
		temp:node(Icons.Main(tagName,tagName))
			:wikitext('(',count,')')
			:wikitext(' • ')
	end
	
	cart:tag('div'):addClass('mw-collapsible mw-collapsed')
		:tag('h2'):wikitext('Tags'):done()
		:tag('div'):addClass('mw-collapsible-content')
		:wikitext('Icons can be changed via [[Module:Icons/Data]]. <br>')
		:node(temp)
	:allDone()
	
	return cart
end

--Returns links to all vestiges, to rapidly create missing pages
function p.BotTest()
	local a = mw.html.create()
	for Name, Data in Shared.skpairs(ItemData) do
		a:wikitext('[[',Name,']] ')
	end
	return a
end

--counts tags and categories in Module:Item/Infoboxex
function p.countNavData()
	local tabs, tags = 0,0
	for catName, cat in pairs(NavData) do
		if type(cat)=='table' then 
			tabs = tabs+1
		else
			tags=tags+1
		end
	end
	mw.log(tabs,tags)
end

return p