UWAGA
Strona jest ponownie oddana do uzytku po zabiegach konfiguracyjnych. Jeśli zobaczą Państwo na niej jakieś błedy techniczne, prosimy o ich zgłoszenie.

Większość artykułów w portalu to nasze własne teksty z kluczowych dziedzin związanych z naszą misją. Spora część materiałów pochodzi też z polskiej wersji Wikipedii, gdzie były odrzucone ze względu na politykę redaktorów (przeczytaj o krytyce Wikipedii). Są też i takie, które zostały przeniesione na nasze strony, gdyż stanowią istotne uzupełnienie merytorycznej treści naszego serwisu. Wszystkie artykuły podlegają edycji przez naszych Użytkowników, dlatego ich wersje mogą się różnić od prezentowanych na innych witrynach.

Moduł:Navbox/diag

Z Wedapedia
Przejdź do nawigacji Przejdź do wyszukiwania

Dokumentacja dla tego modułu może zostać utworzona pod nazwą Moduł:Navbox/diag/opis

local res = mw.loadData('Moduł:Navbox/res')

local function fullMatch ( str )
	return '^'..mw.ustring.gsub( str, "([%(%)%.%%%+%-%*%?%[%^%$%]])", "%%%1" )..'$'
end

local function templateMatch ( name )
	local title = mw.title.new(name)
	local text = title.namespace ~= 10 and name or title.text
	return "{{%s*"..mw.ustring.gsub( text, "([%(%)%.%%%+%-%*%?%[%^%$%]])", "%%%1" ).."[%s|]"
end

local function loadKeys ( tab )
	local result = {}
	for k, v in pairs(tab) do
		table.insert(result, k)
	end
	
	return result
end

local function copySequenceExcept(tab, unwanted)
	local skip = {}
	if unwanted then
		for i, v in ipairs(unwanted) do
			skip[v] = true
		end
	end
	
	local result = {}
	for i, v in ipairs(tab) do
		if not skip[v] then
			table.insert(result, v)
		end
	end
	return result
end

local FindPositionsInReverseOrder = function(text, plainPattern)
	local result = {}
	if #plainPattern > 0 then
		local init = 1
		while init do
			init = string.find(text, plainPattern, init, true)
			if init then
				table.insert(result, 1, init)
				init = init + #plainPattern
			end
		end
	end
	
	return result
end

local RemoveInPlace = function(text, start, len)
	local before = start > 1 and string.sub(text, 1, start-1) or ""
	local stop = start + len
	local after = stop <= #text and string.sub(text, stop) or ""
	return before..string.rep("_", len)..after
end

