local export = {}

local X16 = "[0-9A-Fa-f][0-9A-Fa-f]?[0-9A-Fa-f]?[0-9A-Fa-f]?"
local IPv6_FULL = "^" .. X16 .. ":" .. X16 .. ":" .. X16 .. ":" .. X16 .. ":" .. X16 .. ":" .. X16 .. ":" .. X16 .. ":" .. X16 .. "$"

local function is_unregistered(username)
	-- IPv4
	if username:match("^[0-9][0-9]?[0-9]?%.[0-9][0-9]?[0-9]?%.[0-9][0-9]?[0-9]?%.[0-9][0-9]?[0-9]?$") then
		-- this is the same algorithm MediaWiki uses, so we use it here too.
		-- seriously, 359.33.9.234 passes off as valid.
		return true
	end
	
	-- IPv6
	local lhs, rhs = username:match("^([0-9A-Fa-f:]*)::([0-9A-Fa-f:]*)$")
	if lhs then
		-- abbreviated address	
		local counter = 0
		local function check(side)
			if side == "" then
				return true
			end
			for word in mw.text.gsplit(side, ":") do
				if not word:match(X16) then
					return false
				end
				counter = counter + 1
				if counter >= 8 then
					return false	
				end
			end
			return true
		end

		if check(lhs) and check(rhs) then
			return true
		end
	else
		-- full address
		if username:match(IPv6_FULL) then
			return true
		end
	end

	return false
end

local user_linkbar_items = {
	userpage = {
		label = "user page";
		page = "User:%s";
		only_registered = true;
		no_ping = true;
	};

	talk = {
		label = "talk";	
		page = "User talk:%s";
	};
	
	contribs = {
		label = "contribs";
		page = "Special:Contributions/%s";
	};

	deleted = {
		label = "deleted contribs";
		page = "Special:DeletedContributions/%s";
	};

	block = {
		label = "block";
		page = "Special:Block/%s";
	};

	-- this is just to have a different label
	reblock = {
		label = "change block settings";
		page = "Special:Block/%s";
	};

	unblock = {
		label = "unblock";
		page = "Special:Unblock/%s";
	};

	blocklog = {
		label = "block log";
		page = "Special:Log";
		query = "type=block&page=User:%s";
	};

	actions = {
		label = "actions";
		page = "Special:Log//%s";
	};

	moves = {
		label = "page moves";
		page = "Special:Log/move/%s";
		only_registered = true;
	};

	newusers = {
		label = "user creation log";
		page = "Special:Log/newusers/%s";
		only_registered = true;
	};

	blocklist = {
		label = "active blocks";
		page = "Special:BlockList/%s"
	};

	global_blocklist = {
		label = "global blocks";
		page = "Special:GlobalBlockList/%s";
		only_ip = true;
	};

	rights = {
		label = "rights";
		page = "Special:UserRights/%s";
		only_registered = true;
	};

	nuke = {
		label = "nuke";
		page = "Special:Nuke/%s";
	};

	abuselog = {
		label = "edit filter log";
		page = "Special:AbuseLog";
		query = "wpSearchUser=%s";
	};

	userspace = {
		label = "userspace";
		page = "Special:PrefixIndex/User:%s/";
		only_registered = true;
	};

	email = {
		label = "email";
		page = "Special:EmailUser/%s";
		only_registered = true;
	};

	centralauth = {
		label = "global account info";
		page = "m:Special:CentralAuth/%s";
		only_registered = true;
	};

	whois = {
		label = "whois";
		external = "//whois.toolforge.org/w/%s/lookup";
		only_ip = true;
	};
}

function export.make_user_linkbar(frame)
	local po, pc = '', ''

	local user_name = frame.args.user or "Example"
	local user_enc = mw.uri.encode(user_name, "WIKI")
	
	-- https://git.wikimedia.org/blob/mediawiki%2Fextensions%2FEcho.git/HEAD/includes%2FDiscussionParser.php#L223
	-- shows that Echo parses discussions without passing the revision id (or user) to the parser.
	-- therefore we can use this trick to conceal a link from Echo, but render it normally on ordinary page view.
	-- the "obfuscated" link will also show up in page preview and pre-save transform (substitution), though.
	local is_echo = frame.preprocess and frame:preprocess "{{REVISIONUSER}}" == ""

	local function make_link(linkinfo, label)
		if linkinfo.external then
			po, pc = '<span class="plainlinks">', '</span>'
			return "[" .. linkinfo.external:format(user_enc) .. " " .. (label or linkinfo.label) .. "]"

		elseif linkinfo.query or (linkinfo.no_ping and frame.args.noping and is_echo) then
			po, pc = '<span class="plainlinks">', '</span>'
			return "[" .. tostring(mw.uri.fullUrl(
				linkinfo.page:format(user_enc),
				(linkinfo.query or ""):format(user_enc)
			)) .. " " .. (label or linkinfo.label) .. "]"
		else
			return "[[" .. linkinfo.page:format(user_name) .. "|" .. (label or linkinfo.label) .. "]]"
		end
	end

	local is_anon = is_unregistered(user_name)
	local items = {}
	local user_link
	
	if is_anon then
		if frame.args.ip then
			user_link = make_link(user_linkbar_items[frame.args.ip], user_name)
		else
			user_link = user_name
		end
	else
		user_link = make_link(user_linkbar_items.userpage, user_name)
	end

	for _, item in ipairs(frame.args) do
		local linkinfo = user_linkbar_items[item]
		if not linkinfo then
			error("Unrecognised link id: \"" .. item .. "\"")	
		end

		if is_anon then
			if not (linkinfo.only_registered or (item == frame.args.ip)) then
				items[#items + 1] = make_link(linkinfo)
			end
		else
			if not linkinfo.only_ip then
				items[#items + 1] = make_link(linkinfo)
			end
		end
	end
	
	return po .. user_link .. ((#items > 0) and (" (" .. table.concat(items, " • ") .. ")") or "") .. pc
end

return export
"https://si.wiktionary.org/w/index.php?title=Module:linkbar&oldid=24808" වෙතින් සම්ප්‍රවේශනය කෙරිණි