local p = {}
local Frame_args = {}
local Moduletext
local Modulecite
local flags
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"] = "[[تصنيف: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 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 (isvalid(options.nolink) == nil) then
        return cat
    else
        return ""
    end
end

function getqualifierbysortingproperty(claim, sortingproperty)
	for k, v in pairs(sortingproperty) do
		if claim.qualifiers and claim.qualifiers[v] and claim.qualifiers[v][1].snaktype == "value" then
			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 getDate(claim, options)
	local sortingproperty = sortingproperties
	if type(options.sortingproperty) == "table" then
		sortingproperty = options.sortingproperty
	elseif type(options.sortingproperty) == "string" and options.sortingproperty ~= "" then
		sortingproperty = {options.sortingproperty}
	end
	return getqualifierbysortingproperty(claim, sortingproperty)
end

function get_entityId(options)
	local id = options.entityId or options.entityid or options.id or options.qid
	if isvalid(id) == nil then
		if isvalid(options.page) then
			id = mw.wikibase.getEntityIdForTitle( options.page )
		end
	end
	--mw.log("id :" .. id)
	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 isvalid(formatch) == nil 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 isvalid(langcode) == nil 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 isvalid(langcode) == nil 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 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" then
			return comparedates(timeB, timeA)
		else
			return comparedates(timeA, timeB)
		end
	end
	)
	return claims
end

function dontget(claims, options)
	-- options.dontget
	-- options.dontgetproperty
	local claims2 = {}
	for i, j in pairs(claims) do
		local id = get_snak_id(j)
		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 k, state in pairs(t2) do
					for j2, falseqid in pairs(mw.text.split(options.dontget, ",")) do
						if state.item == falseqid then
							valid = false
                            break
						end
					end
				end
			end
			if valid then
				table.insert(claims2, j)
			end
		end
	end
	return claims2
end

function getonly(claims, options)
	-- options.getonly
	-- options.getonlyproperty
	local claims2 = {}
	--mw.log("wikidata2 : getonly:" .. options.getonly )
	for i, j in pairs(claims) do
		local id = get_snak_id(j)
		--if j.mainsnak and j.mainsnak.snaktype == "value" and j.mainsnak.datavalue and j.mainsnak.datavalue.value and j.mainsnak.datavalue.value.id then
			--local id = j.mainsnak.datavalue.value.id
		if id then
			local traff = false
			local t2 = formatStatements({property=(options.getonlyproperty or "P31"), entityId=id, noref="t", raw="t" })
			if t2 and #t2 > 0 then
				for k, state in pairs( t2 ) do
					for j2, only in pairs(mw.text.split(options.getonly,",")) do
						if state.item == only then
							traff = true
						end
					end
				end
			end
			if traff then
				table.insert(claims2, j)
			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)
	-- options.avoidvalue
	-- to avoid values
	local claims4 = {}
	local add2claims
	local avoidvalue
	if(type(options.avoidvalue) == "string") then avoidvalue = mw.text.split(options.avoidvalue,",")
		elseif(type(options.avoidvalue) == "table") then avoidvalue = options.avoidvalue
			else return claims
	end
	--mw.log("avoidvalue: " .. mw.dumpobject(options.avoidvalue))
	for i, j in pairs( claims ) do
		--mw.log("t:" .. t)
		ID = get_snak_id(j)
		add2claims = true
		if ID then
		    for k, t in pairs(avoidvalue) do
				--mw.log("ID: " .. ID)
				if ID == t then
					add2claims = false
				end
			end
			if add2claims then
				table.insert( claims4, j)
			end
		end
	end
	return claims4
end

function prefervalue(claims, options)
	local claims3 = {}
	--mw.log("prefervalue: " .. mw.dumpobject(options.prefervalue))
	local prefervalue
	if(type(options.prefervalue) == "string") then prefervalue = mw.text.split(options.prefervalue,",")
		elseif(type(options.prefervalue) == "table") then prefervalue = options.prefervalue
			else return claims
	end
	for k, t in pairs(prefervalue) do
		--mw.log("t:" .. t)
		for i, j in pairs( claims ) do
			local active = false
			ID = get_snak_id(j)
			if ID then
				--mw.log("ID: " .. ID)
				if ID == t and not active then
					table.insert( claims3, j)
					active = true
					--mw.log("ID == t" .. t)
				end
			end
		end
	end
	return claims3
end

