local p = {}
local Frame_args = {}
local Moduletext
local Modulecite
local Moduleflags
local InfoboxImage
local ModuleGlobes
local formatera
local weblink

local citetitle = "Module:Cite Q"
if nil ~= string.find(mw.getCurrentFrame():getTitle(), "ملعب", 1, true) then
	citetitle = "Module:Cite Q/ملعب"
end

local i18n = {
	["errors"] = {
		["property-param-not-provided"] = "وسيط property غير متوفر.",
		["entity-not-found"] = "الكيان غير موجود.",
		["unknown-claim-type"] = "نوع claim غير معروف.",
		["unknown-snak-type"] = "نوع snak غير معروف.",
		["unknown-datatype"] = "نوع data غير معروف.",
		["unknown-entity-type"] = "نوع entity غير معروف.",
		["unknown-value-module"] = "يجب عليك تعيين كل من  value-module و value-function.",
		["unknown-claim-module"] = "يجب عليك تعيين كل من claim-module و claim-function.",
		["unknown-property-module"] = "يجب عليك تعيين كل من property-module و property-function.",
		["property-module-not-found"] = "الوحدة المستخدمة في وسيط property-module غير موجودة.",
		["property-function-not-found"] = "الوظيفة المستخدمة في وسيط property-function غير موجودة.",
		["value-module-not-found"] = "الوحدة المستخدمة في وسيط value-module غير موجودة.",
		["value-function-not-found"] = "الوظيفة المستخدمة في وسيط value-function غير موجودة.",
		["claim-module-not-found"] = "الوحدة المستخدمة في وسيط claim-module غير موجودة.",
		["claim-function-not-found"] = "الوظيفة المستخدمة في وسيط claim-function غير موجودة."
	},
	["noarabiclabel"] = "تصنيف:صفحات_ويكي_بيانات_بحاجة_لتسمية_عربية",
	["warnDump"] = "[[Category:Called function 'Dump' from module Wikidata]]",
	["somevalue"] = "", --'"غير محدد"'
	["novalue"] = "", --قيمة مجهولة
	["cateref"] = "[[" .. "تصنيف:صفحات بها مراجع ويكي بيانات" .. "]]",
	["to translate"] = "صفحات تستعمل معطيات من ويكي بيانات بحاجة لترجمة",
	["trackingcat"] = "صفحات تستخدم خاصية $1",
	["see-wikidata-value"] = "الاطلاع ومراجعة البيانات على ويكي داتا",
	["see-wikidata"] = "راجع العنصر من ويكي بيانات المقابل",
	["see-another-project"] = "مقالة على $1",
	["see-another-language"] = "مقالة على أرابيكا $1"
}
local sortingproperties = {"P585", "P571", "P580", "P569", "P582", "P570"}
local sorting_methods = {
	["chronological"] = "chronological",
	["تصاعدي"] = "chronological",
	["asc"] = "chronological",
	["inverted"] = "inverted",
	["تنازلي"] = "inverted",
	["desc"] = "inverted"
}

local falsetitles = {
	"قالب:قيمة ويكي بيانات",
	"وحدة:Wikidata2"
}

local skiip_items = {
	["P106"] = {
		"Q42857", -- prophet
		"Q14886050", -- terrorist
		"Q2159907" -- criminal
	}
}

function isvalid(x)
	if x and x ~= "" then return x end
	return nil
end

function isntvalid(x)
	if not x or x == "" or x == nil then return true end
	return false
end

function No_Tracking_cat(options)
	if isvalid(options.formatting) == "raw" or isvalid(options.formatting) == "sitelink" then
		return true
	end
	local notracking = isvalid(options.nocate) or isvalid(options.notracking) or isvalid(Frame_args.notracking)
	local raw = isvalid(options.raw) or isvalid(Frame_args.raw) or isvalid(options.raw2) or isvalid(Frame_args.raw2)
	local nolink = isvalid(options.nolink) or isvalid(Frame_args.nolink)
	if notracking or raw or nolink then
		return true
	end
	local pagetitle = mw.title.getCurrentTitle().text
	for _, title in pairs(falsetitles) do
		if string.find(pagetitle, title, 1, true) then
			mw.log("notracking for title with: " .. title)
			return true
		end
	end
	return false
end

function addTrackingCategory(options)
	if No_Tracking_cat(options) then
		return ""
	end
	local cat = require("Module:Wikidata/تتبع").makecategory1
	local category = cat(options)
	local nbsp = " "
	if isvalid(options.nbsp) then
		nbsp = ""
	end
	if isvalid(category) then
		return nbsp .. category
	end
	return ""
end

function catewikidatainfo(options)
	--[[  function to add tracking category ]]
	if No_Tracking_cat(options) then
		return ""
	end
	local cat = ""
	local prop = options.property
	cat = cat .. " [[" .. "تصنيف:صفحات بها بيانات ويكي بيانات|" .. (prop or "wikidata") .. "]]"
	if isntvalid(options.nolink) then
		return cat
	else
		return ""
	end
end

function getqualifierbysortingproperty(claim, sortingproperty)
	for k, v in pairs(sortingproperty) do
		if claim and claim.qualifiers and claim.qualifiers[v] and claim.qualifiers[v][1].snaktype == "value" then
			local vali = claim.qualifiers[v][1].datavalue.value.time or claim.qualifiers[v][1].datavalue.value.amount
			if vali:sub(1, 1) == "+" then
				vali = vali:sub(2)
			end
			--mw.log(vali)
			return vali
		end
	end
	return nil
end

function get_sorting_properties(options)
	if type(options.sortingproperty) == "table" then
		return options.sortingproperty
	elseif type(options.sortingproperty) == "string" and options.sortingproperty ~= "" then
		return mw.text.split(options.sortingproperty, ",")
	else
		return sortingproperties
	end
end

function getDate(claim, options)
	local sortingproperty = get_sorting_properties(options)
	return getqualifierbysortingproperty(claim, sortingproperty)
end

function get_entityId(options)
	local id = isvalid(options.entityId) or isvalid(options.id) or isvalid(options.qid)
	if id then
		return id
	end
	if isvalid(options.page) then
		id = mw.wikibase.getEntityIdForTitle(options.page)
	else
		id = mw.wikibase.getEntityIdForCurrentPage()
	end
	return id or ""
end

function countSiteLinks(id)
	local numb = 0
	local entity = mw.wikibase.getEntityObject(id)
	if entity and entity.sitelinks then
		for i, v in pairs(entity.sitelinks) do
			numb = numb + 1
		end
	end
	return numb
end

function make_format_num(String)
	local line = String
	line = mw.getCurrentFrame():preprocess("{{ {{{|safesubst:}}}formatnum: " .. String .. " }}")
	line = mw.ustring.gsub(line, "٫", ".")
	line = mw.ustring.gsub(line, "٬", ",")
	return line
end

function formatcharacters(label, options)
	local formatch = options.formatcharacters
	--if options.FormatfirstCharacter and options.num == 1 then
	--formatch = options.FormatfirstCharacter
	--end

	local String2 = mw.ustring.gsub(label, "–", "-")
	local march_y =
		mw.ustring.match(String2, "%d%d%d%d%-%d%d%d%d", 1) or mw.ustring.match(String2, "%d%d%-%d%d%d%d", 1) or
		mw.ustring.match(String2, "%d%d%d%d", 1) or
		mw.ustring.match(String2, "%d%d%d%d%-%d%d", 1) or
		mw.ustring.match(String2, "%d%d%d%d", 1)

	if isvalid(options.illwd2y) then
		return march_y or label
	end
	if isvalid(options.illwd2noy) and march_y then
		label = mw.ustring.gsub(label, march_y, "")
		return label
	end

	if isntvalid(formatch) then
		return label
	end

	local prepr = {
		["lcfirst"] = "{{lcfirst: " .. label .. " }}",
		["lc"] = "{{lc: " .. label .. " }}",
		["uc"] = "{{uc: " .. label .. " }}"
	}
	if prepr[formatch] then
		return mw.getCurrentFrame():preprocess(prepr[formatch])
	elseif formatch == "ucfirst" then
		return mw.language.getContentLanguage():ucfirst(label)
	elseif formatch == "formatnum" then
		return make_format_num(label)
	end
	return label
end