local diag = {
	classStats = "navbox-statistics",
	categoryCSS = "[[Kategoria:Szablony nawigacyjne ze stylami]]",
	categoryProblems = "[[Kategoria:Szablony nawigacyjne – spisy do sprawdzenia]]",
	categorySuspected = "[[Kategoria:Szablony nawigacyjne – spisy podejrzane]]",
	categoryWikilinks0 = "[[Kategoria:Szablony nawigacyjne – spisy bez linków]]",
	categoryWikilinks1 = "[[Kategoria:Szablony nawigacyjne – tylko 1 link]]",
	categoryWikilinks2 = "[[Kategoria:Szablony nawigacyjne – tylko 2 linki]]",
	categoryWikilinks3 = "[[Kategoria:Szablony nawigacyjne – tylko 3 linki]]",
	categoryWikilinks4 = "[[Kategoria:Szablony nawigacyjne – tylko 4 linki]]",
	categoryLargeList = "[[Kategoria:Szablony nawigacyjne – ponad 500 pozycji]]",
	categoryUnknownArgs = "[[Kategoria:Szablony nawigacyjne – nieznane parametry]]",
	categoryManyColumns = "[[Kategoria:Szablony nawigacyjne – dużo kolumn]]",
	categoryVertical = "[[Kategoria:Szablony nawigacyjne – pionowe]]",
	categoryBadName = "[[Kategoria:Szablony nawigacyjne ze złym parametrem nazwa]]",
	categoryNavboxInside = "[[Kategoria:Szablony nawigacyjne – zagnieżdżone]]",
	categoryAnonymousLists = "[[Kategoria:Szablony nawigacyjne – nieopisane spisy]]",
	categoryCheckWikicode = "[[Kategoria:Szablony nawigacyjne – wikikod do sprawdzenia]]",
	categoryUnusedArgs = "[[Kategoria:Szablony nawigacyjne – nieużywane parametry]]",
	categoryUnverifiedArgs = "[[Kategoria:Szablony nawigacyjne – nieprawidłowe parametry]]",
	categoryMissingArgs = "[[Kategoria:Szablony nawigacyjne – brakujące parametry]]",
	categoryEmptyArgs = "[[Kategoria:Szablony nawigacyjne – puste parametry]]",
	categoryMissingWikilink = "[[Kategoria:Szablony nawigacyjne – spis bez linków]]",
	listItem = "^[%*#:]",
	wikilink = "%[%[ *%S[^\r\n]- *%]%]",
	problemIndicator = '<sup class="problemy-w-navbox problemy">?</sup>',
	suspectedIndicator = '<sup class="suspected problemy">!</sup>',
	navboxInside = '^<([a-z]+) class="navbox ',

	-- wzory wyrażeń regularnych
	verificators = {
		["nazwa"] = {
			inverted = true,
			patterns = {
				"[%c#%[%]%{%}|<>_\127]", -- niedozwolone znaki
				"^:", -- artykuły?
				"^%.$",
				"^%.%.$",
				"^%./",
				"^%.%./",
				"/%./",
				"/%.%./",
				"/%.$",
				"/%.%.$",
				"~~+",
			},
		},
	
		["tytuł"] = {
			inverted = true,
			patterns = {
				-- pliki
				"%[%[ *[Pp][Ll][Ii][Kk] *:.-%]%]",
				"%[%[ *[Ff][Ii][Ll][Ee] *:.-%]%]",
				-- listy
				"^[%*#:]",
				"\n[%*#:]",
			},
		},
	
		["klasa"] = {
			inverted = false,
			patterns = {
				"^[%w%-_ ]+$",
			},
		},
	
		["lista"] = {
			inverted = false,
			patterns = {
				"^[%*#:]",
				"\n[%*#:]",
			},
		},
	
		["tekst lub lista"] = {
			inverted = false,
			patterns = {
				"%S", -- cokolwiek byle nie pusto
			},
		},
	
		["grafika"] = {
			inverted = false,
			patterns = {
				"%[%[ *[Pp][Ll][Ii][Kk] *:.-%]%]",
				"%[%[ *[Ff][Ii][Ll][Ee] *:.-%]%]",
				"%[%[ *[Gg][Rr][Aa][Ff][Ii][Kk][Aa] *:.-%]%]",
			},
		},
	
		["zwijanie"] = {
			inverted = false,
			patterns = {
				fullMatch(res.arg.collapsible.collapsed),
				fullMatch(res.arg.collapsible.expanded),
				fullMatch(res.arg.collapsible.auto),
				fullMatch(res.arg.collapsible.disabled),
			},
		},
	},
	
	statsMessage = "Pozycje linkujące:&nbsp;$1, specjalne:&nbsp;$2, problemy$3:&nbsp;$4, '''RAZEM:&nbsp;$5'''",
	suspectedMessage = " (podejrzane$1:&nbsp;$2)",
	
	templateCats = {
		args = { "kategoria", "kategoria2", "kategoria3", "kategoria4", "kategoria5", "kategoria6", },
		ns = "Kategoria",
		prefix = "Szablony nawigacyjne - ",
		default = "Kategoria:Szablony nawigacyjne",
		disabled = "nie",
	},

	sourceCatsPatterns = {
		"%[%[ *[Kk][Aa][Tt][Ee][Gg][Oo][Rr][Ii][Aa] *: *([^|%[%]]-) *|[^|%[%]]-%]%]",
		"%[%[ *[Kk][Aa][Tt][Ee][Gg][Oo][Rr][Ii][Aa] *: *([^|%[%]]-) *%]%]",
		"%[%[ *[Cc][Aa][Tt][Ee][Gg][Oo][Rr][Yy] *: *([^|%[%]]-) *|[^|%[%]]-%]%]",
		"%[%[ *[Cc][Aa][Tt][Ee][Gg][Oo][Rr][Yy] *: *([^|%[%]]-) *%]%]",
	},
	
	brPattern = "<[bB][Rr] ?/?>",
	suspectedText = {
		'•', '&bull;', '&#x2022;', '&#8226;',
		'·', '&middot;', '&#xB7;', '&#183;',
		'∙', '&#x2219;', '&#8729;',
	},

	brackets = {
		pattern = "[%(%)%[%]]",
		['('] = ')',
		['['] = ']',
		[')'] = '(',
		[']'] = '[',
	}
}

local function printStatistics(builder, diagItems)
	local wikilinks = 0
	local nowikis = 0
	local problems = 0
	local suspected = 0
	for k, v in pairs(diagItems) do
		wikilinks = wikilinks + v.wikilinks
		nowikis = nowikis + v.nowikis
		problems = problems + v.problems
		suspected = suspected + v.suspected
	end
	--local lang = mw.getContentLanguage()
	local message = mw.message.newRawMessage(diag.statsMessage)
		:numParams(wikilinks, nowikis)
		:rawParams(diag.problemIndicator)
		:numParams(problems, wikilinks + nowikis + problems)
	local report = builder:tag('div')
		:addClass(diag.classStats)
		:wikitext(message:plain())
	if suspected > 0 then
		local message = mw.message.newRawMessage(diag.suspectedMessage)
			:rawParams(diag.suspectedIndicator)
			:numParams(suspected)
		report:wikitext(message:plain())
	end

	report:wikitext(problems > 0 and diag.categoryProblems or nil)
	report:wikitext(suspected > 0 and diag.categorySuspected or nil)

	if wikilinks == 0 then
		report:wikitext(diag.categoryWikilinks0)
	elseif wikilinks == 1 then
		report:wikitext(diag.categoryWikilinks1)
	elseif wikilinks == 2 then
		report:wikitext(diag.categoryWikilinks2)
	elseif wikilinks == 3 then
		report:wikitext(diag.categoryWikilinks3)
	elseif wikilinks == 4 then
		report:wikitext(diag.categoryWikilinks4)
	elseif (wikilinks + nowikis + problems) > 500 then
		report:wikitext(diag.categoryLargeList)
	end