function preferqualifier(claims, options)
	-- options.preferqualifier
	-- options.preferqualifiervalue
	mw.log("preferqualifier: " .. options.preferqualifier)
	local claims2 = {}
	for i, statement in pairs( claims ) do --
		if statement.qualifiers and statement.qualifiers[options.preferqualifier:upper()] then
			if isvalid(options.preferqualifiervalue) then
				local active = false
				for k, t in pairs(mw.text.split(options.preferqualifiervalue,",")) do
					--mw.log( "t " .. t )
					--kaso = formatStatements({property=options.preferqualifier:upper(), raw="t", formatting="raw"}, statement.qualifiers)
					----kaso = formatStatements({property=options.preferqualifier:upper(), formatting="raw"}, statement.qualifiers)
					----value = kaso
					for ii, quall in pairs( statement.qualifiers[options.preferqualifier:upper()] ) do
						--mw.log( "value " .. value )
						snaktype = quall.snaktype
						if snaktype == "value" then
							ty = quall.datavalue.value["id"]
							if ty and ty == t and not active then
								--if value == t and not active then
									table.insert( claims2, statement)
									active = true
								--end
							end
						end
					end
				end
			else
				table.insert( claims2, statement)
			end
		end
	end
	return claims2
end

function avoidqualifier(claims, options)
	-- options.avoidqualifier
	-- options.avoidqualifiervalue
	if isvalid(options.avoidqualifier) == nil then return claims end
	local av = options.avoidqualifier:upper()
	local claims2 = {}
	for i, statement in pairs( claims ) do
		if not statement.qualifiers or not statement.qualifiers[options.avoidqualifier:upper()] then
			table.insert( claims2, statement)
		elseif statement.qualifiers and statement.qualifiers[av] then
			if isvalid(options.avoidqualifiervalue) then
				list = {}
				if(type(options.avoidqualifiervalue) == "string") then
					list = mw.text.split(options.avoidqualifiervalue,",")
				elseif(type(options.avoidqualifiervalue) == "table") then
					list = options.avoidqualifiervalue
				end
				local active = true
				for k, t in pairs( list ) do
					for ii, quall in pairs( statement.qualifiers[av] ) do
						if quall.snaktype == "value" and quall.datavalue and quall.datavalue.value and quall.datavalue.value["id"] then
							if quall.datavalue.value["id"] == t then
								active = false
							end
						end
					end
				end
				if active then
					table.insert( claims2, statement)
				end
			end
		end
	end
	return claims2
end

function claims_limit(claims,limit)
	local newclaims = {}
	local ic = 0
	if #claims > limit then -- limit is not 0
	    for i = 1, #claims do
	        if i <= limit then
	            newclaims[ic] = claims[i]
	            ic = ic + 1
	        end
	    end
	end
	return newclaims
end

function claims_offset(claims,offset)
	local offsetclaims = {}
	local ic = 1
	if #claims > offset then -- offset is not 0
	    for i = 1, #claims do
	        if i > offset then
	            offsetclaims[#offsetclaims + 1] = claims[i]
	        end
	    end
	end
	return offsetclaims
end

function filter_claims( claims, options)
	local claims = claims
	
	local offset = options.offset
	if isvalid(offset) and type(offset) ~= "number" then
		offset = tonumber(offset)
		claims = claims_offset(claims,offset)
	end
	
	local limit = options.limit
	if isvalid(limit) and type(limit) ~= "number" then
		limit = tonumber(limit)
		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
	
	if isvalid(options.langpref) == nil then
		local claims7 = {}
		for i, statement in pairs( claims ) do
			if statement.qualifiers and statement.qualifiers.P407 then
				for k, v in pairs( statement.qualifiers.P407 ) do
					if v.snaktype == "value" and v.datavalue.value["numeric-id"] == 13955 then -- Q13955 = "العربية"
						table.insert( claims7, statement )
					end
				end
			elseif statement.qualifiers and statement.qualifiers.P282 then
				for k, v in pairs( statement.qualifiers.P282 ) do
					if v.snaktype == "value" and v.datavalue.value["numeric-id"] == 8196 then -- Q8196 = "أبجدية عربية"
						table.insert( claims7, statement )
					end
				end
			end
		end
		if #claims7 > 0 then
			claims = claims7
		end
	end
	
	local sortingmethod = options.sortbyarbitrary or options.sortingmethod
	local sorting_properties = {}

	if (type(options.sortingproperty) == "table") then
		sorting_properties = options.sortingproperty

	elseif (type(options.sortingproperty) == "string") and options.sortingproperty ~= "" then
		sorting_properties = mw.text.split(options.sortingproperty,",") --{options.sortingproperty}
	end

	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, options, sorting_properties)

	elseif isvalid(sortingmethod) and sorting_methods[sortingmethod] then
		claims = sortbyarb(claims, sorting_properties, options)
	end
	
	local firstvalue = options.enbarten or options.firstvalue
	local first = isvalid(tonumber(firstvalue))
	if isvalid(first) and #claims > 1 then
		if first > 0 and #claims > first then
			claims = {claims[first]}
		elseif first == "2" and #claims > 1 then
			claims = {claims[2]}
		elseif first == "3" and #claims > 2 then
			claims = {claims[3]}
		elseif first == "4" and #claims > 3 then
			claims = {claims[4]}
		elseif first == "5" and #claims > 4 then
			claims = {claims[5]}
		elseif first == "6" and #claims > 5 then
			claims = {claims[6]}
		elseif first == "7" and #claims > 6 then
			claims = {claims[7]}
		elseif first == "8" and #claims > 7 then
			claims = {claims[8]}
		elseif first == "9" and #claims > 8 then
			claims = {claims[9]}
		else
			claims = {claims[1]}
		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 sortbyqualifier(claims, sortingproperty,options)
	table.sort(claims, function(a,b)
		local timeA = getqualifierbysortingproperty(a, sortingproperty)
		local timeB = getqualifierbysortingproperty(b, sortingproperty)
		if options.sortbytime == "inverted" then
			return comparedates(timeB, timeA)
		else
			return comparedates(timeA, timeB)
		end
	end
	)
	return claims