function descriptionIn(langcode, id) -- returns item description for a given language
	if isntvalid(langcode) then
		langcode = "ar"
	end
	langcode = mw.text.trim(langcode or "")
	id = mw.text.trim(id or "")
	if langcode == "ar" then
		local description, lange = mw.wikibase.getDescriptionWithLang(id)
		if lange == langcode then
			return description
		else
			return nil
		end
	else
		local entity = getEntityFromId(id)
		if entity and entity.descriptions then
			local description = entity.descriptions[langcode]
			if description and description.value then
				if description["language"] == langcode then
					return description.value
				end
			end
		end
	end
	return nil
end

function labelIn(langcode, id) -- returns item label for a given language
	if isntvalid(langcode) then
		langcode = "ar"
	end
	if type(id) ~= "string" then
		id = tostring(id)
	end
	langcode = mw.text.trim(langcode or "")
	id = mw.text.trim(id or "")
	local label = mw.wikibase.getLabelByLang(id, langcode) or nil
	return label
end

function get_snak_id(snak)
	if
		snak and snak.type and snak.type == "statement" and snak.mainsnak and snak.mainsnak.snaktype and
			snak.mainsnak.snaktype == "value" and
			snak.mainsnak.datavalue and
			snak.mainsnak.datavalue.type and
			snak.mainsnak.datavalue.type == "wikibase-entityid" and
			snak.mainsnak.datavalue.value and
			snak.mainsnak.datavalue.value.id
	 then
		ID = snak.mainsnak.datavalue.value.id
		return ID
	end
end

function comparedates(a, b) -- returns true if a is earlier than B or if a has a date but not b
	if a and b then
		return a > b
	elseif a then
		return true
	end
end

function getDateArb(claim, sorting_properties)
	local sortingproperty = sorting_properties
	if claim.mainsnak.snaktype == "value" then
		local item = claim.mainsnak.datavalue.value["numeric-id"]
		if claim.mainsnak.datavalue.value["entity-type"] == "item" then
			item = "Q" .. item
		elseif claim.mainsnak.datavalue.value["entity-type"] == "property" then
			item = "P" .. item
		end
		for k, prop in pairs(sortingproperty) do
			local date =
				formatStatements({property = prop, entityId = item, firstvalue = "t", noref = "t", modifytime = "q"})
			if isvalid(date) then
				--mw.log("item:".. item .. ", prop:".. prop .. ", date:".. date)
				return date
			end
		end
	end
end

function table_contains(table, element)
	for _, value in pairs(table) do
		if value == element then
			return true
		end
	end
	return false
end

function dontget(claims, options)
	--[[
	options.dontget
	options.dontgetproperty
	]]
	local claims2 = {}
	local dontget_values = mw.text.split(options.dontget, ",")

	for _, claim in pairs(claims) do
		local id = get_snak_id(claim)
		if id then
			local valid = true
			local t2 =
				formatStatements({property = (options.dontgetproperty or "P31"), entityId = id, noref = "t", raw = "t"})

			if t2 and #t2 > 0 then
				for _, state in pairs(t2) do
					if table_contains(dontget_values, state.item) then
						valid = false
						break
					end
				end
			end

			if valid then
				table.insert(claims2, claim)
			end
		end
	end

	return claims2
end

function getonly(claims, options)
	--[[
	-- options.getonly
	-- options.getonlyproperty
	]]
	local claims2 = {}
	local getonly_values = mw.text.split(options.getonly, ",")

	for _, claim in pairs(claims) do
		local id = get_snak_id(claim)
		if id then
			local t2 =
				formatStatements({property = (options.getonlyproperty or "P31"), entityId = id, noref = "t", raw = "t"})
			if t2 and #t2 > 0 then
				for _, state in pairs(t2) do
					if table_contains(getonly_values, state.item) then
						table.insert(claims2, claim)
						break
					end
				end
			end
		end
	end

	return claims2
end

function claimindex(claims, options)
	local claims2 = {}
	for j, index in pairs(mw.text.split(options.claimindex, ",")) do
		if tonumber(index) and #claims >= tonumber(index) then
			table.insert(claims2, claims[tonumber(index)])
		end
	end
	return claims2
end

function avoidvalue(claims, options)
	local avoidvalue = options.avoidvalue
	if type(avoidvalue) == "string" then
		avoidvalue = mw.text.split(avoidvalue, ",")
	elseif type(avoidvalue) ~= "table" then
		return claims
	end

	local claims4 = {}
	for i, j in pairs(claims) do
		local ID = get_snak_id(j)
		if ID and not table_contains(avoidvalue, ID) then
			table.insert(claims4, j)
		end
	end
	return claims4
end

function prefervalue(claims, options)
	local prefervalue = options.prefervalue
	if type(prefervalue) == "string" then
		prefervalue = mw.text.split(prefervalue, ",")
	elseif type(prefervalue) ~= "table" then
		return claims
	end

	local claims3 = {}
	for _, claim in pairs(claims) do
		local ID = get_snak_id(claim)
		if ID and table_contains(prefervalue, ID) then
			table.insert(claims3, claim)
		end
	end

	return claims3
end

function preferqualifier(claims, options)
	--[[
	-- options.preferqualifier
	-- options.preferqualifiervalue
	]]
	local claims2 = {}
	local preferq_values = mw.text.split(options.preferqualifiervalue or "", ",")

	for _, statement in pairs(claims) do
		if statement.qualifiers and statement.qualifiers[options.preferqualifier:upper()] then
			if isvalid(options.preferqualifiervalue) then
				for _, quall in pairs(statement.qualifiers[options.preferqualifier:upper()]) do
					if quall.snaktype == "value" and table_contains(preferq_values, quall.datavalue.value["id"]) then
						table.insert(claims2, statement)
						break
					end
				end
			else
				table.insert(claims2, statement)
			end
		end
	end

	return claims2
end

function avoidqualifier(claims, options)
	-- options.avoidqualifier
	-- options.avoidqualifiervalue
	if isntvalid(options.avoidqualifier) then
		return claims
	end

	local av = options.avoidqualifier:upper()
	local avoidqualifiervalue_values =
		type(options.avoidqualifiervalue) == "string" and mw.text.split(options.avoidqualifiervalue, ",") or
		options.avoidqualifiervalue
	local claims2 = {}

	for _, statement in pairs(claims) do
		if not statement.qualifiers or not statement.qualifiers[av] then
			table.insert(claims2, statement)
		elseif isvalid(options.avoidqualifiervalue) then
			local active = true
			for _, quall in pairs(statement.qualifiers[av]) do
				if
					quall.snaktype == "value" and quall.datavalue and quall.datavalue.value and
						quall.datavalue.value["id"] and
						table_contains(avoidqualifiervalue_values, quall.datavalue.value["id"])
				 then
					active = false
					break
				end
			end
			if active then
				table.insert(claims2, statement)
			end
		end
	end

	return claims2
end

function claims_limit(claims, limit)
	local newclaims = {}
	if type(limit) ~= "number" then
		limit = tonumber(limit)
	end
	if limit and type(limit) == "number" then
		if limit < 1 or #claims < limit then
			return claims
		end
		for i = 1, #claims do
			if i <= limit then
				newclaims[i] = claims[i]
			end
		end
		return newclaims
	end
	return claims
end

