Notice: Template failed integrity check: /home/jvzmxxx/wiki/extensions/MobileFrontend/includes/skins/minerva.mustache in /home/jvzmxxx/wiki/includes/TemplateParser.php on line 121
Moduł:Cytuj – Czarnobyl Wiki
Otwórz menu główne

Czarnobyl Wiki β

Moduł:Cytuj

Wersja z dnia 20:09, 4 cze 2016 autorstwa Paweł Ziemian (dyskusja) (kategorie techniczne tylko w przestrzeni głównej)
(różn.) ← poprzednia wersja | przejdź do aktualnej wersji (różn.) | następna wersja → (różn.)

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

Błąd skryptu: Błąd Lua: Błąd wewnętrzny: Proces interpretera został zakończony z sygnałem "-129".

local resources = {
	modes = { "auto", "książkę", "pismo", "stronę" },
	
	COinS = {
		false,                          -- auto
		"info:ofi/fmt:kev:mtx:book",    -- książkę
		"info:ofi/fmt:kev:mtx:journal", -- pismo
		"info:ofi/fmt:kev:mtx:journal", -- stronę
	},

	categories = {
		empty = "[[Kategoria:Szablon cytowania bez parametrów]]",
		undetermined = "[[Kategoria:Szablon cytowania bez określonego trybu]]",
		missingArg = "[[Kategoria:Szablon cytowania w trybie 'cytuj %s' bez obowiązkowych parametrów]]",
		suspectedComma = "[[Kategoria:Szablon cytowania zawiera przecinek w polu z opisem autora]]",
		unusedUrl = "[[Kategoria:Szablon cytowania zawiera nieużywany URL]]",
		unusedPublished = "[[Kategoria:Szablon cytowania zawiera pola 'opublikowany' i 'wydawca']]",
		sameJournalAndPublished = "[[Kategoria:Szablon cytowania zawiera identyczne pola 'czasopismo' i 'opublikowany']]",
	},
	
	--[[
	; name : name of the parameter used in the template
	; used : indicator whether the parameter is used in specific citation mode
		list of modes is declared in variable 'modes' at the top of the module
		the first entry is reserved for automatic full citation mode, which accepts all parameters
		; "!" : mandatory
		; false : not used
		; ''otherwise'' : optional
			; "+" : only in one mode, and written differently for easier notice
			; "*" : additional support in the code (in url and published for now)
	--]]
	params = {
		chapterauthor = {
			name = "autor r",
			used = { true, "+", false, false, },
		},
		chapter = {
			name = "rozdział",
			used = { true, "+", false, false, },
		},
		author = {
			name = "autor",
			used = { true, true, true, true, },
		},
		editor = {
			name = "redaktor",
			used = { true, true, true, true, },
		},
		url = {
			name = "url",
			used = { true, true, true, "*", },
		},
		title = {
			name = "tytuł",
			used = { true, "!", true, "!", },
		},
		others = {
			name = "inni",
			used = { true, "+", false, false, },
		},
		work = {
			name = "praca",
			used = { true, false, false, "+", },
		},
		journal = {
			name = "czasopismo",
			used = { true, false, "!", false, },
		},
		mediatype = {
			name = "typ nośnika",
			used = { true, true, true, true, },
		},
		responsibility = {
			name = "odpowiedzialność",
			used = { true, false, "+", false, },
		},
		issue = {
			name = "wydanie",
			used = { true, true, true, false, },
		},
		description = {
			name = "opis",
			used = { true, "+", false, false, },
		},
		place = {
			name = "miejsce",
			used = { true, true, true, false, },
		},
		published = {
			name = "opublikowany",
			used = { true, "*", "*", "*", },
		},
		publisher = {
			name = "wydawca",
			used = { true, true, true, false, },
		},
		date = {
			name = "data",
			used = { true, true, true, true, },
		},
		p = {
			name = "s",
			used = { true, true, true, true, },
		},
		doi = {
			name = "doi",
			used = { true, true, true, false, },
		},
		isbn = {
			name = "isbn",
			used = { true, "+", false, false, },
		},
		lccn = {
			name = "lccn",
			used = { true, "+", false, false, },
		},
		issn = {
			name = "issn",
			used = { true, true, true, false, },
		},
		pmid = {
			name = "pmid",
			used = { true, false, "+", false, },
		},
		pmc = {
			name = "pmc",
			used = { true, false, "+", false, },
		},
		bibcode = {
			name = "bibcode",
			used = { true, false, "+", false, },
		},
		oclc = {
			name = "oclc",
			used = { true, true, true, false, },
		},
		arxiv = {
			name = "arxiv",
			used = { true, false, false, true, },
		},
		id = {
			name = "id",
			used = { true, true, true, true, },
		},
		accessdate= {
			name = "data dostępu",
			used = { true, true, true, true, },
		},
		archive = {
			name = "archiwum",
			used = { true, true, true, true, },
		},
		archived = {
			name = "zarchiwizowano",
			used = { true, true, true, true, },
		},
		quotation = {
			name = "cytat",
			used = { true, true, true, true, },
		},
		lang = {
			name = "język",
			used = { true, true, true, true, },
		},
		odn = {
			name = "odn",
			used = { true, true, true, true, },
		},
	},

	monthparser = {
		["styczeń"] = 1,      ["stycznia"] = 1,      ["sty"] = 1,  ["i"] = 1,
		["luty"] = 2,         ["lutego"] = 2,        ["lut"] = 2,  ["ii"] = 2,
		["marzec"] = 3,       ["marca"] = 3,         ["mar"] = 3,  ["iii"] = 3,
		["kwiecień"] = 4,     ["kwietnia"] = 4,      ["kwi"] = 4,  ["iv"] = 4,
		["maj"] = 5,          ["maja"] = 5,                        ["v"] = 5,
		["czerwiec"] = 6,     ["czerwca"] = 6,       ["cze"] = 6,  ["vi"] = 6,
		["lipiec"] = 7,       ["lipca"] = 7,         ["lip"] = 7,  ["vii"] = 7,
		["sierpień"] = 8,     ["sierpnia"] = 8,      ["sie"] = 8,  ["viii"] = 8,
		["wrzesień"] = 9,     ["września"] = 9,      ["wrz"] = 9,  ["ix"] = 9,
		["październik"] = 10, ["października"] = 10, ["paź"] = 10, ["x"] = 10,
		["listopad"] = 11,    ["listopada"] = 11,    ["lis"] = 11, ["xi"] = 11,
		["grudzień"] = 12,    ["grudnia"] = 12,      ["gru"] = 12, ["xii"] = 12,
	},

	months = {
		[1]  = { m="styczeń",     d="stycznia", },
		[2]  = { m="luty",        d="lutego", },
		[3]  = { m="marzec",      d="marca", },
		[4]  = { m="kwiecień",    d="kwietnia", },
		[5]  = { m="maj",         d="maja", },
		[6]  = { m="czerwiec",    d="czerwca", },
		[7]  = { m="lipiec",      d="lipca", },
		[8]  = { m="sierpień",    d="sierpnia", },
		[9]  = { m="wrzesień",    d="września", },
		[10] = { m="październik", d="października", },
		[11] = { m="listopad",    d="listopada", },
		[12] = { m="grudzień",    d="grudnia", },
	},
	
	exactAuthors = {
		["Praca zbiorowa"] = true,
		["[[Gall Anonim]]"] = true,
	}
}