end

function sortbyqualifiernumber(claims, options, sorting_properties)
	if not sorting_properties then
		if (type(options.sortingproperty) == "table") then
			sorting_properties = options.sortingproperty
		elseif (type(options.sortingproperty) == "string") and options.sortingproperty ~= "" then
			sorting_properties = mw.text.split(options.sortingproperty,",")
		else
			sorting_properties = sortingproperties
		end
	end
	table.sort(claims, function(a,b)
		local timeA = getqualifierbysortingproperty(a, sorting_properties)
		local timeB = getqualifierbysortingproperty(b, sorting_properties)
		if options.sortbynumber == "inverted" then
			return comparedates(timeB, timeA)
		else
			return comparedates(timeA, timeB)
		end
	end
	)
	return claims
end

function getEntityFromId( id )
	if isvalid(id) then
	--	if not(mw.wikibase.isValidEntityId(id)) or not(mw.wikibase.entityExists(id)) then
		--	return false
		--end
		return mw.wikibase.getEntityObject( id )
	else
		return mw.wikibase.getEntityObject()
	end
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 isvalid(s) == nil then
		return { v = value, raw=stat}
	end

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

	local P585 = stat.qualifiers.P585 or ""
	local tf = stat.tifr
	local awardqual = stat.foto
	local pr = stat.pr
	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
	local QPrefix = isvalid(options.qualifierprefix)
	local QSuffix = isvalid(options.qualifiersuffix)

	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, 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

	if isvalid(qp1) and options.qual1 and 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(options.withdate) then
		if isvalid(P585) 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
	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 not 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 -- f?r de fall d?r funktionen anropas och alla claims redan finns i en tabell
		claims = LuaClaims[options.property] or {}
	else
    	--Get entity
    	local entity = nil
    	if options.entity and type( options.entity ) == "table" then
        	entity = options.entity
    	else
        	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()
    	--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
	    	end
    	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 not 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")
		Conjunction = mw.text.tag("br")
	end
	if Separator == "*" then
		priff = "\n*"
		Separator = "\n*"
		Conjunction = "\n*"
	end
	if Separator == "#" then
		priff = "\n#"
		Separator = "\n#"
		Conjunction = "\n#"
	end
	if isvalid(options.justref) then 
		priff = ""
		Separator = ""
		Conjunction = ""
	end
	local tot = mw.text.listToText( valuetable, Separator, Conjunction )
	if #valuetable > 1 then
		tot = priff .. tot
	end

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

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