function claims_offset(claims, offset)
	local offsetclaims = {}
	if type(offset) ~= "number" then
		offset = tonumber(offset)
	end
	if offset and type(offset) == "number" then
		for i = offset + 1, #claims do
			offsetclaims[#offsetclaims + 1] = claims[i]
		end
		return offsetclaims
	end
	return claims
end

function sortbyarb(claims, sorting_properties, options)
	local sortingmethod = options.sortbyarbitrary or options.sortingmethod
	--mw.log("sortbyarb: " .. sortingmethod)

	table.sort(
		claims,
		function(a, b)
			local timeA = getDateArb(a, sorting_properties)
			local timeB = getDateArb(b, sorting_properties)
			if sortingmethod == "inverted" or sorting_methods[sortingmethod] == "inverted" then
				return comparedates(timeB, timeA)
			else
				return comparedates(timeA, timeB)
			end
		end
	)
	return claims
end

function sort_langs(claims, options)
	local claims7 = {}
	local arabic_id = {["P407"] = 13955, ["P282"] = 8196} -- Q13955 = "العربية", Q8196 = "أبجدية عربية"

	for _, statement in pairs(claims) do
		for prop, id in pairs(arabic_id) do
			if statement.qualifiers and statement.qualifiers[prop] then
				for _, v in pairs(statement.qualifiers[prop]) do
					if v.snaktype == "value" and v.datavalue.value["numeric-id"] == id then
						table.insert(claims7, statement)
						break
					end
				end
			end
		end
	end

	if #claims7 > 0 then
		claims = claims7
	end

	return claims
end

function sortbyqualifier(claims, sorting_properties, options)
	if not sorting_properties or #sorting_properties == 0 then
		sorting_properties = get_sorting_properties(options)
	end
	
	local sort_by = sorting_methods[options.sortbytime] or options.sortbytime

	table.sort(
		claims,
		function(a, b)
			local timeA = getqualifierbysortingproperty(a, sorting_properties)
			local timeB = getqualifierbysortingproperty(b, sorting_properties)
			if sort_by == "inverted" then
				return comparedates(timeB, timeA)
			else
				return comparedates(timeA, timeB)
			end
		end
	)
	return claims
end

function sortbyqualifiernumber(claims, sorting_properties, options)
	if not sorting_properties or #sorting_properties == 0 then
		sorting_properties = get_sorting_properties(options)
	end

	local sort_by = sorting_methods[options.sortbynumber] or options.sortbynumber

	table.sort(
		claims,
		function(a, b)
			local timeA = getqualifierbysortingproperty(a, sorting_properties)
			local timeB = getqualifierbysortingproperty(b, sorting_properties)
			if sort_by == "inverted" then
				return comparedates(timeB, timeA)
			else
				return comparedates(timeA, timeB)
			end
		end
	)
	return claims
end

function sort_claims(claims, options)
	local sortingmethod = options.sortbyarbitrary or options.sortingmethod
	local sorting_properties = get_sorting_properties(options)

	if isvalid(options.sortbytime) and sorting_methods[options.sortbytime] then
		if #sorting_properties == 0 then
			sorting_properties = sortingproperties
		end
		claims = sortbyqualifier(claims, sorting_properties, options)
	elseif isvalid(options.sortbynumber) and sorting_methods[options.sortbynumber] then
		claims = sortbyqualifiernumber(claims, sorting_properties, options)
	elseif isvalid(sortingmethod) and sorting_methods[sortingmethod] then
		claims = sortbyarb(claims, sorting_properties, options)
	end
	return claims
end

function filter_claims(claims, options)
	local claims = claims

	if isntvalid(options.langpref) then
		claims = sort_langs(claims, options)
	end

	claims = sort_claims(claims, options)

	local offset = options.offset
	if isvalid(offset) then
		claims = claims_offset(claims, offset)
	end

	local limit = options.limit
	if isvalid(limit) then
		claims = claims_limit(claims, limit)
	end

	if isvalid(options.avoidqualifier) then -- to avoid value with a given qualifier
		claims = avoidqualifier(claims, options)
	end

	if isvalid(options.preferqualifier) then
		claims = preferqualifier(claims, options)
	end

	-- options.avoidvalue
	if isvalid(options.avoidvalue) then
		claims = avoidvalue(claims, options)
	end

	-- options.prefervalue
	if isvalid(options.prefervalue) then
		claims = prefervalue(claims, options)
	end

	-- options.getonly
	if isvalid(options.getonly) then
		claims = getonly(claims, options)
	end

	-- options.dontget
	if isvalid(options.dontget) then
		claims = dontget(claims, options)
	end

	local firstvalue = options.enbarten or options.firstvalue
	local first = isvalid(tonumber(firstvalue))
	if isvalid(first) and #claims > 1 then
		if #claims > 0 then
			first = tonumber(first) or 1
			if first > 0 and first <= #claims then
				claims = {claims[first]}
			else
				claims = {claims[1]}
			end
		end
	elseif isvalid(firstvalue) and #claims > 0 then
		claims = {claims[1]}
	end

	local numval = options.numval
	if numval and type(numval) ~= "number" then
		numval = tonumber(numval)
	end
	if numval and type(numval) == "number" and #claims > 1 and #claims > numval then
		local claimsnumval = {}
		local ic = 1
		while (numval >= ic) and (#claims >= ic) do
			table.insert(claimsnumval, claims[ic])
			ic = ic + 1
		end
		claims = claimsnumval
	end

	return claims
end

function getEntityFromId(id)
	return isvalid(id) and mw.wikibase.getEntityObject(id) or mw.wikibase.getEntityObject()
end

function formatError(key)
	return i18n.errors[key]
end

function formatOneStatement(statement, ref, options)
	local value = nil
	local stat = formatStatement(statement, options)
	if not stat then
		return {v = value, raw = stat}
	end

	local s = stat.value
	if isntvalid(s) then
		return {v = value, raw = stat}
	end

	if not stat.qualifiers then
		stat.qualifiers = {}
	end

	local P585 = stat.P585 or ""
	local tf = stat.tifr
	local awardqual = stat.foto
	local ro = stat.ro
	local qp1a = stat.qp1a
	local onlyqualifier = stat.onlyqualifier
	local qp1 = stat.qp1
	local qp2 = stat.qp2
	local qp3 = stat.qp3
	local qp4 = stat.qp4
	local qp5 = stat.qp5
	local reff = stat.reff

	if reff and isvalid(options.reff) then
		s = s .. reff
	end
	if isvalid(options.template) then
		s =
			mw.getCurrentFrame():expandTemplate {
			title = options.template,
			args = {
				stat.QQ1,
				s,
				stat.QQ2,
				stat.QQ3,
				stat.QQ4,
				stat.QQ5,
				stat.QQ6,
				stat.QQ7,
				stat.QQ8,
				stat.QQ9,
				stat.QQ10,
				entityId = options.entityId,
				v1 = options.v1,
				id = stat.ID
			}
		}
	end
	if isvalid(options.football) then
		s =
			mw.getCurrentFrame():expandTemplate {
			title = "صندوق معلومات سيرة كرة قدم/سطر فريق",
			args = {
				stat.qualifiers.P580 or "",
				stat.qualifiers.P582 or "",
				s,
				stat.amatch,
				stat.goal
			}
		}
	end

	if isvalid(options.office) then
		s =
			mw.getCurrentFrame():expandTemplate {
			title = "معلومات صاحب منصب/منصب ويكي بيانات/نواة",
			args = {
				office = s,
				termstart = stat.qualifiers.P580 or "",
				termend = stat.qualifiers.P582 or "",
				constituency = stat.qualifiers.P768 or "",
				predecessor = stat.qualifiers.P1365 or "",
				successor = stat.qualifiers.P1366 or "",
				series = stat.qualifiers.P1545 or "",
				of = stat.qualifiers.P642 or "",
				electedin = stat.qualifiers.P2715 or "",
				jurisdiction = stat.qualifiers.P1001 or "",
				employer = stat.qualifiers.P108 or "",
				entityId = options.entityId
			}
		}
	end

	local function qoo(Prefix, qualpref, p, Suffix)
		if isvalid(p) then
			local stri = (Prefix or " (") .. (qualpref or "") .. p .. (Suffix or ")")
			if isvalid(options.nosmall) then
				return stri
			else
				return mw.text.tag("small", {}, stri)
			end
		end
	end
			  
	local QPrefix = isvalid(options.qualifierprefix)
	local QSuffix = isvalid(options.qualifiersuffix)

	if isvalid(qp1) and isvalid(options.qual1) and isvalid(qp1a) and isvalid(options.qual1a) then
		s = s .. 
			qoo(QPrefix, options.qual1pref, qp1, QSuffix) .. qoo(QPrefix, options.qp1apref, qp1a, QSuffix)

	elseif isvalid(qp1) and isvalid(options.qual1) then
		s = s .. qoo(QPrefix, options.qual1pref, qp1, QSuffix)

	elseif isvalid(qp1a) and isvalid(options.qual1a) then
		s = s .. qoo(QPrefix, options.qp1apref, qp1a, QSuffix)
	end

	if isvalid(qp2) and isvalid(options.qual2) then
		s = s .. qoo(QPrefix, options.qual2pref, qp2, QSuffix)
	end

	if isvalid(qp3) and isvalid(options.qual3) then
		s = s .. qoo(QPrefix, options.qual3pref, qp3, QSuffix)
	end
	if isvalid(qp4) and isvalid(options.qual4) then
		s = s .. qoo(QPrefix, options.qual4pref, qp4, QSuffix)
	end
	if isvalid(qp5) and isvalid(options.qual5) then
		s = s .. qoo(QPrefix, options.qual5pref, qp5, QSuffix)
	end

	if isvalid(options.justthisqual) then
		if onlyqualifier then
			s = onlyqualifier
		else
			s = nil -- We need only the qualifier
		end
	end
	if isvalid(ro) and isvalid(options.withro) then
		s = s .. qoo(QPrefix, "", ro, QSuffix)
	end

	if isvalid(P585) and isvalid(options.withdate) then
			if options.withdate == "y" then
				s = s .. qoo(QPrefix, "سنة ", P585, QSuffix)
			elseif options.withdate == "before" then
				s = "*" .. P585 .. ":" .. s .. "\n"
			else
				s = s .. qoo(QPrefix, "", P585, QSuffix)
			end
		end

	if awardqual and isvalid(options.awardqua) then
		s = s .. qoo(QPrefix, "", awardqual, QSuffix)
	end

	local bothdates = options.withintervall or options.bothdates
	if tf and isvalid(bothdates) then
		if bothdates == "line" then
			s = s .. mw.text.tag("br") .. qoo(QPrefix, "", tf, QSuffix)
		elseif bothdates == "before" then
			s = qoo(QPrefix, "", tf, QSuffix) .. s
		else
			s = s .. qoo(QPrefix, "", tf, QSuffix)
		end
	end

	if type(ref) == "table" or (isvalid(options.noref)) or (isvalid(options.justthisqual)) then
		value = s
	else
		local t = formatReferences(statement, options)
		stat.ref = t
		if isvalid(options.justref) then
			value = t
		elseif isvalid(options.onlyvaluewithref) then
			if isvalid(t) then
				value = s .. t
			end
		else
			value = s .. t
		end
	end
	return {v = value, raw = stat}
end

function formatStatements(options, LuaClaims)
	local valuetable = {} -- formattedStatements
	local claims = {}

	if isntvalid(options.property) and isvalid(options.pid) then
		options.property = options.pid
	end
	
	if isntvalid(options.property) then
		return formatError("property-param-not-provided")
	end
	local option1 = options.option1
	if option1 and options.option1value then
		options[option1] = options.option1value
		options['"' .. option1 .. '"'] = options.option1value
	--mw.log( "option1: " .. option1 .. "value: " .. options.option1value  )
	end
	if type(LuaClaims) == "table" then
		claims = LuaClaims[options.property] or {}
		mw.log("module:wikidata2: claims = LuaClaims[options.property]")
	else
		--Get entity
		local entity = nil
		if options.entity and type(options.entity) == "table" then
			entity = options.entity
		else
			local id = get_entityId(options)
			if isvalid(id) then
				local check = mw.ustring.match(id, "Q%d+") or mw.ustring.match(id, "P%d+")
				if check == nil then
					mw.addWarning(id .. " لا يمثل معرف ويكي بيانات صحيح")
					return ""
				else
					options.entityId = id
					options.qid = id
				end
			end
			entity = getEntityFromId(id)
		end
		--local property = mw.wikibase.resolvePropertyId( options.property:upper() )
		local property = options.property:upper()

		if not entity then
			return ""
		end --TODO error?
		if not entity.claims or not entity.claims[property] then
			if isvalid(options.otherproperty) then
				options.property = options.otherproperty
				property = options.otherproperty:upper()
			end
		end
		if property == nil then
			return ""
		end
		if not entity.claims or not entity.claims[property] then
			return "" --TODO error?
		end

		--Format statement and concat them cleanly
		if options.rank == "best" or isntvalid(options.rank) then
			--claims = entity:getAllStatements( property )
			claims = entity:getBestStatements(property)
		elseif options.rank == "valid" then
			for i, statement in pairs(entity.claims[property]) do
				if statement.rank == "preferred" or statement.rank == "normal" then
					table.insert(claims, statement)
				end
			end
		elseif options.rank == "all" then
			for i, statement in pairs(entity.claims[property]) do
				table.insert(claims, statement)
			end
		else
			for i, statement in pairs(entity.claims[property]) do
				if statement.rank == options.rank then
					table.insert(claims, statement)
				end
			end
		end
	end
	claims = filter_claims(claims, options)
	local statementsraw = {}
	local All_claims = claims
	if claims then
		if options["property-module"] or options["property-function"] then
			if not options["property-module"] or not options["property-function"] then
				return formatError("unknown-property-module")
			end
			local formatter = require("Module:" .. options["property-module"])
			if not formatter then
				return formatError("property-module-not-found")
			end
			local fun = formatter[options["property-function"]]
			if not fun then
				return formatError("property-function-not-found")
			end

			mw.log("work with property-module: " .. options["property-module"] .. "|" .. options["property-function"])
			return fun(claims, options)
		else
			for i, statement in pairs(claims) do
				options.num = i
				local va = formatOneStatement(statement, LuaClaims, options)
				if va.v then
					table.insert(valuetable, va.v)
				end
				table.insert(statementsraw, va.raw)
			end
		end
	end

	if isvalid(options.raw) then
		if isvalid(options.rawtolua) then
			return mw.getCurrentFrame():extensionTag("source", mw.dumpObject(statementsraw), {lang = "lua"})
		end
		return statementsraw
	end

	local priff = ""
	local Separator = options.separator -- or ""
	local Conjunction = options.conjunction -- or ""

	if Separator == "br" or Conjunction == "br" then
		Separator = mw.text.tag("br")
	end
	if Separator == "*" then
		priff = "\n*"
		Separator = "\n*"
	end
	if Separator == "#" then
		priff = "\n#"
		Separator = "\n#"
	end
	if isvalid(options.justref) then
		priff = ""
		Separator = ""
	end

	local tot = mw.text.listToText(valuetable, Separator, Separator)
	if #valuetable > 1 then
		tot = priff .. tot
	end

	if isntvalid(tot) then
		tot = nil
	end
	if isvalid(options.returnnumberofvalues) or options.returnnumberofvalues == true then
		return tot, #valuetable
	end
	if isvalid(options.numberofclaims) then
		return #All_claims
	end
	return tot
end

function p.formatAndCat(args)
	if args == nil then
		return nil
	end

	Frame_args = args
	args.linkback = args.linkback or true
	args.addcat = true
	if isvalid(args.value) and args.value == "-" then
		return nil
	end
	if isvalid(args.value) then
		local val = args.value .. addTrackingCategory(args)
		val = p.addLinkBack(val, args.entity, args.property)
		return val
	end
	return p.formatStatementsFromLua(args)
end

function formatReferences(statement, options)
	local ic = 1
	local reference = {}
	local numberofref = tonumber(options.numberofreferences) or 7
	local qid = get_entityId(options)
	local statementreferences = statement.references

	if statementreferences then
		if Modulecite == nil then
			Modulecite = require(citetitle)
		end
		for i, ref in ipairs(statementreferences) do
			if ref.snaks and numberofref >= ic then
				local s = Modulecite._cite_wikidata(ref, qid)
				if isvalid(s) then
					ic = ic + 1
					table.insert(reference, s)
				end
			end
		end
	end

	local final = table.concat(reference)
	if isvalid(final) then
		final = final .. i18n.cateref
	end
	return final or ""
end

function formatqualifiers(statement, s, options)
	s.qualifiers = {}
	local function qua(p, firstvalue, modifytime)
		local vvv
		if isvalid(p) then
			vvv =
				formatStatements(
				{
					property = p,
					enlabelcate = "t",
					firstvalue = (firstvalue or ""),
					modifytime = (modifytime or "longdate"),
					noref = "t"
				},
				statement.qualifiers
			) or ""
			s.qualifiers[p] = vvv
			return vvv
		end
	end

	if isvalid(options.template) then
		s.ID = statement.mainsnak.datavalue.value.id
		s.QQ1 = qua(options.Q1)
		s.QQ2 = qua(options.Q2)
		s.QQ3 = qua(options.Q3)
		s.QQ4 = qua(options.Q4)
		s.QQ5 = qua(options.Q5)
		s.QQ6 = qua(options.Q6)
		s.QQ7 = qua(options.Q7)
		s.QQ8 = qua(options.Q8)
		s.QQ9 = qua(options.Q10)
		s.QQ10 = qua(options.Q10)
	end
	if isvalid(options.football) then
		if statement.qualifiers.P1350 or statement.qualifiers.P1351 then
			s.amatch = qua("P1350", "true")
			s.goal = qua("P1351", "true")
		end
	end
	if (isvalid(options.football)) or (isvalid(options.office)) then
		s.start1 = qua("P580", "true")

		s.finish1 = qua("P582", "true")
	end
	if isvalid(options.office) then
		if
			statement.qualifiers.P580 or statement.qualifiers.P582 or statement.qualifiers.P1365 or
				statement.qualifiers.P1366
		 then
			s.before1 = qua("P1365", "true")
			s.after1 = qua("P1366", "true")
			s.constituency1 = qua("P768")
			s.series1 = qua("P1545")
			s.electedin1 = qua("P2715", "")
			s.pp1001 = qua("P1001")
			s.pp108 = qua("P108")
			s.pp642 = qua("P642")
		end
	end

	if isvalid(options.withdate) then
		--if statement.qualifiers.P585 then
		s.P585 = qua("P585", "true", options.modifyqualifiertime)
	end
	local qwe = options.qwer
	if statement.qualifiers.qwe then
		s.ro = qua(qwe, "true")
	end
	local bothdates_option = options.withintervall or options.bothdates
	if isvalid(bothdates_option) then
		if statement.qualifiers.P580 or statement.qualifiers.P582 then
			local f = qua("P580", "true", options.modifyqualifiertime)
			local t = qua("P582", "true", options.modifyqualifiertime)
			s.tifr = f .. "–" .. t
		end
	end
	if isvalid(options.awardqua) then
		if statement.qualifiers.P585 or statement.qualifiers.P1346 then
			local fo = qua("P585", "true", options.modifyqualifiertime)
			local to = qua("P1346", "true")
			s.foto = fo .. " " .. mw.text.tag("span", {}, " " .. to .. "")
		end
	end
	local function quaaal(opti, options)
		if isvalid(opti) and statement.qualifiers[opti] then
			local kkk =
				formatStatements(
				{
					property = opti,
					noref = "t",
					separator = options.qualifierseparator,
					conjunction = options.qualifierconjunction,
					size = options.size,
					image = options.image,
					modifytime = options.modifyqualifiertime,
					enlabelcate = "t",
					langpref = options.langpref,
					showlang = options.showlang
				},
				statement.qualifiers
			) or ""

			s.qualifiers[opti] = kkk
			return kkk
		end
	end

	if isvalid(options.justthisqual) and statement.qualifiers[options.justthisqual] then
		s.onlyqualifier = quaaal(options.justthisqual, options)
	end
	if isvalid(options.qual1) and statement.qualifiers[options.qual1] then
		s.qp1 = quaaal(options.qual1, options)
	end
	if isvalid(options.qual1a) and statement.qualifiers[options.qual1a] then
		s.qp1a = quaaal(options.qual1a, options)
	end
	if isvalid(options.qual2) and statement.qualifiers[options.qual2] then
		s.qp2 = quaaal(options.qual2, options)
	end
	if isvalid(options.qual3) and statement.qualifiers[options.qual3] then
		s.qp3 = quaaal(options.qual3, options)
	end
	if isvalid(options.qual4) and statement.qualifiers[options.qual4] then
		s.qp4 = quaaal(options.qual4, options)
	end
	if isvalid(options.qual5) and statement.qualifiers[options.qual5] then
		s.qp5 = quaaal(options.qual5, options)
	end
end

function formatSnak(snak, options)
	if snak.snaktype == "somevalue" then
		local somevalue = options.somevalue or i18n["somevalue"]
		return {value = somevalue}
	elseif snak.snaktype == "novalue" then
		local novalue = options.novalue or i18n["novalue"]
		return {value = novalue}
	elseif snak.snaktype == "value" then
		local s = formatDatavalue(snak.datavalue, snak.datatype, options)
		if s and s.value and isvalid(s.value) then
			s.value = (options.prefix or "") .. s.value .. (options.suffix or "")
		end
		return s
	else
		return {value = formatError("unknown-snak-type")}
	end
end

function formatStatement(statement, options)
	if options["claim-module"] or options["claim-function"] then
		if not options["claim-module"] or not options["claim-function"] then
			return {value = formatError("unknown-claim-module")}
		end
		local formatter = require("Module:" .. options["claim-module"])
		if formatter == nil then
			return {value = formatError("claim-module-not-found")}
		end
		local fun = formatter[options["claim-function"]]
		if fun == nil then
			return {value = formatError("claim-function-not-found")}
		end
		return {value = fun(statement, options)}
	elseif statement.type == "statement" then
		local s = formatSnak(statement.mainsnak, options)
		if isvalid(s) then
			s.qualifiers = {}
			if statement.qualifiers then
				local qualu = formatqualifiers(statement, s, options)
			--if isvalid(qualu) then table.insert(qualu) end
			end
			if statement.references then
				if isvalid(options.reff) then
					s.reff = formatReferences(statement, options)
				end
			end
		end
		return s
	elseif not statement.type then
		return formatSnak(statement, options)
	end
	return {value = formatError("unknown-claim-type")}
end



function get_property1(options, item)
	--[[ function to get countries flags without reload large countries items ]]
	local flagprop = {"p27", "p1532", "p17", "p495", "p1376"}
	local work_flag = false
	if string.lower(options.property1) == "p41" then
		for k, l in pairs(flagprop) do
			if string.lower(options.property) == l then
				work_flag = true
			end
		end
	end
	local caca = ""
	local size = options.size or ""
	if isntvalid(size) then
		size = "20"
	end
	if work_flag then
		if Moduleflags == nil then
			Moduleflags = require("Module:Wikidata2/Flags")
		end
		local flag = Moduleflags[item]
		if isntvalid(flag) then
			flag =
				formatStatements(
				{
					property = options.property1,
					otherproperty = options.otherproperty1,
					entityId = item,
					rank = options.property1rank,
					pattern = options.property1pattern,
					formatting = options.property1formatting,
					noref = "t",
					firstvalue = "t"
				}
			)
		--mw.log("get flag2 :" .. flag .. ", for item ".. item )
		end
		if isvalid(flag) then -- return real image
			if isvalid(options.image) then -- return real image
				caca = "[[file:" .. flag .. "|" .. size .. "px|" .. "border" .. "]]"
			--caca = Infobox_Image( {image=flag, size=size, maxsize = "280x330px", center=options.center} )
			--mw.log("get flag :" .. flag .. ", for item ".. item )
			end
		end
	end
	if isntvalid(caca) then
		caca =
			formatStatements(
			{
				property = options.property1,
				otherproperty = options.otherproperty1,
				entityId = item,
				rank = options.property1rank,
				pattern = options.property1pattern,
				formatting = options.property1formatting,
				size = options.size,
				image = options.image,
				noref = "t",
				firstvalue = "t"
			}
		)
	end
	return caca
end

function formatwikibaseitem(datavalue, datatype, options)
	--[[  datatype	wikibase-item	]]
	local value
	local itemqid = datavalue.value.id
	local Skipped = skiip_items[options.property] or {}
	for k, v in pairs(Skipped) do
		if datavalue.value.id == v then
			return {value = "", item = ""}
		end
	end
	if isvalid(options.formatting) then
		if options.formatting == "raw" then
			return {value = itemqid, item = itemqid}
		elseif options.formatting == "rawtotemplate" and isvalid(options.rawtotemplate) then
			local args = {q = itemqid, no1 = options.no1 or "", no2 = options.no2 or ""}
			value = mw.getCurrentFrame():expandTemplate {title = options.rawtotemplate, args = args} .. "\n"
			return {value = value, item = itemqid}
		elseif options.formatting == "fu" then
			value =
				mw.getCurrentFrame():expandTemplate {
				title = "Cycling race/stageclassification2",
				args = {itemqid, type = "1"}
			}
			return {value = value, item = itemqid}
		elseif options.formatting == "sitelink" then
			value = formatsitelink(datavalue.value.id, options)
			return {value = value, item = itemqid}
		else
			value = formatcharacters(datavalue.value, options)
			if isvalid(options.pattern) then
				value = formatFromPattern(value, options)
			end
			return {value = value, item = itemqid}
		end
	end

	local itemValue = formatEntityId(itemqid, options).value
	if isvalid(itemValue) then
		if isvalid(options.property1) and options.property1:upper():sub(1, 1) == "P" then
			local prop1value = get_property1(options, itemqid)
			if isvalid(prop1value) then
				prop1value = (options.property1pref or "") .. "" .. prop1value .. "" .. (options.property1suff or "")
				value = prop1value .. " " .. itemValue
				if isvalid(options.property1after) then
					value = itemValue .. prop1value
				end
			else
				value = itemValue
			end
			return {value = value, item = itemqid}
		elseif isvalid(options.propertyimage) then
			local p_f = options.propertyimageformatting or options.formattingpropertyimage
			local vas =
				formatStatements(
				{
					property = options.propertyimage,
					formatting = p_f,
					entityId = itemqid,
					rank = options.rank,
					pattern = options.pattern,
					size = options.size,
					image = options.image,
					noref = "t",
					avoidvalue = options.avoidvaluepropertyimage,
					firstvalue = "t",
					nolink = options.nolink
				}
			)
			if isvalid(vas) then
				return {value = vas}
			end
		elseif isvalid(options.property2) then
			local caca =
				formatStatements(
				{
					property = options.property2,
					entityId = itemqid,
					noref = options.noref,
					rank = options.rank,
					pattern = options.property2pattern,
					size = options.size,
					image = options.image,
					propertyimage = options.property3,
					firstvalue = "t"
				}
			)
			if isvalid(caca) then
				return {value = caca .. " " .. itemValue}
			end
		end
	end
	return {value = itemValue, item = itemqid}
end

function formatwikibaseproperty(datavalue, datatype, options)
	--[[  datatype	wikibase-property	]]
	local tid = ""
	if isvalid(options.formatting) then
		if options.formatting == "raw" then
			tid = datavalue.value.id
		end
	else
		tid = formatEntityId(datavalue.value.id, options).value
	end
	return {value = tid}
end

function formattabulardata(datavalue, datatype, options)
	--[[  tabular-data ]]
	local data = "[[commons:" .. datavalue.value .. "|" .. datavalue.value .. "]]"
	return {value = data}
end

function formatgeoshape(datavalue, datatype, options)
	--[[  geo-shape	 ]]
	local shape = "[[commons:" .. datavalue.value .. "|" .. datavalue.value .. "]]"
	return {value = shape}
end

function formatcommonsMedia(datavalue, datatype, options)
	local tid
	--[[ commonsMedia ]]
	local size = options.size or ""
	if isvalid(options.image) then -- return real image
		--tid = "[[file:" .. datavalue.value  .. "|".. (options.size or "20").."px|border]]"
		--if isvalid(options.center) then
		--tid = "[[file:" .. datavalue.value  .. "|".. (options.size or "20").."px|border|center]]"
		--end
		--tid = "[[file:" .. datavalue.value  .. "|".. (options.size or "60").."px|".."border".."]]"
		local params = {image = datavalue.value, maxsize = "280x330px", center = (options.center or "")}
		if isvalid(options.size) then
			params.size = size
		end
		if InfoboxImage == nil then
			InfoboxImage = require("Module:InfoboxImage")
		end
		tid = InfoboxImage.Infobox_Image(params)
	else
		tid = formatcharacters(datavalue.value, options)
	end
	return {value = tid}
end

function formatmath(datavalue, datatype, options)
	--[[datatype math ]]
	--return	{value=mw.text.tag("math", {}, "".. datavalue.value.."") } -- that doesn't work well
	local result = mw.getCurrentFrame():callParserFunction("#tag:math", datavalue.value)
	return {value = result}
end

function formatstring(datavalue, datatype, options)
	--[[  datatype string ]]
	local par = options.pattern
	local result = formatcharacters(datavalue.value, options)
	local tid = result

	if isvalid(options.stringpattern) then
		tid = mw.ustring.gsub(options.stringpattern, "$1", datavalue.value)
	elseif isvalid(par) then
		if par ~= "autourl" and par ~= "autourl2" and par ~= "autourl3" and par ~= "autourl4" then
			tid = formatFromPattern(result, options)
		end
	end
	return {value = tid}
end

function formatexternalid(datavalue, datatype, options)
	local result = formatcharacters(datavalue.value, options)
	if isntvalid(options.pattern) then
		return {value = result} --just return value
	end
	local patter =
		formatStatements({property = "P1630", entityId = options.property, firstvalue = "t", noref = "t", rank = "all"}) -- get formatter URL

	local par = options.pattern
	local tid = result

	if isvalid(patter) then -- if P1630 are there
		local pp = formatFromPattern(datavalue.value, {pattern = patter})
		local plabel = mw.wikibase.label(options.property) or pp
		local ppp = mw.ustring.gsub(pp, " ", "_")

		local results = {
			["autourl"] = ppp, -- like http://example.com/$1.html
			["autourl2"] = "[" .. ppp .. " " .. datavalue.value .. "]", -- like [http://example.com/$1.html $1]
			["autourl3"] = "[" .. ppp .. " " .. ppp .. "]", -- like [http://example.com/$1.html http://example.com/$1.html]
			["autourl4"] = "[" .. ppp .. " " .. plabel .. "]"
		}
		if results[par] then
			tid = results[par]
		else
			tid = formatFromPattern(result, options)
		end
	elseif isvalid(par) then
		if par ~= "autourl" and par ~= "autourl2" and par ~= "autourl3" and par ~= "autourl4" then
			tid = formatFromPattern(result, options)
		end
	end
	return {value = tid}
end

function formattime(datavalue, datatype, options)
	--[[  datatype	time  ]]
	local ModuleTime = require "Module:wikidata2/time"
	local timen = datavalue.value
	local tid = ModuleTime.getdate(timen, options)
	-- local tid = mw.getCurrentFrame():preprocess(mall)
	if isvalid(options.modifytime) then
		if options.modifytime == "q" then
			local mall = datavalue.value.time
			tid = mw.getCurrentFrame():preprocess(mall)
		elseif options.modifytime == "precision" then
			local mall = datavalue.value.precision
			tid = mw.getCurrentFrame():preprocess(mall)
		end
	end
	return {value = tid}
end

function formatcoordinate(datavalue, datatype, options)
	--[[  datatype	globe-coordinate  ]]
	--local GlobeCoordinate = require "Module:GlobeCoordinate"
	--return {value=GlobeCoordinate.newFromWikidataValue( datavalue.value ):toHtml()}
	if ModuleGlobes == nil then
		ModuleGlobes = require("Module:Wikidata2/Globes")
	end
	local coord = datavalue.value
	local globe = datavalue.value.globe
	local globe2 = ModuleGlobes[globe] or ""
	local results = {
		["latitude"] = coord.latitude,
		["longitude"] = coord.longitude,
		["dimension"] = coord.dimension,
		["precision"] = coord.precision,
		["globe"] = globe:match("Q%d+"),
		["globe2"] = globe2
	}

	local pro = options.formatting and results[options.formatting]
	if pro == nil then
		pro =
			mw.getCurrentFrame():preprocess(
			"{{ {{{|safesubst:}}}#invoke:Coordinates|coord" ..
			"|" .. coord.latitude ..
			"|" .. coord.longitude ..
			"|display=inline" ..
			"|globe:" .. globe2 .. "_type:landmark" ..
			"|format=" .. (options.formatcoord or "") .. "}}"
		) .. catewikidatainfo(options)
	end

	return {value = pro}
end

function formatquantity(datavalue, datatype, options)
	--[[  datatype quantity	 ]]
	local amount, unit = datavalue.value.amount, datavalue.value.unit
	amount = mw.ustring.gsub(amount, "+", "")
	if unit then
		unit = unit:match("Q%d+")
	end
	if formatera == nil then
		formatera = require("Module:Wikidata2/Math")
	end
	local number = formatera.newFromWikidataValue(datavalue.value)
	local unitraw = unit
	if unit then
		-- يتحقق اذا كان هناك اي اختصار لوحدة القياس
		--if lab and ( isntvalid(options.nounitshort) ) then
		if isvalid(options.unitshort) then
			local lab =
				options.label or formatStatements({property = "P498", entityId = unit, firstvalue = "t", noref = "t"}) or
				formatStatements(
					{property = "P5061", entityId = unit, firstvalue = "t", langpref = options.langpref, noref = "t"}
				) or
				""
			local s =
				formatEntityId(unit, {label = lab, enlabelcate = "t", nolink = (options.nounitlink or options.nolink)})
			unit = s.value
		else
			local s = formatEntityId(unit, {nolink = options.nounitlink, enlabelcate = "t"})
			unit = s.value
		end
	end
	if options.formatcharacters and options.formatcharacters == "formatnum" then
		amount = make_format_num(amount)
	end
	local Value = amount .. " " .. (unit or "")
	if isvalid(options.nounit) then
		Value = amount
	end
	return {value = Value, amount = amount, unit = unit, unitraw = unitraw}
end

function formaturl(datavalue, datatype, options)
	--[[  datatype	url	 ]]
	local label = options.label
	if isvalid(options.urllabel) then
		label = options.urllabel
	end
	local va = mw.ustring.gsub(datavalue.value, " ", "_")
	if label == nil and options.property == "P856" then
		label = "الموقع الرسمي"
	end
	if isvalid(options.displayformat) == "weblink" then
		if weblink == nil then
			weblink = require("Module:Weblink")
		end
		return {value = weblink.makelink(va)}
	end
	if isvalid(options.formatting) == "raw" then
		return {value = va}
	end
	local pro = va
	if isvalid(label) then
		pro = "[" .. va .. " " .. label .. "]"
	end
	return {value = pro}
end

function formatmonolingualtext(datavalue, datatype, options) -- showlang
	local text = datavalue.value.text
	if isvalid(options.textformat) == "text" then
		return {value = text}
	end
	if Moduletext == nil then
		Moduletext = require "Module:wikidata2/monolingualtext"
	end
	local tid = Moduletext._main(datavalue, datatype, options)
	return {value = tid}
end

function formatDatavalue(datavalue, datatype, options)
	--Use the customize handler if provided
	if options["value-module"] or options["value-function"] then
		if not options["value-module"] or not options["value-function"] then
			return {value = formatError("unknown-value-module")}
		end
		local formatter = require("Module:" .. options["value-module"])
		if not formatter then
			return {value = formatError("value-module-not-found")}
		end
		local fun = formatter[options["value-function"]]
		if not fun then
			return {value = formatError("value-function-not-found")}
		end
		return {value = fun(datavalue, datatype, options)}
	end

	--Default dataformatters
	local dataformatters = {
		["wikibase-item"] = formatwikibaseitem,
		["wikibase-property"] = formatwikibaseproperty,
		["commonsMedia"] = formatcommonsMedia,
		["math"] = formatmath,
		["time"] = formattime,
		["external-id"] = formatexternalid,
		["string"] = formatstring,
		["globe-coordinate"] = formatcoordinate,
		["quantity"] = formatquantity,
		["url"] = formaturl,
		["monolingualtext"] = formatmonolingualtext,
		["geo-shape"] = formatgeoshape,
		["tabular-data"] = formattabulardata
	}

	local dataformatter = dataformatters[datatype]
	if not dataformatter then
		return {value = formatError("unknown-data-type")}
	end
	return dataformatter(datavalue, datatype, options)
end

function Labelfunction(qid, arlabel, options) -- label with no arwiki sitelink
	local value
	local cat = ""
	local use_en_label = isvalid(options.enlabelcate) or isvalid(options.use_en_labels)
	local Args = {fromlua = "t", ["المعرف"] = qid, nocat = "t"}
	if isvalid(options.illwd2noy) then
		Args.noy = "t"
	end
	if isvalid(options.illwd2y) then
		Args.y = "t"
	end

	if isvalid(arlabel) then
		value = arlabel
		if isvalid(options.illwd2) then
			Args.label = arlabel
			value = mw.getCurrentFrame():expandTemplate {title = "Ill-WD2", args = Args}
		end
	elseif isntvalid(options.justarabic) then
		-- else
		--cat = " [[".. i18n.noarabiclabel .."|".. qid .."]]"
		local en_label = mw.wikibase.label(qid) or ""
		if isvalid(options.illwd2noarlabel) then
			if isvalid(en_label) then
				Args.enlabel = en_label
			end
			value = mw.getCurrentFrame():expandTemplate {title = "Ill-WD2", args = Args}
		elseif use_en_label and isvalid(en_label) then
			value = en_label
		end
	end
	return {value = value or "", cat = cat}
end

function formatEntityId(qid, options)
	local labeloption = options.label
	local label = ""
	local value
	local arlabel = labelIn("ar", qid) or "" -- The arabic label
	local link = mw.wikibase.sitelink(qid)

	if isvalid(labeloption) then
		label = labeloption
	elseif isvalid(arlabel) then
		--mw.log("arlabel" .. arlabel)
		label = arlabel
	elseif isvalid(link) then
		label = link
		arlabel = link
	end

	if isvalid(link) then
		-- elseif isvalid(arlabel) then
		local linklabel = isvalid(label) or link
		if (isntvalid(options.nolink)) then
			value = "[[:" .. link .. "|" .. formatcharacters(linklabel, options) .. "]]"
			label = linklabel
		else
			value = formatcharacters(linklabel, options)
			label = linklabel
		end
	else
		local va = Labelfunction(qid, arlabel, options)
		label = va.value
		value = va.value -- .. va.cat
	end
	return {value = value or "", label = label or ""}
end

function sitelink_g(id, wikisite)
	--[[ function to get any link from any sister project ]]
	local site = wikisite or "arwiki"
	local link = mw.wikibase.sitelink(id, site) or ""
	--mw.log("mw.wikibase.sitelink,site: " .. site.. ",link:" .. link )
	return link
end

function sitelink(id, wikisite)
	local site = wikisite or "arwiki"
	local link = ""
	--local link = mw.wikibase.getSitelink( id, site ) or ""

	local entity = mw.wikibase.getEntityObject(id)
	if
		entity and entity.sitelinks and entity.sitelinks["" .. site .. ""] and entity.sitelinks["" .. site .. ""].site and
			entity.sitelinks["" .. site .. ""].title
	 then
		if entity.sitelinks["" .. site .. ""].site == site then
			link = entity.sitelinks["" .. site .. ""].title
		end
	end
	return link
end

function formatsitelink(entityId, options)
	--[[ function to get only the value with link ]]
	local link = sitelink(entityId)
	if isvalid(link) and isntvalid(options.nolink) then
		return "[[" .. link .. "]]" .. catewikidatainfo(options)
	end
	return link
end

function formatFromPattern(str, options)
	-- [[  function to replace $1 with string  ]]
	if isvalid(options.pattern) then
		str = string.gsub(str, "%%", "%%%%")
		str = mw.ustring.gsub(options.pattern, "$1", str)
	end
	return str
end

function p.getEntity(id)
	if type(id) == "table" then
		return id
	end
	return getEntityFromId(id)
end

function p.translate(str, rep1, rep2)
	str = i18n[str] or str
	if rep1 and (type(rep1) == "string") then
		str = str:gsub("$1", rep1)
	end
	if rep2 and (type(rep2) == "string") then
		str = str:gsub("$2", rep2)
	end
	return str
end

function p.getId(snak)
	if (snak.snaktype == "value") then
		if snak.datavalue.type == "wikibase-entityid" then
			return "Q" .. snak.datavalue.value["numeric-id"]
		end
	end
end

function p.addLinkBack(str, id, property)
	if not id then
		id = p.getEntity()
	end
	if not id then
		return str
	end
	if type(property) == "table" then
		property = property[1]
	end
	if type(id) == "table" then
		id = id.id
	end
	local class = ""
	if property then
		class = "wd_" .. string.lower(property)
	end
	local icon = "[[File:Blue pencil.svg|%s|10px|baseline|class=noviewer|link=%s]]"
	local title = i18n["see-wikidata-value"]
	local url = mw.uri.fullUrl("d:" .. id, "uselang=ar")
	url.fragment = property
	url = tostring(url)
	local v =
		mw.html.create("span"):addClass(class):wikitext(str):tag("span"):addClass("noprint wikidata-linkback"):css(
		"padding-left",
		"0.5em"
	):wikitext(icon:format(title, url)):allDone()
	return tostring(v)
end

-- Function to check whether a certain item is a parent of a given item.
-- If pExitItem is reached without finding the searched parent item, the search stops.
-- A parent is connected via P31 or P279.
-- Attention: very intensive function, use carefully!
function isParent(property, pItem, pParent, pExitItem, pMaxDepth, pDepth)
	if not pDepth then
		pDepth = 0
	end

	local entity = mw.wikibase.getEntity(pItem)
	if not entity then
		return false
	end
	local claims31
	local claims279
	if entity.claims then
		if isvalid(property) then
			claims31 = entity.claims[property]
		else
			claims31 = entity.claims["P31"]
			claims279 = entity.claims["P279"]
		end
	else
		return false
	end
	if not claims31 and not claims279 then
		return false
	end
	local parentIds = {}
	if claims31 and #claims31 > 0 then
		for i, v in ipairs(claims31) do
			parentIds[#parentIds + 1] = p.getId(v.mainsnak)
		end
	end
	if claims279 and #claims279 > 0 then
		for i, v in ipairs(claims279) do
			parentIds[#parentIds + 1] = p.getId(v.mainsnak)
		end
	end
	-- check if searched parent or exit item is reached or do recursive call
	if not parentIds[1] or #parentIds == 0 then
		return false
	end
	local itemString = ""
	local result = nil
	for i, qid in ipairs(parentIds) do
		if not qid then
			return false
		end
		--itemString = "Q" .. v
		itemString = qid
		if itemString == pParent then
			-- successful!
			return true
		elseif itemString == pExitItem then --or itemString == "Q35120"
			-- exit if either "exit item" or node item (Q35120) is reached
			return false
		else
			if pDepth + 1 < pMaxDepth then
				result = isParent(property, itemString, pParent, pExitItem, pMaxDepth, pDepth + 1)
			else
				return false
			end

			if result == true then
				return result
			end
		end
	end
	do
		return false
	end
end

function p.Subclass(options)
	if options then
		Frame_args = options
	end
	local parent = options.parent or ""
	local id = options.id or ""
	local Entity = getEntityFromId(id)
	if Entity then
		id = Entity.id
	end
	local property = options.property or "P31"
	if isntvalid(parent) or isntvalid(id) or isntvalid(property) then
		return false
	end
	local tab = mw.text.split(options.parent, ",")
	local result = mw.wikibase.getReferencedEntityId(id, property, tab) -- { "Q5", "Q2095" } )
	if result == nil and property == "P31" then
		result = mw.wikibase.getReferencedEntityId(id, "P279", tab)
	end
	if result then
		return true
	end
end

function old_isSubclass(options)
	if isntvalid(options.parent) then
		return false
	end
	local maxDepth
	maxDepth = tonumber(options.maxDepth) or 10
	if not type(maxDepth) == "number" then
		maxDepth = 5
	end
	local property = options.property
	local result
	result = isParent(property, options.id, options.parent, options.exitItem, maxDepth)
	if options.returnInt then
		if result == true then
			return 1
		else
			return nil
		end
	else
		return result
	end
end

function p.formatSnak(snak, options)
	return formatSnak(snak, options)
end

function p.formatEntityId(entityId, options)
	return formatEntityId(entityId, (options or {}))
end

function p.formatStatements(frame, key)
	if frame.args then
		if type(key) == "table" and key ~= {} then
		else
			Frame_args = frame.args
		end
	end
	--[[ The main function ]]
	local args = frame.args
	--If a value if already set, use it
	if isvalid(args.value) then
		return args.value
	end
	local wd_arg = frame:getParent().args["ويكي بيانات"] or frame.args["ويكي بيانات"] -- arg used to ban wikidata value
	if isvalid(wd_arg) == "لا" then
		return ""
	end

	local valuesnumb = 0
	local s
	local prop = formatStatements(args, key)
	if isvalid(args.returnnumberofvalues) then
		s, valuesnumb = formatStatements(frame.args, key)
	end
	if isvalid(prop) then
		if isvalid(args.mainprefix) then -- mainprefix
			prop = args.mainprefix .. prop
		end
		if isvalid(args.mainsuffix) then -- mainsuffix
			prop = prop .. args.mainsuffix
		end
		if isvalid(args.addTrackingCat) then -- add tracking cat
			prop = prop .. addTrackingCategory(frame.args)
		end
		if isvalid(args.mainsuffixAfterIcon) then -- another suffix but after wikidata icon
			prop = prop .. args.mainsuffixAfterIcon
		end
	else
		if isvalid(args.NoPropValue) then -- value if no local value and no wikidata value
			prop = args.NoPropValue
		end
	end
	if isvalid(args.returnnumberofvalues) then
		mw.log("valuesnumb: " .. valuesnumb)
		return s, valuesnumb
	end
	return prop
end

function p.formatStatementsFromLua(options, key) --	 main function but to use from lua module
	if options then
		if type(key) == "table" and key ~= {} then
		else
			Frame_args = options
		end
	end

	--If a value if already set, use it
	if isvalid(options.value) then
		return options.value
	end
	local valuesnumb = 0
	local s = formatStatements(options, key)
	if isvalid(options.returnnumberofvalues) then
		s, valuesnumb = formatStatements(options, key)
	end
	if isntvalid(s) then
		s = nil
	end
	if isvalid(s) then
		if isvalid(options.mainprefix) then -- mainprefix
			s = options.mainprefix .. s
		end
		if isvalid(options.mainsuffix) then -- mainsuffix
			s = s .. options.mainsuffix
		end
		if isvalid(options.addTrackingCat) then -- add tracking cat
			s = s .. addTrackingCategory(options)
		end
		if isvalid(options.mainsuffixAfterIcon) then -- another suffix but after wikidata icon
			s = s .. options.mainsuffixAfterIcon
		end
	else
		if isvalid(options.NosValue) then -- value if no local value and no wikidata value
			s = options.NosValue
		end
	end
	if isvalid(options.returnnumberofvalues) then
		--	mw.log( "valuesnumb: " .. valuesnumb )
		return s, valuesnumb
	end
	return s
end

function p.isSubclass(frame)
	return p.Subclass(frame.args)
end

-- Return the site link for a given data item and a given site (the current site by default)

function p.getSiteLink(frame)
	local site = frame.args[2] or frame.args.site
	local id = frame.args[1] or frame.args.id
	local count = frame.args.countsitelinks
	if isntvalid(id) then
		if isvalid(frame.args.page) then
			id = mw.wikibase.getEntityIdForTitle(frame.args.page)
		end
	end
	if isvalid(count) then
		return countSiteLinks(id)
	end
	local link = sitelink(id, site)
	if isvalid(link) then
		return link
	end
end

function p.getSiteLink1(frame)
	local project = frame.args[1]
	local id = frame.args[2]
	local link = sitelink(id, project)
	return link
end

-- returns the page id (Q...) of the current page or nothing of the page is not connected to Wikidata
function p.pageId(frame)
	return mw.wikibase.getEntityIdForCurrentPage()
end

function p.descriptionIn(frame)
	local langcode = frame.args[1] or frame.args["lang"]
	local id = frame.args[2] or frame.args["id"]
	return descriptionIn(langcode, id)
end

function p.labelIn(frame)
	local langcode = frame.args[1] or frame.args["lang"]
	local id = frame.args[2] or frame.args["id"]
	return labelIn(langcode, id)
end

function p.getLabel(entity, lang)
	return labelIn(lang, entity)
end

function p.ViewSomething(frame) -- from en:Module:Wikidata
	local f = (frame.args[1] or frame.args.id) and frame or frame:getParent()
	local aa
	if isvalid(f.args.id) then
		aa = f.args.id
	end
	local data = mw.wikibase.getEntityObject(aa)
	if data == nil then
		return nil
	end
	local i = 1
	while true do
		local index = f.args[i]
		if index == nil then
			if type(data) == "table" then
				return mw.text.jsonEncode(data, mw.text.JSON_PRESERVE_KEYS + mw.text.JSON_PRETTY)
			else
				return tostring(data)
			end
		end
		data = data[index] or data[tonumber(index)]
		if data == nil then
			return
		end
		i = i + 1
	end
end

function p.Dump(frame)
	local f = (frame.args[1] or frame.args.id) and frame or frame:getParent()
	local aa
	if isvalid(f.args.id) then
		aa = f.args.id
	end
	local data = mw.wikibase.getEntityObject(aa)
	if data == nil then
		return i18n.warnDump
	end
	local i = 1
	while true do
		local index = f.args[i]
		if index == nil then
			return frame:extensionTag("source", mw.dumpObject(data), {lang = "lua"}) .. i18n.warnDump
		end
		data = data[index] or data[tonumber(index)]
		if data == nil then
			return i18n.warnDump
		end
		i = i + 1
	end
end

function p.countSiteLinks(id)
	return countSiteLinks(id)
end

function p.EntityIdForTitle(frame)
	local title = frame.args[1]
	local str = mw.wikibase.getEntityIdForTitle(title)
	--mw.log(str)
	return str
end

function p.Qidfortitleandwiki(frame)
	local title = frame.args[1]
	local wiki = frame.args[2]
	local str = mw.wikibase.getEntityIdForTitle(title, wiki)
	return str
end

return p