end

local function printListWithoutWikilinks(report, diagItems)
	local nowikilinks = {}
	for k, v in pairs(diagItems) do
		if (v.wikilinks <= 0) and mw.ustring.match(k, '^'..res.arg.list.name..'%d') then
			table.insert(nowikilinks, k)
		end
	end
	if #nowikilinks > 0 then
		report:newline():wikitext("; brak wikilinków: ", #nowikilinks, diag.categoryMissingWikilink)
		for i, v in ipairs(nowikilinks) do
			report:newline():wikitext(":* ", v)
		end
	end
end

local function printNested(report, diagItems)
	--mw.logObject(diagItems, "nested")
	local nested = {}
	for k, v in pairs(diagItems) do
		if v.inside then
			table.insert(nested, k)
		end
	end
	if #nested > 0 then
		report:newline():wikitext("; zagnieżdżone szablony nawigacyjne: ", #nested, diag.categoryNavboxInside)
		for i, v in ipairs(nested) do
			report:newline():wikitext(":* ", v)
		end
	end
end

local function printWikicodeAnalyze(report)
	local contents = mw.title.getCurrentTitle():getContent()
	--mw.logObject(contents, 'contents')
	local text = contents or "" -- pusty tekst jeśli nie ma strony
	-- gumkowanie
	text = string.gsub(text, "<!%-%-.-%-%->", '')
	text = string.gsub(text, "<nowiki>.-</nowiki>", '')
	text = string.gsub(text, "<math>.-</math>", '')
	text = string.gsub(text, "<pre>.-</pre>", '')
	text = string.gsub(text, "<noinclude>.-</noinclude>", '')
	text = string.gsub(text, "<includeonly>(.-)</includeonly>", '%1')
	--mw.logObject(text, 'text')
	
	local cleanContents = text
	-- wikilinki iteracyjnie od końca
	for _, startPos in ipairs(FindPositionsInReverseOrder(text, "[[")) do
		local endPos = string.find(text, "]]", startPos, true)
		if endPos then
			local eol = string.find(text, "\n", startPos, true)
			if eol and (eol < endPos) then
				endPos = nil
			end
		end
		
		local len = endPos and (endPos - startPos + 2) or 2
		text = RemoveInPlace(text, startPos, len)
	end

	local paramPos = {}
	local templPos = {}
	local ob = string.byte('{')
	local cb = string.byte('}')
	for _, startPos in ipairs(FindPositionsInReverseOrder(text, "{{")) do
		local endPos = string.find(text, "}}", startPos, true)
		local len = endPos and (endPos - startPos + 2) or 2
		local sPos = startPos
		if (startPos > 1) and ((startPos + len) <= #text) and (string.byte(text, startPos + 2) == ob) and (string.byte(text, startPos + len) == cb) then
			-- parametr szablonu
			len = len + 1
			paramPos[startPos] = len
		elseif len ~= 2 then
			templPos[startPos] = len
		end
		
		-- usuń szablony zawarte wewnątrz znaleziska
		local inside = {}
		local ePos = sPos + len
		for s, l in pairs(templPos) do
			local e = s + l
			if (s > sPos) and (s < ePos) and (e > sPos) and (e < ePos) then
				table.insert(inside, s)
			end
		end
		for i, v in ipairs(inside) do
			templPos[v] = nil
		end
		
		-- zarejestruj pozycję znaleziska
		text = RemoveInPlace(text, sPos, len)
	end
	
	local notFound = 10000000000
	
	local params = {}
	for k, v in pairs(paramPos) do
		local e1 = string.find(cleanContents, "|", k, true) or notFound
		local e2 = string.find(cleanContents, "\n", k, true) or notFound
		local e3 = string.find(cleanContents, "}}}", k, true) or notFound
		local e = math.min(e1, e2, e3)
		assert(e < notFound)
		assert(e > (k + 2))
		local paramname = mw.text.trim(string.sub(cleanContents, k + 3, e - 1))
		params[paramname] = true
	end
	local paramnames = loadKeys(params)

	local templates = {}
	for k, v in pairs(templPos) do
		local e1 = string.find(cleanContents, "|", k, true) or notFound
		local e2 = string.find(cleanContents, "\n", k, true) or notFound
		local e3 = string.find(cleanContents, "}}", k, true) or notFound
		local e = math.min(e1, e2, e3)
		local p1 = false
		if (e3 < notFound) and (e1 < e3) then
			local e11 = string.find(cleanContents, "|", e1 + 1, true) or e3
			p1 = mw.text.trim(string.sub(cleanContents, e1+1, e11-1))
		end
		assert(e < notFound)
		assert(e > (k + 2))
		local templateName = mw.text.trim(string.sub(cleanContents, k + 2, e - 1))
		local invokeName = mw.ustring.match(templateName, "^#invoke:%s*(.+)$")
		if invokeName and p1 then
			templateName = "#invoke:"..mw.title.new(invokeName, "Module").text..'|'..p1
		end
		table.insert(templates, {
			start = k,
			len = v,
			name = templateName,
		})
	end
	
	report:newline():wikitext("; definicja szablonu")
	if #templates == 1 then
		local template = templates[1]
		report:newline():wikitext(":"):tag('code'):wikitext(template.name)
		if template.start > 1 then
			local before = mw.text.nowiki(mw.text.trim(string.sub(cleanContents, 1, template.start - 1)))
			if #before > 0 then
				report:newline():wikitext(": znaleziono treść przed szablonem")
					:newline():wikitext(":*"):tag('code'):wikitext(before)
			else
				report:newline():wikitext(": znaleziono odstęp przed szablonem")
			end
			report:wikitext(diag.categoryCheckWikicode)
		end
		local endPos = template.start + template.len
		--mw.logObject(endPos, 'endPos')
		--mw.logObject(#cleanContents, '#cleanContents')
		if (endPos == #cleanContents) and (string.sub(cleanContents, endPos, endPos) == '\n') then
			report:newline():wikitext(": znaleziono znak nowej linii za szablonem")
		elseif endPos <= #cleanContents then
			local after = mw.text.nowiki(mw.text.trim(string.sub(cleanContents, endPos)))
			if #after > 0 then
				report:newline():wikitext(": znaleziono treść za szablonem")
					:newline():wikitext(":*"):tag('code'):wikitext(after)
			else
				report:newline():wikitext(": znaleziono odstęp za szablonem")
			end
			report:wikitext(diag.categoryCheckWikicode)
		end
	elseif #templates < 1 then
		local text = mw.text.trim(cleanContents)
		if #text > 0 then
			report:newline():wikitext(": znaleziono jakąś treść zamiast szablonu")
		else
			report:newline():wikitext(": nie znaleziono żadnego szablonu")
		end
		report:wikitext(diag.categoryCheckWikicode)
	else
		report:newline():wikitext(": znaleziono wywołanie wielu szablonów", diag.categoryCheckWikicode)
		for i, t in ipairs(templates) do
			report:newline():wikitext(":*"):tag('code'):wikitext(t.name)
		end
	end
	if #paramnames > 0 then
		report:newline():wikitext("; wykryto parametry")
		for i, v in ipairs(paramnames) do
			report:newline():wikitext(':'):tag('code'):wikitext(v)
		end
	end
end

local function printTemplateCategories(report, categories)
	local pagename = mw.title.getCurrentTitle().text
	report:newline():wikitext("; zadeklarowane kategorie: ")
	if categories == false then
		report:wikitext("''wyłączone''")
	else
		local count = 0
		for k, v in pairs(categories) do
			count = count + 1
		end
		
		if count <= 0 then
			report:wikitext("''brak''", '[[', diag.templateCats.default, '|', pagename, ']]')
		else
			report:wikitext(count)
			local nameIndex = mw.ustring.len(diag.templateCats.ns)
				+ mw.ustring.len(diag.templateCats.prefix)
				+ 2
			for v, s in pairs(categories) do
				report:newline():wikitext(':*', mw.ustring.sub(v, nameIndex), '[[', v, '|', s, ' ]]')
				if #s == 0 then
					report:wikitext(' '):tag('small'):wikitext('(pusty klucz)')
				elseif s ~= pagename then
					report:wikitext(' '):tag('small'):wikitext('(klucz: ', s, ')')
				end
			end
		end
	end
end

local function printSourceCategories(report)
	
	local function print(description, content)
		if not content then
			return
		end
		
		local categories = {}
		for i, pattern in ipairs(diag.sourceCatsPatterns) do
			for c in mw.ustring.gmatch(content, pattern) do
				local title = mw.title.makeTitle(diag.templateCats.ns, c)
				if title then
					table.insert(categories, title.text)
				end
			end
		end
	
		report:newline():wikitext("; ", description, " : ", #categories)
		for i, v in ipairs(categories) do report:newline():wikitext(':*', v) end
	end
	
	local content = mw.title.getCurrentTitle():getContent() or ""
	print('kategorie w kodzie', content)
	local docTitle = mw.title.getCurrentTitle():subPageTitle(res.aux.docSubpageText)
	if docTitle and docTitle.exists then
		print('kategorie w dokumentacji', docTitle:getContent())
	end
	local otherDoc = mw.ustring.match(content, "{{ *[Dd]okumentacja *| *([^|%[%]]-/opis) *}}")
	if otherDoc then
		local otherDocTitle = mw.title.new(otherDoc)
		if otherDocTitle then
			print('kategorie w dołączonej dokumentacji', otherDocTitle:getContent())
		end
	end
end

local function printLogSummary(report, printlog)
	if printlog.levels then
		report:newline():wikitext("; głębokość drzewa :", printlog.levels)
	end
	if printlog.leafs then
		report:newline():wikitext("; liczba liści :", printlog.leafs)
	end
	if printlog.notree then
		report:newline():wikitext("; drzewo : ''nie''")
	end
	if printlog.example then
		report:newline():wikitext("; przykład : ''tak''")
	end
	if printlog.pionowy then
		report:wikitext(diag.categoryVertical)
	end
	if printlog.cols then
		report:newline():wikitext("; liczba kolumn :", printlog.cols)
		if printlog.cols > 3 then
			report:wikitext(diag.categoryManyColumns)
		end
	end
	if printlog.allCols then
		report:newline():wikitext("; liczba wszystkich komórek kolumnowych :", printlog.allCols)
	end
	if printlog.templateClassName then
		report:newline():wikitext("; prywatny CSS")
		report:newline():wikitext(": ", printlog.templateClassName)
		if printlog.privateCSS then
			report:newline():wikitext(": [[", printlog.privateCSS, "|styles.css]]", diag.categoryCSS)
		end
	end
	if printlog.unknownClasses then
		report:newline():wikitext("; nieużywane klasy", diag.categoryUnknownArgs)
		for i, v in ipairs(printlog.unknownClasses) do
			report:newline():wikitext(": ", #v <= 0 and "''pusta''" or v)
		end
	end
end

local function printEmptyArguments(report, argsTree)
	local result = {}
	for k, v in pairs(argsTree.args) do
		if not v.value or (#v.value <= 0) then
			table.insert(result, k)
		end
	end
	
	if #result <= 0 then
		return
	end
	
	report:newline():wikitext("; puste pola", diag.categoryEmptyArgs)
	for i, v in ipairs(result) do
		report:newline():wikitext(": ", v)
	end
end

local function printUnverifiedArguments(report, argsTree)
	local result = {}
	for k, v in pairs(argsTree.args) do
		if argsTree.used[k] and not v.verified then
			table.insert(result, k)
		end
	end
	
	if #result <= 0 then
		return
	end
	
	report:newline():wikitext("; nieprawidłowe pola", diag.categoryUnverifiedArgs)
	for i, v in ipairs(result) do
		report:newline():wikitext(": ", v)
	end
end

local function printUnknownArguments(report, argsTree)
	local result = {}
	for k, v in pairs(argsTree.args) do
		if not v.recognized and not v.obsolete and not argsTree.used[k] then
			table.insert(result, k)
		end
	end
	
	if #result <= 0 then
		return
	end
	
	report:newline():wikitext("; nieznane pola", diag.categoryUnknownArgs)
	for i, v in ipairs(result) do
		report:newline():wikitext(": ", v)
	end
end

local function printUnusedArguments(report, argsTree)
	local result = {}
	local cat = false
	for k, v in pairs(argsTree.args) do
		if (#v.value > 0) and not argsTree.used[k] and (v.recognized or v.obsolete) then
			cat = k ~= res.arg.collapsible.name -- omiń ponad 10k wywołań
			table.insert(result, k)
		end
	end
	
	if #result <= 0 then
		return
	end
	
	report:newline():wikitext("; nieużywane pola", cat and diag.categoryUnusedArgs or '')
	for i, v in ipairs(result) do
		report:newline():wikitext(": ", v)
	end
end

local function printMissingArguments(report, missing)
	local result = {}
	for k, v in pairs(missing) do
		table.insert(result, k)
	end
	
	if #result <= 0 then
		return
	end
	
	report:newline():wikitext("; brakujące pola", diag.categoryMissingArgs)
	for i, v in ipairs(result) do
		report:newline():wikitext(": ", v)
	end
end

local function printTestListDescriptions(report, tree)
	
	local direct = {}
	local parent = {}
	
	local function argName(node)
		local address = string.sub(node.address(), 2)
		return res.arg.list.name..string.gsub(address, '_', '.')
	end
	
	local function parseNode(node)
		if #node <= 0 then
			-- liści nie obrabiamy
			return
		end
		
		local suspected = {}
		for i, n in ipairs(node) do
			if not n.peek(res.arg.group.name) and n.peek(res.arg.list.name) then
				table.insert(suspected, i)
			end
		end
		
		if #suspected > 1 then
			for i, v in ipairs(suspected) do
				table.insert(direct, argName(node[v]))
			end
		elseif (#suspected > 0) and node.address() and not node.peek(res.arg.group.name) then
			table.insert(parent, argName(node[suspected[1]]))
		end
		
		for i, n in ipairs(node) do
			parseNode(n)
		end
	end

	parseNode(tree)
	if (#direct <= 0) and (#parent <= 0) then
		return
	end
	
	if #direct > 0 then
		report:newline():wikitext("; nieopisany spis w grupie", diag.categoryAnonymousLists)
		for i, v in ipairs(direct) do
			report:newline():wikitext(": ", v)
		end
	end
	
	if #parent > 0 then
		report:newline():wikitext("; zagnieżdżony nieopisany spis", diag.categoryAnonymousLists)
		for i, v in ipairs(parent) do
			report:newline():wikitext(": ", v)
		end
	end
end

local function formatArgs(args)
	local padindex = '................................................'
	local orders = {
		["nazwa"]    = { p = 'A', s = '1', n = ' ', },
		["tytuł"]    = { p = 'A', s = '2', n = ' ', },
		["klasa"]    = { p = 'A', s = '3', n = ' ', },
		["góra"]     = { p = 'B', s = '1', n = '\n', },
		["przed"]    = { p = 'C', s = '1', n = ' ', },
		["po"]       = { p = 'C', s = '2', n = ' ', },
		["grafika"]  = { p = 'C', s = '3', n = ' ', },
		["opis"]     = { p = 'D', s = '1', n = ' ', },
		["zwijanie"] = { p = 'D', s = '2', n = ' ', },
		["spis"]     = { p = 'D', s = '3', n = '\n', },
		["dół"]      = { p = 'E', s = '1', n = '\n', },
		[false]      = { p = 'Z', s = '1', n = ' ', },
	}
	local list = {}
	local i = 0
	for k, v in pairs(args) do
		i = i + 1
		local prefix, suffix = mw.ustring.match(k, "^(.-)([1-9][%.0-9]*)$")
		if not prefix then
			prefix = k
			suffix = padindex
		else
			suffix = string.sub(suffix..padindex, 1, #padindex)
		end
		
		local ord = orders[prefix] or orders[false]
		local item = {
			o = string.format('%s-%s-%s-%08d', ord.p, suffix, ord.s, i),
			k = k,
			v = v,
			n = ord.n,
		}
		table.insert(list, item)
	end
	
	table.sort(list, function(a,b) return a.o < b.o end)
	local result = {}
	for i, v in ipairs(list) do
		table.insert(result, '| '..v.k..' ='..v.n..v.v..(v.n == '\n' and v.n or ''))
	end
	
	return table.concat(result, '\n')
end

local function verify(argInfo)
	local verificator = diag.verificators[argInfo.recognized]
	if verificator then
		argInfo.verified = verificator.inverted
		for i, v in ipairs(verificator.patterns) do
			if mw.ustring.match(argInfo.value, v) then
				argInfo.verified = not verificator.inverted
				break
			end
		end
	end
end

local function testBrackets(text)
	local stack = {}
	for b in mw.ustring.gmatch(text, diag.brackets.pattern) do
		if (b == '(') or (b == '[') then
			table.insert(stack, b)
		elseif (b == ')') or (b == ']') then
			if (#stack > 0) and stack[#stack] == diag.brackets[b] then
				table.remove(stack, #stack)
			else
				return false -- brak otwartego nawiasu
			end
		end
	end
		
	return #stack == 0 -- oczekiwane zamknięte wszystkie nawiasy
end

local function check(text, br)
	local lines = mw.text.split(text, '\n', true)
	local wikilinks = 0
	local nowikis = 0
	local problems = 0
	local suspected = 0
	local result = {}
	for i, v in ipairs(lines) do
		local t = v
		if not mw.ustring.match(v, diag.listItem) then
			-- to nie jest wikilista
		elseif mw.ustring.match(v, diag.wikilink) then
			wikilinks = wikilinks + 1
		elseif string.match(v,'\127') then
			-- nowiki, ref, etc
			nowikis = nowikis + 1
		else
			problems = problems + 1
			t = v..diag.problemIndicator
		end
		
		if br and mw.ustring.match(v, diag.brPattern) then
			suspected = suspected + 1
			t = t..diag.suspectedIndicator
		elseif not testBrackets(v) then
			suspected = suspected + 1
			t = t..diag.suspectedIndicator
		else
			-- zamieniam wikilinki na tekst do testowania
			local s, c = string.gsub(v, "%[%[.-|(.-)%]%]", "%1") -- nie patrz w linki
			local s, c = string.gsub(s, "%[%[[^|\n%[%]]+%]%]", "ok") -- lub zamień je na dobry tekst
			for i, p in ipairs(diag.suspectedText) do
				if mw.ustring.match(s, p, 1, true) then
					suspected = suspected + 1
					t = t..diag.suspectedIndicator
					break
				end
			end
		end

		table.insert(result, t)
	end
	
	return {
		value = table.concat(result,'\n'),
		wikilinks = wikilinks,
		nowikis = nowikis,
		problems = problems,
		suspected = suspected,
		inside = string.match(lines[1], diag.navboxInside) and true or false,
	}
end

local function argsService(templateContext)
	local argsTree = {
		args = {},
		missing = {},
		used = {},
		diag = {},
	}
	
	local staticArgs = {}
	local dynamicArgs = {}
	for k, v in pairs(res.arg) do
		if templateContext and templateContext.aliases then
			local alias = templateContext.aliases[v.name]
			if v.static and alias then staticArgs[alias] = v.static end
			if v.dynamic and alias then dynamicArgs[alias] = v.dynamic end
		end
		if v.static then staticArgs[v.name] = v.static end
		if v.dynamic then dynamicArgs[v.name] = v.dynamic end
		if v.template and templateContext then staticArgs[v.name] = v.template end
	end
	
	local function add(k, v, prefix)
		--mw.logObject({k, v, prefix}, "analyzeArg")
		local argInfo = {
			value = v,
			recognized = staticArgs[k] or (prefix and dynamicArgs[prefix])
		}
		if argInfo.recognized then
			verify(argInfo)
		elseif templateContext and templateContext.obsolete then
			argInfo.obsolete = prefix and templateContext.obsolete[prefix]
				or (templateContext.obsolete[k] == false)
		end
		argsTree.args[k] = argInfo
		--mw.logObject(argInfo, k)
	end

	local peekName = function(name)
		if (not argsTree.args[name] or (#argsTree.args[name].value <= 0)) and templateContext and templateContext.aliases then
			local alias = templateContext.aliases[name]
			if alias and argsTree.args[alias] and (#argsTree.args[alias].value > 0) then
				return alias
			end
		end
		
		return name
	end

	local function peek(name)
		--mw.logObject(name, "peek")
		local name = peekName(name)
		local arg = argsTree.args[name]
		return (arg and (#arg.value > 0)) and arg.value or nil
	end
	
	local function use(name)
		local name = peekName(name)
		local arg = argsTree.args[name]
		local result = arg and arg.value or nil
		--mw.logObject({name, result}, "use")
		argsTree.used[name] = (argsTree.used[name] or 0) + 1
		return result
	end
	
	local function get(name)
		local name = peekName(name)
		local result = use(name)
		if result == nil then
			argsTree.missing[name] = (argsTree.missing[name] or 0) + 1
			result = res.aux.missingArgNamePrefix..name..res.aux.missingArgNameSuffix
		elseif not argsTree.diag[name] then
			local br = mw.ustring.match(name, '^'..res.arg.list.name..'%d')
			argsTree.diag[name] = check(result, br)
			result = argsTree.diag[name].value
		end
		--mw.logObject({name, result}, "get")
		return result
	end
	
	local function dump()
		local buffer = {}
		for k, v in pairs(argsTree.args) do
			buffer[k] = v.value
		end
		return mw.text.jsonEncode(buffer)
	end
	
	local function loadTemplateCategories()
		local pagename = mw.title.getCurrentTitle().text
		local map = {}
		for i, argName in ipairs(diag.templateCats.args) do
			if i > 1 then -- piersza inaczej
				local catName = peek(argName)
				if catName and (#catName > 0) then
					local name, sort = mw.ustring.match(catName, "^(.-)%s*|%s*(.*)$")
					if not name then
						name = catName
						sort = pagename
					end
					local categoryTitle = mw.title.makeTitle(diag.templateCats.ns, diag.templateCats.prefix..name)
					if categoryTitle and (#categoryTitle.fragment <= 0) and not map[categoryTitle.fullText] then
						use(argName)
						argsTree.args[argName].verified = true
						map[categoryTitle.fullText] = sort
					end
				end
			end
		end
	
		local cat1arg = diag.templateCats.args[1]
		local cat1 = peek(cat1arg)
		if cat1 == diag.templateCats.disabled then
			use(cat1arg)
			argsTree.args[cat1arg].verified = true
			for k, v in pairs(map) do
				return map
			end
			
			return false
		end
		
		if cat1 and (#cat1 > 0) then
			local name, sort = mw.ustring.match(cat1, "^(.-)%s*|%s*(.*)$")
			if not name then
				name = cat1
				sort = pagename
			end
			local categoryTitle = mw.title.makeTitle(diag.templateCats.ns, diag.templateCats.prefix..name)
			if categoryTitle and (#categoryTitle.fragment <= 0) and not map[categoryTitle.fullText] then
				use(cat1arg)
				argsTree.args[cat1arg].verified = true
				map[categoryTitle.fullText] = sort
			end
		end
		
		return map
	end

	local function diagnosticView (builder, printlog, tree)
		printStatistics(builder, argsTree.diag)
		local summaryReport = mw.html.create('div')
			:addClass('navbox-summary')
			:addClass("mw-collapsible mw-collapsed")
		summaryReport:tag('div')
			:addClass('title')
			:wikitext('Informacje diagnostyczne')
		local report = summaryReport:tag('div')
			--:addClass('hlist')
			:addClass('mw-collapsible-content')
		if printlog.badName then
			report:wikitext(diag.categoryBadName)
		end
		printWikicodeAnalyze(report)
		if printlog.useTemplateCategories then
			printTemplateCategories(report, loadTemplateCategories())
		end
		printSourceCategories(report)
		report:newline():wikitext('----')
		printLogSummary(report, printlog)
		report:newline():wikitext('----')
		printListWithoutWikilinks(report, argsTree.diag)
		printEmptyArguments(report, argsTree)
		printUnverifiedArguments(report, argsTree)
		printUnusedArguments(report, argsTree)
		printUnknownArguments(report, argsTree)
		printMissingArguments(report, argsTree.missing)
		printNested(report, argsTree.diag)
		if tree then
			printTestListDescriptions(report, tree)
		end
		
		local argsReport = ''
		local formattedArgs = formatArgs(mw.text.jsonDecode(dump()))
		if formattedArgs and (#formattedArgs > 0) then
			local report = mw.html.create('div')
				:addClass('navbox-summary')
				:addClass("mw-collapsible mw-collapsed")
			report:tag('div')
				:addClass('title')
				:wikitext('Kanoniczne zestawienie parametrów')
			local content = mw.getCurrentFrame():extensionTag('pre', formattedArgs, {class='mw-collapsible-content'})
			report:wikitext(content)
			argsReport = tostring(report)
		end

		local navbox = tostring(builder)
		local details = tostring(summaryReport)
		local catReport = ''
		
		local function hideCategories()
			local currentTitle = mw.title.getCurrentTitle()
			if currentTitle.isTalkPage then
				return true
			elseif currentTitle.namespace ~= 2 then
				return false
			else -- Wikipedysta - może programista?
				local navboxDeveloper = mw.title.makeTitle(2, currentTitle.rootText..'/navbox-developer')
				return not navboxDeveloper or not navboxDeveloper.exists
			end
		end
		
		if hideCategories() then
			local categories = {}
			local function extractCategories(text)
				local function foundCat(category)
					table.insert(categories, category)
					return ''
				end
				local t1, c1 = mw.ustring.gsub(text, diag.sourceCatsPatterns[1], foundCat)
				local t2, c2 = mw.ustring.gsub(t1, diag.sourceCatsPatterns[2], foundCat)
				return t2
			end
			navbox = extractCategories(navbox)
			details = extractCategories(details)
			if #categories > 0 then
				local report = mw.html.create('div')
					:addClass('navbox-summary')
					:addClass("mw-collapsible mw-collapsed")
				report:tag('div')
					:addClass('title')
					:wikitext('Kategorie')
				local content = report:tag('div')
					:addClass('mw-collapsible-content')
				for i, v in ipairs(categories) do
					content:newline():wikitext('*', '[[:Kategoria:', v, ']]')
				end
				content:newline()
				catReport = tostring(report)
			end
		end

		local result = navbox..details..argsReport..catReport
		return result
	end

	return {
		add = add,
		peek = peek,
		use = use,
		get = get,
		dump = dump,
		diagnosticView = diagnosticView,
	}
end

return {
	
argsService = argsService,

diagnosticView = function(builder, args, printlog)
	return args.diagnosticView(builder, printlog, args.tree and args.tree() or nil) 
end,

verifyTemplateName = function(currentTitle, expectedTitle, templateName)
	local content = currentTitle:getContent()
	if not content then
		mw.log("Navbox:verifyTemplateName: brak zawartości strony")
		return false
	end

	mw.logObject(templateName, "Navbox:verifyTemplateName: templateName")
	local navboxTemplate = templateMatch(templateName)
	mw.logObject(navboxTemplate, "Navbox:verifyTemplateName: navboxTemplate")
	local s, e = mw.ustring.find(content, navboxTemplate, 1)
	if not s then
		mw.log("Navbox:verifyTemplateName: myślę, że jest ok, bo tu nie widzę kodu szablonu nawigacyjnego")
		return true
	end

	local exists1 = function(pattern)
		local s, e = mw.ustring.find(content, pattern, s)
		if not s then
			return 0
		end
		
		local s, e = mw.ustring.find(content, pattern, e)
		if not s then
			return 1
		end
		
		return 2
	end
	
	if 1 == exists1("|%s*nazwa%s*=%s*{{%s*#invoke:Navbox%s*|%s*Name%s*}}%s*[|}]") then
		mw.log("Navbox:verifyTemplateName: myślę, że jest ok, automatyczna nazwa jest tylko raz -> true")
		return true
	end
	
	mw.logObject(expectedTitle, "Navbox:verifyTemplateName: zadeklarowana nazwa w szablonie")
	mw.logObject(currentTitle, "Navbox:verifyTemplateName: obrabiana strona")
	-- w naszym szablonie oczekuję jednej nazwy
	-- w przeciwnym razie nie oczekuję żadnej nazwy
	local expectedCount = mw.title.equals(currentTitle, expectedTitle) and 1 or 0
	mw.logObject(expectedCount, "Navbox:verifyTemplateName: oczekiwana liczba wystąpień podanej nazwy w szablonie")
	local name = mw.ustring.gsub(expectedTitle.text, "([%(%)%.%%%+%-%*%?%[%^%$%]])", "%%%1" );
	local pattern = ((expectedTitle.namespace == 10) or (0 < exists1("|%s*przestrzeń%s*=%s*"..expectedTitle.nsText.."%s*[|}]")))
		and ("|%s*nazwa%s*=%s*"..name.."%s*[|}]") -- zwykła nazwa (w szablonie lub jawnie zadeklarowanej przestrzeni)
		or ("|%s*nazwa%s*=%s*"..expectedTitle.nsText..":"..name.."%s*[|}]") -- pełna nazwa (w szablonie w innej przestrzeni)
	mw.logObject(pattern, "Navbox:verifyTemplateName: szukam nazwy w szablonie według wzoru")
	local count = exists1(pattern)
	mw.logObject(count, "Navbox:verifyTemplateName: liczba wyników wyszukiwania")
	return expectedCount == count
end,

}