function formatReferences( statement, options )
	local ic = 1
	local s
	local statementreferences = statement.references
	local reference = {}
	local numberofref = tonumber(options.numberofreferences) or 7
	if statementreferences then
		if Modulecite == nil then
			Modulecite = require(citetitle)
		end
		for i, ref in pairs( statementreferences ) do
			if ref.snaks then
				if numberofref >= ic then
					s = Modulecite._cite_wikidata(ref, options.entityId or options.qid)
                    if isvalid(s) then
						ic = ic + 1
						table.insert(reference, s)
					end
				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
    	if isvalid(options.somevalue) then
			return {value=options.somevalue}
		end
		return {value=i18n["somevalue"]}

	elseif snak.snaktype == "novalue" then
    	if isvalid(options.novalue) then
			return {value=options.novalue}
    	end
        return {value=i18n["novalue"]}

    elseif snak.snaktype == "value" then
		local s = formatDatavalue( snak.datavalue, snak.datatype, options )
    	if s and s.value and isvalid(s.value) and isvalid(options.prefix) then
    		s.value = options.prefix .. s.value
    	end
    	if s and s.value and isvalid(s.value) and isvalid(options.suffix) then
    		s.value = s.value .. options.suffix
    	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 not formatter then
            return {value=formatError( "claim-module-not-found" )}
        end
        local fun = formatter[options["claim-function"]]
        if not fun 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
	caca = ""
	local size = options.size or ""
	if size == "" then size = "20" end
	if work_flag then
		if flags == nil then
			flags = require("Module:Wikidata2/Flags")
		end
		local flag = flags[item]
		if isvalid(flag) == nil 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 = "[[ملف:" .. 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 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 ]]
	data= "[[commons:" .. datavalue.value .. "|" .. datavalue.value .. "]]"
	return {value=data}
end

function formatgeoshape( datavalue, datatype, options )
 --[[  geo-shape  ]]
	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 = "[[ملف:" .. 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 )
		--tid = "[[ملف:" .. datavalue.value  .. "|".. (options.size or "20").."px|border]]"
		--if isvalid(options.center) then
			--tid = "[[ملف:" .. datavalue.value  .. "|".. (options.size or "20").."px|border|center]]"
		--end
	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 isvalid(options.pattern) == nil 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 globe = globe:match("Q%d+")
	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 = ""
	if isvalid(options.formatting) then
		pro = results[options.formatting]
	else
		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 ( isvalid(options.nounitshort) == nil ) 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
	va = mw.ustring.gsub( datavalue.value, " ", "_" )
	if not label 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 )
   	--[[functions = {
   		["P172"] = {["value-module"] ="Wikidata2/P172" ,["value-function"] ="get_P172_lab"} ,
   		["P106"] = {["value-module"] ="Wikidata2/P106" ,["value-function"] ="formatEntityWithGenderClaim"} ,
   	}
   	functions["P413"] = functions["P106"]
   	if ( isvalid(options["value-module"]) == nil )
   			or ( isvalid(options["value-function"]) == nil )
   		or  ( isvalid(options["property-module"]) == nil )
   			or ( isvalid(options["property-function"]) == nil )
   		or  ( isvalid(options["claim-module"]) == nil )
   			or ( isvalid(options["claim-function"]) == nil )
   	then
	   	if functions[options.property:upper()] then
	   		options["value-module"] = functions[options.property:upper()]["value-module"]
	   		options["value-function"] = functions[options.property:upper()]["value-function"]
	   	end
   	end]]
    --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 }
	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 isvalid(options.justarabic) == nil 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
		local linklabel = isvalid(label) or link
		if (isvalid(options.nolink) == nil) then
			value = "[[:" .. link .. "|" .. formatcharacters(linklabel, options) .. "]]"
			label = linklabel
		else
			value = formatcharacters(linklabel, options)
			label = linklabel
		end
    -- elseif isvalid(arlabel) then
	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 isvalid(options.nolink) == nil 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 = "[[ملف: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 parent == "" or id == "" or property == "" then return false end
	local tab = mw.text.split(options.parent,",")
	local result = mw.wikibase.getReferencedEntityId( id, property, tab  ) -- { "Q5", "Q2095" } )
	if not result and property == "P31" then
		result = mw.wikibase.getReferencedEntityId( id, "P279", tab  )
	end
	if result then return true end
end

function old_isSubclass(options)
	if not options.parent then return false end
	local maxDepth
	maxDepth = tonumber(options.maxDepth) or 10
	if not type(maxDepth) == "number" then maxDepth = 5 end
	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 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 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 isvalid(id) == nil 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 )
	var = link
	return var
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()
          if isvalid(f.args.id) then aa = f.args.id end
	local data = mw.wikibase.getEntityObject(aa)
	if not data then
		return nil
	end
	local i = 1
	while true do
		local index = f.args[i]
		if not index 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 not data 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()
	if isvalid(f.args.id) then aa = f.args.id end
	local data = mw.wikibase.getEntityObject(aa)
	if not data then
		return i18n.warnDump
	end
	local i = 1
	while true do
		local index = f.args[i]
		if not index then
			return frame:extensionTag("source", mw.dumpObject(data),{ lang= "lua"}).. i18n.warnDump
		end
		data = data[index] or data[tonumber(index)]
		if not data 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