local function softNoWiki(text)
	local result, count = string.gsub(text, "['%[%]{|}\"]", { ["\""] = """, ["'"] = "'", ["["] = "[", ["]"] = "]", ["{"] = "{", ["|"] = "|", ["}"] = "}"})
	return result
end

local function escapeUrl(url)
	local result, count = string.gsub(url, "[ '%[%]]", { [" "] = "%20", ["'"] = "%27", ["["] = "%5B", ["]"] = "%5D"})
	return result
end

local function plainText(text)
	local result, count = string.gsub(text, "</?[Ss][Pp][Aa][Nn][^>]*>", "")
	return result
end

local function determineMode(p)
	local detector = {}
	local count = 0
	for i, v in ipairs(resources.modes) do
		detector[i] = v
		count = count + 1
	end
	
	detector[1] = false -- skip 'auto'
	count = count - 1
	for k, v in pairs(resources.params) do
		local arg = p.args[v.name]
		for i, w in ipairs(v.used) do
			if not w and arg then
				-- unexpected argument
				if detector[i] then
					detector[i] = false
					count = count - 1
					if count == 0 then
						-- the mode cannot be determined
						break
					end
				end
			end
		end
		if count == 0 then
			-- the mode cannot be determined
			break
		end
	end

	for i, v in ipairs(detector) do
		if detector[i] then
			-- the type is succesfully determined
			-- but in case more than one is possible
			-- use only the first one
			-- include COinS format if this is the only determined type
			return i, count == 1 and resources.COinS[i] or false
		end
	end

	-- in case nothing is selected
	-- use the auto mode as default fallback
	return 1
end

local authorMetatable = {}
local authorMethodtable = {}

authorMetatable.__index = authorMethodtable

local function checkPatterns(author, prefixes, suffixes)
	if author.exact then
		return false
	end
	
	if author.prefix and prefixes then
		for _, v in ipairs(prefixes) do
			if mw.ustring.match(author.prefix, v) then
				return true
			end
		end
	end
	
	if author.suffix and suffixes then
		for _, v in ipairs(suffixes) do
			if mw.ustring.match(author.suffix, v) then
				return true
			end
		end
	end

	return false
end

authorMethodtable.isIlustrator = function(author)
	return checkPatterns(author, {"il%.?", "ilus%.?", "ilustrator" }, {"[%(%[]il%.?[%)%]]", "[%(%[]ilus%.?[%)%]]", "[%(%[]ilustrator[%)%]]" })
end

authorMethodtable.isTranslator = function(author)
	return checkPatterns(author, {"tłum%.?", "tłumacz" }, {"[%(%[]tłum%.?[%)%]]", "[%(%[]tłumacz[%)%]]" })
end

authorMethodtable.isEditor = function(author)
	return checkPatterns(author, {"red%.?", "redaktor", "pod red%.?", "pod redakcją" }, {"[%(%[]red%.?[%)%]]", "[%(%[]redaktor[%)%]]" })
end

authorMethodtable.isDeveloper = function(author)
	return checkPatterns(author, {"oprac%.?", "opracowała?" }, {"[%(%[]oprac%.?[%)%]]", "[%(%[]opracowała?[%)%]]" })
end

authorMethodtable.format = function(data, namefirst)
	if data.exact then
		return data.exact
	end

	if namefirst and data.familynamefirst then
		namefirst = false
	end
	
	local builder = mw.html.create()
	local name = data.name and (#data.name > 0)
	local initials = data.nameinitials and (#data.nameinitials > 0)
	local namehint = nil
	if name and initials and (data.name ~= data.nameinitials) then
		namehint = data.name
	end
	
	if not data.familynamefirst and (name or initials) then
		local before = namefirst and builder or builder:tag("span"):addClass("cite-name-before")
		if name then
			before:tag("span"):addClass("cite-name-full"):wikitext(softNoWiki(data.name))
		end
		if initials then
			before:tag("span"):addClass("cite-name-initials"):attr("title", namehint):wikitext(softNoWiki(data.nameinitials))
		end
		before:wikitext("&nbsp;")
	end

	builder:tag("span"):addClass("cite-lastname"):wikitext(softNoWiki(data.lastname))

	if not namefirst and (name or initials) then
		local after = data.familynamefirst and builder or builder:tag("span"):addClass("cite-name-after")
		after:wikitext("&nbsp;")
		if name then
			after:tag("span"):addClass("cite-name-full"):wikitext(softNoWiki(data.name))
		end
		if initials then
			after:tag("span"):addClass("cite-name-initials"):attr("title", namehint):wikitext(softNoWiki(data.nameinitials))
		end
	end
	
	return tostring(builder)
end

authorMethodtable.towiki = function(data)
	if data.exact then
		return data.exact
	end

	local result = {}
	local name = data.name and (#data.name > 0)
	if not data.familynamefirst and name then
		table.insert(result,softNoWiki(data.name))
		table.insert(result, " ")
	end
	
	table.insert(result, softNoWiki(data.lastname))

	if data.familynamefirst and name then
		table.insert(result, " ")
		table.insert(result, softNoWiki(data.name))
	end

	return table.concat(result)
end

local function makeInitials(name)
	local nameinitials = mw.ustring.gsub(name, "(%w[Hh]?)([%w%-%.]+)%s*", "%1. ")
	nameinitials = mw.ustring.gsub(nameinitials, "%f[%w]%l%.%s", "")
	nameinitials = mw.ustring.gsub(nameinitials, "([^C%W])[Hh]%.%s", "%1. ")
	return mw.text.trim(nameinitials)
end

local function parseAuthor(author)
	local result = {}
	
	local author = mw.text.trim(author)
	if resources.exactAuthors[author] then
		result.exact = author
		setmetatable(result, authorMetatable)
		return result
	end

	local exactName = mw.ustring.match(author, "^%s*%*%s*(.*)$")
	if exactName then
		result.exact = mw.text.trim(exactName)
		if #result.exact == 0 then
			return nil
		end
		
		setmetatable(result, authorMetatable)
		return result
	end

	local prefix0, link, description, suffix0 = mw.ustring.match(author, "^(.-)%[%[(.-)%|(.-)%]%](.*)$")
	if prefix0 then
		result.link = link
		author = description
	else
		prefix0, link, suffix0 = mw.ustring.match(author, "^(.-)%[%[(.-)%]%](.*)$")
		if prefix0 then
			author = link
			result.link = link
		else
			prefix0 = ""
			suffix0 = ""
		end
	end

	local prefix, rest = mw.ustring.match(author, "^([%l%p%s]+)(.+)$")
	if not prefix then
		rest = author
		prefix = ""
	end

	prefix = mw.text.trim(prefix0.." "..prefix)
	if #prefix > 0 then
		if mw.ustring.sub(prefix, -1) == "#" then
			result.familynamefirst = true
			prefix = mw.text.trim(mw.ustring.match(prefix, "^(.-)#$"))
		end
		if #prefix > 0 then
			result.prefix = mw.ustring.gsub(prefix, "%s+", " ") -- collapse spaces
		end
	end

	local rest2, suffix = mw.ustring.match(rest, "^([%w%-%.%s]-)%s([%l%p%s]-)$")
	if not suffix then
		rest2 = rest
		suffix = ""
	end
	
	suffix = mw.text.trim(suffix.." "..suffix0)
	if #suffix > 0 then
		result.suffix = mw.ustring.gsub(suffix, "%s+", " ") -- collapse spaces
	end
	
	local lastname, name = mw.ustring.match(rest2, "%s*([^,]-)%s*,%s*(.-)%s*$")
	if not lastname then
		if result.familynamefirst then
			lastname, name = mw.ustring.match(rest2, "%s*(%u[%l%d%p]*)%s+(.-)%s*$")
		else
			name, lastname = mw.ustring.match(rest2, "%s*(.-)%s+(%u[%w%p]-)%s*$")
		end
	end
	
	if not lastname then
		result.lastname = mw.text.trim(rest2)
	else
		result.name = name
		result.lastname = lastname
		result.nameinitials = makeInitials(name)
	end
	
	if #result.lastname == 0 then
		return nil
	end
	
	setmetatable(result, authorMetatable)
	return result
end

local function parseDate(date, month, year, patch)
	local result = {}
	
	-- parse full date
	local y, m, d = false, false, false
	y, m, d = mw.ustring.match(date, "(%d%d%d%d)[%-%s%./](%d%d?)[%-%s%./](%d%d?)")
	
	if y and patch and (date == (y.."-01-01")) then
		result.year = tonumber(y)
		result.month = false
		result.day = false
		return result, true
	end
	
	if not y then
		d, m, y = mw.ustring.match(date, "(%d%d?)[%-%s%.](%d%d?)[%-%s%.](%d%d%d%d)")
		if not y then
			y, m, d = mw.ustring.match(date, "(%d%d%d%d)%s*(%w+)%s*(%d%d?)")
			if not y then
				d, m, y = mw.ustring.match(date, "(%d%d?)%s*(%w+)%s*(%d%d%d%d)")
			end
			if m then
				m = resources.monthparser[mw.ustring.lower(m)]
				if not m then
					y = false
					m = false
					d = false
				end
			end
		end
	end

	if y then
		y = tonumber(y)
		m = tonumber(m)
		d = tonumber(d)
	end
	if y and ((d > 31) or (m > 12) or (d < 1) or (m < 1)) then 
		y = false
		m = false
		d = false
	elseif y then
		result.year = y
		result.month = m
		result.day = d
		return result, false
	end
	
	-- parse year and month
	y, m = mw.ustring.match(date, "(%d%d%d%d)[%-%s%./](%d%d?)")
	if not y then
		m, y = mw.ustring.match(date, "(%d%d?)[%-%s%./](%d%d%d%d)")
		if not y then
			y, m = mw.ustring.match(date, "(%d%d%d%d)%s*(%w+)")
			if not y then
				m, y = mw.ustring.match(date, "(%w+)%s*(%d%d%d%d)")
			end
			if m then
				m = resources.monthparser[mw.ustring.lower(m)]
				if not m then
					y = false
					m = false
				end
			end
		end
	end
	if y then
		y = tonumber(y)
		m = tonumber(m)
	end
	if y and ((m > 12) or (m < 1)) then 
		y = false
		m = false
	elseif y then
		result.year = y
		result.month = m
		return result, false
	end
	
	-- try any method to extract year or month
	if not y then
		y = mw.ustring.match(date, "[%s%p%-–]?(%d%d%d%d)[%s%p%-–]?")
		if y then
			y = tonumber(y)
		end
		if y then
			result.year = y
		end
	end

	if y then
		if not m then
			m = mw.ustring.match(date, "[%s%p%-–]?(%w+)[%s%p%-–]?")
			if m then
				m = resources.monthparser[mw.ustring.lower(m)]
			end
			if m then
				result.month = m
			end
		end
	else
		-- reset only month
		result.month = nil
	end
	
	if y then
		return result, false
	end
end

local function loadAuthor(frame, params, index)
	local argAuthor = formatDynamicArgName(params.author.name, index)

	local result = false
	local author = frame.args[argAuthor]
	if author and (#author > 0) then
		result = parseAuthor(author)
	end

	if not result then
		return
	end

	local first = frame.args[argFirst]
	if first and (#first > 0) then
		result.name = first
		result.nameinitials = makeInitials(first)
	end
	
	local link = frame.args[argLink]
	if link and (#link > 0) then
		result.link = link
	end
	
	return result
end

local function collectAuthors(author)
	if not author then
		return
	end
	
	local result = {}
	local splitter = string.match(author, ";") and ";" or ","
	local authors = mw.text.split(author, splitter, true)
	for _, v in ipairs(authors) do
		local author = parseAuthor(v)
		if author then
			table.insert(result, author)
		end
	end

	if #result == 0 then
		return
	end
	
	return result, (#result == 2) and (separator == ",")
end
	
local function formatAuthors(authors, useDecorations, nextgroup)
	local count = #authors
	if count == 0 then
		return nil
	end
	
	local formatter = function(author)
		local a = author:format(nextgroup)
		local r = author.link and ("[["..author.link.."|"..a.."]]") or a
		local s = useDecorations and (author:isEditor() and " (red.)" or (author:isTranslator() and " (tłum.)" or (author:isIlustrator() and " (ilust.)" or (author:isDeveloper() and " (oprac.)" or "")))) or ""
		return r..s
	end
	
	if count == 1 then
		return formatter(authors[1])
	end
	
	local result = {}
	table.insert(result, formatter(authors[1]))
	
	if count <= 3 then
		table.insert(result, ", ");
		table.insert(result, formatter(authors[2]))
		if count == 3 then
			table.insert(result, ", ");
			table.insert(result, formatter(authors[3]))
		end
		
		return table.concat(result, "")
	end
	
	table.insert(result, "<span class=\"cite-more-full\">")
	local title = {}
	for i = 2, count do
		table.insert(result, ", ");
		table.insert(result, formatter(authors[i]))
		table.insert(title, authors[i]:towiki())
	end
	table.insert(result, "</span>")
	table.insert(result, "<span class=\"cite-at-al\" title=\"")
	table.insert(result, table.concat(title, ", "))
	table.insert(result, "\"> i inni</span>")
	return table.concat(result, "")
end

local function collectLanguages(value)
	if value then
		local result = {}
		local values = mw.text.split(value, "%s+")
		for _, v in ipairs(values) do
			if #v > 0 then
				table.insert(result, v)
			end
		end
	
		if #result > 0 then
			return result
		end
	end

	return nil
end

local function splitWikiLink(text)
	local link, description = mw.ustring.match(text, "^%[%[(.-)%|(.-)%]%]$")
	if link then
		return description, link, false
	end
	
	local link = mw.ustring.match(text, "^%[%[(.-)%]%]$")
	if link then
		return link, link, false
	end
	
	local link, description = mw.ustring.match(text, "^%[([hH][tT][tT][pP][sS]?://%S*)%s+(.-)%]$")
	if link then
		return description, false, link
	end
	
	return text, false, false
end

local function detectArchive(url)
	local y, m, d, link = mw.ustring.match(url, "^https?://web%.archive%.org/web/(%d%d%d%d)(%d%d)(%d%d)%d%d%d%d%d%d/(https?://.*)$")
	if y then
		return link, y.."-"..m.."-"..d
	end
	
	return false, false
end

local function loadCitation(frame, mode)
	local result = {}

	-- copy parameters
	for k, v in pairs(resources.params) do
		if v.used[mode] then
			local value = frame.args[v.name]
			if value then
				value = mw.text.trim(value)
				if #value > 0 then
					result[k] = value
				end
			end
		
			if (v.used[mode] == "!") and not result[k] then
				-- simulate missing mandatory parameter
				result[k] = "{{{"..v.name.."}}}"
				if not result.missing then
					result.missing = v.name
				end
			end
		end
	end

	-- translate some parameters
	result.chapterauthor, result.chapterComma = collectAuthors(result.chapterauthor)
	result.author, result.authorComma = collectAuthors(result.author)
	result.lang = collectLanguages(result.lang)
	result.editor, result.editorComma = collectAuthors(result.editor)
	result.others, result.othersComma = collectAuthors(result.others)

	local yearRange = false
	if result.date and mw.ustring.match(result.date, "[12]%d%d%d[-–—][12]%d%d%d") then
		yearRange = result.date
	end
	
	result.date, result.patchCitoidDate = parseDate(result.date or "", false, false, true)
	if result.date then
		result.year = tostring(result.date.year)
		result.yearRange = yearRange
	end

	-- fix other dates
	result.accessdate = parseDate(result.accessdate or "", false, false, false)
	if result.accessdate and not result.accessdate.day then
		result.accessdate = nil
	end

	-- allow more ISBN numbers
	if result.isbn then
		-- TODO allow "(info)" for custom description followed each identifier
		result.isbn = mw.text.split(result.isbn, "%s+")
	end
	
	if result.title then
		local url
		result.title, result.titlelink, url = splitWikiLink(result.title)
		if url or result.titlelink then
			if result.url and (#result.url > 0) and (result.url ~= "{{{url}}}") then
				mw.logObject(result.url, "UNUSED URL")
				result.urlWarning = true
			end
			
			result.url = url
		end
	end
	if result.chapter then
		result.chapter, result.chapterlink, result.chapterurl = splitWikiLink(result.chapter)
	end
	if result.journal then
		result.journal, result.journallink, result.journalurl = splitWikiLink(result.journal)
	end

	if not result.archive and result.url then
		local al, ad = detectArchive(result.url)
		if al then
			result.archive = result.url
			result.url = al
			if ad then result.archived = ad end
		end
	elseif result.archive and (not result.url or not result.archived) then
		local al, ad = detectArchive(result.archive)
		if al and not result.url then result.url = al end
		if ad and not result.archived then result.archived = ad	end
	end

	result.archived = parseDate(result.archived or "", false, false, false)
	if result.archived and not result.archived.day then
		result.archived = null
	end

	if result.issue and result.journal then
		local volume, issue = mw.ustring.match(result.issue, "^%s*([^%(]+)%s+%((.-)%)%s*$");
		if volume then
			result.journalvolume = volume
			result.issue = issue
		end
	end

	-- return collected parameters if there is any	
	for k, v in pairs(result) do
		return result
	end
	
	-- there are no supported parameters
	return nil
end

local function prepareOdnIdentifier(data)
	if not data.odn or (#data.odn == 0) or (data.odn == "nie") then
		return nil
	end

	data.diferentiator = mw.ustring.match(data.odn, "^([a-z])$") or false
	
	if data.odn ~= "tak" and not data.diferentiator then
		-- TODO return only CITEREF...
		return data.odn
	end
	
	local authors = data.chapterauthor or data.author or data.editor
	if not authors then
		-- required custom identifier
		return nil
	end
	
	return "CITEREF"
		.. (authors[1] and (authors[1].lastname or authors[1].exact) or "")
		.. (authors[2] and (authors[2].lastname or authors[2].exact) or "")
		.. (authors[3] and (authors[3].lastname or authors[3].exact) or "")
		.. (authors[4] and (authors[4].lastname or authors[4].exact) or "")
		.. (data.date and data.date.year or "")
		.. (data.diferentiator or "")
end

local function bookCOinS(data)
	local authors = data.chapterauthor or data.author
	local result = {}
	result["rft_val_fmt"] = "info:ofi/fmt:kev:mtx:book"
	if data.chapter and (#data.chapter > 0) then
		result["rft.gengre"] = "bookitem"
		result["rft.atitle"] = plainText(data.chapter)
		result["rft.btitle"] = plainText(data.title)
	elseif data.work and (#data.work > 0) then
		result["rft.gengre"] = "bookitem"
		result["rft.atitle"] = plainText(data.title)
		result["rft.btitle"] = plainText(data.work)
	else
		result["rft.btitle"] = plainText(data.title)
		result["rft.gengre"] = "book"
	end
	if authors then
		if authors[1].lastname then result["rft.aulast"] = authors[1].lastname end
		if authors[1].name then result["rft.aufirst"] = authors[1].name end
		if authors[1].exact then result["rft.au"] = authors[1].exact end
	end
	if data.date then
		result["rft.date"] = data.date.day and string.format("%04d-%02d-%02d", data.date.year, data.date.month, data.date.day) 
			or (data.date.month and string.format("%04d-%02d", data.date.year, data.date.month) or data.date.year)
	end
	if data.issue then result["rft.edition"] = data.issue end
	if data.publisher then result["rft.pub"] = data.publisher end
	if data.place then result["rft.place"] = data.place end
	if data.pages then result["rft.pages"] = data.pages end
	if data.isbn then result["rft.isbn"] = data.isbn[1] end
	if data.issn then result["rft.issn"] = data.issn end
	
	local params = {
		"ctx_ver=Z39.88-2004",
		mw.uri.buildQueryString(result),
	}

	if data.oclc then table.insert(params, mw.uri.buildQueryString( {rft_id = "info:oclcnum/"..data.oclc})) end
	if data.doi then table.insert(params, mw.uri.buildQueryString( {rft_id = "info:doi/"..data.doi})) end
	if data.url then table.insert(params, mw.uri.buildQueryString( {rft_id = data.url})) end
	if data.pmid then table.insert(params, mw.uri.buildQueryString( {rft_id = "info:pmid/"..data.pmid})) end
	if data.lccn then table.insert(params, mw.uri.buildQueryString( {rft_id = "info:lccn/"..data.lccn})) end
		
	local coinsData = table.concat(params, "&")
	return coinsData;
end

local function journalCOinS(data)
	local result = {}
	result["rft_val_fmt"] = "info:ofi/fmt:kev:mtx:journal"
	local gengre = (data.arxiv and (#data.arxiv > 0)) and "preprint" or "article"
	result["rft.gengre"] = data.title and gengre or "journal"
	if data.title then result["rft.atitle"] = plainText(data.title) end
	result["rft.jtitle"] = plainText(data.journal)
	if data.chapter then result["rft.atitle"] = plainText(data.chapter) end
	if data.date then
		result["rft.date"] = data.date.day and string.format("%04d-%02d-%02d", data.date.year, data.date.month, data.date.day) 
			or (data.date.month and string.format("%04d-%02d", data.date.year, data.date.month) or data.date.year)
	end
	if data.title and author then
		if author[1].lastname then result["rft.aulast"] = author[1].lastname end
		if author[1].name then result["rft.aufirst"] = author[1].name end
		if author[1].exact then result["rft.au"] = author[1].exact end
	end
	if data.journalvolume then result["rft.volume"] = data.journalvolume end
	if data.issue then result["rft.edition"] = data.issue end
	if data.publisher then result["rft.pub"] = data.publisher end
	if data.place then result["rft.place"] = data.place end
	if data.pages then result["rft.pages"] = data.pages end
	if data.issn then result["rft.issn"] = data.issn end
	
	local params = {
		"ctx_ver=Z39.88-2004",
		mw.uri.buildQueryString(result),
	}

	if data.pmid then table.insert(params, mw.uri.buildQueryString( {rft_id = "info:pmid/"..data.pmid})) end
	if data.pmc then table.insert(params, mw.uri.buildQueryString( {rft_id = "info:pmc/"..data.pmc})) end
	if data.doi then table.insert(params, mw.uri.buildQueryString( {rft_id = "info:doi/"..data.doi})) end
	if data.url then table.insert(params, mw.uri.buildQueryString( {rft_id = data.url})) end
		
	local coinsData = table.concat(params, "&")
	return coinsData;
end

local function webCOinS(data)
	local result = {}
	result["rft_val_fmt"] = "info:ofi/fmt:kev:mtx:journal"
	result["rft.gengre"] = "unknown"
	if data.title then result["rft.atitle"] = plainText(data.title) end
	result["rft.jtitle"] = plainText(data.published)
	if data.date then
		result["rft.date"] = data.date.day and string.format("%04d-%02d-%02d", data.date.year, data.date.month, data.date.day) 
			or (data.date.month and string.format("%04d-%02d", data.date.year, data.date.month) or data.date.year)
	end
	if data.title and author then
		if author[1].lastname then result["rft.aulast"] = author[1].lastname end
		if author[1].name then result["rft.aufirst"] = author[1].name end
		if author[1].exact then result["rft.au"] = author[1].exact end
	end
	local params = {
		"ctx_ver=Z39.88-2004",
		mw.uri.buildQueryString(result),
	}

	if data.url then table.insert(params, mw.uri.buildQueryString( {rft_id = data.url})) end
		
	local coinsData = table.concat(params, "&")
	return coinsData;
end

local function COinS(data, coinsFormat)
	if (coinsFormat == "info:ofi/fmt:kev:mtx:book") and data.title and (#data.title > 0) then
		-- title is mandatory element for books
		return bookCOinS(data)
	elseif coinsFormat == "info:ofi/fmt:kev:mtx:journal" and data.journal and (#data.journal > 0) and (not data.published or (data.journal ~= data.published)) then
		-- journal title is mandatory element for journals
		return journalCOinS(data)
	elseif coinsFormat == "info:ofi/fmt:kev:mtx:journal" and data.published and (#data.published > 0) then
		return webCOinS(data)
	elseif data.title and (#data.title > 0) then
		-- treat web or unrecognized citations as book
		return bookCOinS(data)
	else
		return false
	end
end

local function Cite(p, mode)
	-- debug helper
	if p.args[3] then mw.log(p.args[3]) end

	-- try to determine type basing on passed parameters
	local coinsFormat = resources.COinS[mode]
	if not mode then
		mode, coinsFormat = determineMode(p)
	end
	
	local data = loadCitation(p, mode)
	if not data then
		return resources.categories.empty
	end
	if data.missing then
		-- do not produce any COiNS info
		-- if some mandatory argument is missing
		coinsFormat = false
	end

	local builder = mw.html.create("span")
	builder
		:addClass("citation")
		:attr("id", prepareOdnIdentifier(data))

	local needDot = false
	local nextAuthorGroup = false
	if data.title then
		
		if data.chapter then
			local authors = data.editor and data.author or data.chapterauthor
			if authors then
				builder:wikitext(formatAuthors(authors, false, nextAuthorGroup), ", ")
				nextAuthorGroup = true
			end
			
			local title = softNoWiki(data.chapter)
			if data.chapterurl then
				builder:wikitext("[", escapeUrl((not data.url and data.archive) and data.archive or data.chapterurl), " ''", title, "'']")
			elseif data.chapterlink then
				builder:wikitext("[[", data.chapterlink, "|''", title, "'']]")
			else
				builder:wikitext("''", title, "''")
			end
			
			if not mw.ustring.match(plainText(data.chapter), ",$") then
				builder:wikitext(",")
			end

			builder:wikitext(" [w:] ")
		end

		local authors = false
		local editor = false
		if not data.chapter and data.author then
			authors = data.author
		else
			authors = data.editor or data.author
			editor = data.editor
		end
		if authors then
			builder:wikitext(formatAuthors(authors, not (editor or false), nextAuthorGroup))
			nextAuthorGroup = true
			if editor then
				builder:wikitext(" (red.)")
			end
			builder:wikitext(", ")
		end
	
		local title = softNoWiki(data.title)
		if data.url then
			builder:wikitext("[", escapeUrl(data.archive or data.url), " ''", title, "'']")
		elseif data.titlelink then
			builder:wikitext("[[", data.titlelink, "|''", title, "'']]")
		else
			builder:wikitext("''", title, "''")
		end
		if not mw.ustring.match(plainText(title), "%p$") then
			needDot = true
		end

		local showmediatype = data.mediatype and (#data.mediatype > 0)
		if showmediatype then
			builder:wikitext(" &#x5B;", data.mediatype, "&#x5D;")
			needDot = true
		end

		if not editor and data.editor then
			builder:wikitext(", ", formatAuthors(data.editor, false, true), " (red.)")
		end
		
		if data.others then
			builder:wikitext(", ", formatAuthors(data.others, true, true))
			needDot = true
		end
	end
	
	if data.work then
		builder:wikitext(", [w:] ", data.work, (not data.mediatype and data.url) and " [online]" or "")
		needDot = true
	end

	if data.journal and (not data.published or (data.journal ~= data.published)) then
		--builder:wikitext((data.title or data.work) and ", [w:] „" or "„")
		builder:wikitext((data.title or data.work) and ", „" or "„")
		local title = softNoWiki(data.journal)
		if data.journalurl then
			builder:wikitext("[", escapeUrl(data.journalurl), " ", title, "]")
		elseif data.journallink then
			builder:wikitext("[[", data.journallink, "|", title, "]]")
		else
			builder:wikitext(title)
		end
		builder:wikitext("”")
		needDot = true
	end

	if data.responsibility then
		builder:wikitext(", ", data.responsibility)
		needDot = true
	end

	if data.issue then
		if data.journalvolume then
			builder:wikitext(", ", data.journalvolume, " (", data.issue, ")")
		elseif data.journal then
			builder:wikitext(", ", data.issue)
		else
			builder:wikitext(", wyd. ", data.issue)
		end
		needDot = true
	end

	if data.description and (#data.description > 0) then
		builder:wikitext(", ", data.description)
		needDot = true
	end

	if data.published and not data.publisher then
		builder:wikitext(", ", data.published)
		needDot = true
	end

	local place = false
	if data.place then
		builder:wikitext(", ", data.place)
		needDot = true
		place = true
	end
	if data.publisher then
		builder:wikitext(place and ": " or ", ", data.publisher)
		needDot = true
		place = false
	end
	if data.date then
		if data.yearRange then
			builder:wikitext(place and " " or ", ", data.yearRange)
		elseif data.date.day then
			builder:wikitext(", ", tostring(data.date.day), " ", resources.months[data.date.month].d, " ", tostring(data.date.year))
		elseif data.date.month then
			builder:wikitext(", ", resources.months[data.date.month].m, " ", tostring(data.date.year))
		else
			builder:wikitext(place and " " or ", ", data.year)
		end
		builder:wikitext(data.diferentiator or "")
		needDot = true
	end

	if data.p and #data.p > 0 then
		local isNonStandardPageNumber = mw.ustring.match(data.p, "[^%s0-9,%-–]")
		builder:wikitext(isNonStandardPageNumber and ", " or ", s. ", data.p)
		needDot = true
	end
	
	if data.doi then
		builder:wikitext(", [[DOI (identyfikator cyfrowy)|DOI]]:&nbsp;[http://dx.doi.org/", data.doi, " ", data.doi, "]")
		needDot = true
	end
	
	if data.isbn then
		for i,v in ipairs(data.isbn) do
			builder:wikitext(", ISBN ", v)
		end
		needDot = true
	end

	if data.lccn then
		builder:wikitext(", [[Biblioteka Kongresu Stanów Zjednoczonych|LCCN]] [http://lccn.loc.gov/", mw.uri.encode(data.lccn), " ", data.lccn, "]")
		needDot = true
	end
	
	if data.issn then
		builder:wikitext(", [[International Standard Serial Number|ISSN]] [http://worldcat.org/issn/", data.issn, " ", data.issn, "]")
		needDot = true
	end
	
	if data.pmid then
		builder:wikitext(", [[PMID]]:&nbsp;[http://www.ncbi.nlm.nih.gov/pubmed/", data.pmid, " ", data.pmid, "]")
		needDot = true
	end
	
	if data.pmc then
		builder:wikitext(", [[PMCID]]:&nbsp;[http://www.ncbi.nlm.nih.gov/pmc/articles/PMC", data.pmc, "/ PMC", data.pmc, "]")
		needDot = true
	end
	
	if data.bibcode then
		builder:wikitext(", [[Bibcode]]:&nbsp;[http://adsabs.harvard.edu/abs/", data.bibcode, " ", data.bibcode, "]")
		needDot = true
	end
	
	if data.oclc then
		builder:wikitext(", [[Online Computer Library Center|OCLC]]&nbsp;[http://worldcat.org/oclc/", mw.uri.encode(data.oclc), " ", data.oclc, "]")
		needDot = true
	end
	
	if data.arxiv then
		builder:wikitext(", [[arXiv]]:")
		local eprint, class = mw.ustring.match(data.arxiv, "^(%S+)%s+%[([^%[%]]+)%]$")
		if eprint then
			builder:wikitext("[//arxiv.org/abs/", eprint, " ", eprint, "] &#x5B;[//arxiv.org/archive/", class, " ", class, "]&#x5D;" )
		else
			builder:wikitext("[//arxiv.org/abs/", data.arxiv, " ", data.arxiv, "]" )
		end
		needDot = true
	end
	
	if data.id then
		builder:wikitext(", ", data.id)
		needDot = true
	end
	
	if data.accessdate then
		builder:wikitext(" [dostęp ", string.format("%04d-%02d-%02d", data.accessdate.year, data.accessdate.month, data.accessdate.day), "]")
		needDot = true
	end
	
	if data.url and data.archive then
		builder:wikitext(" [zarchiwizowane z [", escapeUrl(data.url), " adresu]")
		if data.archived and data.archived.day then
			builder:wikitext(" ", string.format("%04d-%02d-%02d", data.archived.year, data.archived.month, data.archived.day))
		end
		builder:wikitext("]")
		needDot = true
	end
	
	if data.quotation then
		builder:wikitext(", Cytat: ", data.quotation)
		needDot = true
	end

	local coinsData = COinS(data, coinsFormat)
	if coinsData then
		builder:tag("span"):addClass("Z3988"):attr("title",coinsData):css("display","none"):wikitext("&nbsp;")
	end
	
	if data.lang then
		local languages = require("Moduł:Lang").lang({args = data.lang})
		builder:wikitext(" ", languages)
		needDot = true
	end

	if needDot then
		builder:wikitext(".")
	end

	-- categories
	local addCategories = mw.title.getCurrentTitle().namespace == 0
	local problems = {}
	if mode == 1 then
		builder:wikitext(resources.categories.undetermined)
		table.insert(problems, "???")
	end
	if data.publisher and data.published then
		table.insert(problems, "p?")
		if addCategories then
			table.insert(problems, resources.categories.unusedPublished)
		end
	end
	if data.journal and data.published and (data.journal == data.published) then
		table.insert(problems, "j?")
		if addCategories then
			table.insert(problems, resources.categories.sameJournalAndPublished)
		end
	end
	
	local missing = false
	local needurl = ((resources.params.published.used[mode] == "*") and data.published) or (resources.params.url.used[mode] == "*")
	if data.missing then
		-- usually missing title, this is the first check for mandatory arguments
		table.insert(problems, data.missing)
		missing = true
	elseif needurl and not data.url and not data.chapterurl and not data.arxiv then
		-- build in support for missing external link for page citation
		table.insert(problems, resources.params.url.name)
		missing = true
	else
		-- any other missing value (first catch)
		for k, v in pairs(resources.params) do
			if (v.used[mode] == "!") and (not data[k] or (#data[k] == 0)) then
				table.insert(problems, v.name)
				missing = true
				break
			end
		end
	end

	if missing and addCategories then
		builder:wikitext(string.format(resources.categories.missingArg, resources.modes[mode]))
	end
	if data.chapterComma or data.authorComma or data.editorComma or data.othersComma or data.othersbookvolumeComma then
		if addCategories then
			builder:wikitext(resources.categories.suspectedComma)
		end
		
		table.insert(problems, "!!!")
	end
	if data.urlWarning then
		if addCategories then
			builder:wikitext(resources.categories.unusedUrl)
		end
		
		table.insert(problems, "Url")
	end
	if data.patchCitoidDate then
		table.insert(problems, "1 stycznia")
	end

	if #problems > 0 then
		local info = builder:tag("span"):addClass("problemy-w-cytuj")
		if addCategories then
			info:css("display","none")
		else
			info:css("color", "red")
		end
		
		info:wikitext(table.concat(problems,", "))
	end
	
	return builder:done()
end

local module = {}

module.auto = function(frame)
	return Cite(frame:getParent(), nil)
end

return module