local help_functions = require("Module:Wikidata2/functions")
local p = {}
local sorting_methods = help_functions.sorting_methods
local formatera
local Modulecite
local ModuleGlobes
local citetitle = "وحدة:Cite/نسخة"

local 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 get_entityId(options)
	local id = options.entityId or options.entityid or options.id or options.qid
	if isntvalid(id) then
		if isvalid(options.page) then
			id = mw.wikibase.getEntityIdForTitle( options.page )
		end
	end
	--mw.log("id :" .. id)
	return id or ""
end

function addTrackingCategory(prop, options)
	return prop
end

function catewikidatainfo(options)
	return ''
end

function dontget(claims, options)
	-- options.dontget
	-- options.dontgetproperty
	local claims2 = {}
	for i, j in pairs(claims) do
		local id = help_functions.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 = {}
	for i, j in pairs(claims) do
		local id = help_functions.get_snak_id(j)
		if id then
			local valid = 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
							valid = true
							break
						end
					end
				end
			end
			if valid then
				table.insert(claims2, j)
			end
		end
	end
	return claims2
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 formatError(key)
	return help_functions.i18n.errors[key]
end

function Labelfunction(entityId, label, labeloption, options) -- label with no arwiki sitelink

	if isvalid(options.illwd2nowd) then
		noWD = ""
	else
		noWD = "y"
	end
	local jlabel = label --help_functions.formatcharacters(label, options) -- The label
	local ar = help_functions.labelIn("ar", entityId) -- The arabic label
	--mw.log('ar'..ar)
	local arlabel = ar --help_functions.formatcharacters(ar, options)
	if isvalid(labeloption) then
		jlabel = labeloption
	elseif isvalid(options.illwd2) and isntvalid(options.nolink) then
		temp_args = {arlabel, ["المعرف"] = entityId}
		if isvalid(options.illwd2noy) then temp_args.noy = "t" end
		if isvalid(options.illwd2y) then temp_args.y = "t" end

		if isntvalid(arlabel) then
			temp_args.target = "en"
		end
		if isvalid(options.illwd2label) then
			 temp_args["text"] = options.illwd2label
		end
		jlabel = mw.getCurrentFrame():expandTemplate {title = "Ill-WD2",args = temp_args}
		
	elseif isvalid(options.enlabelcate) then
		if isntvalid(arlabel) then
			jlabel = label --help_functions.formatcharacters(label, options)
			if isvalid(jlabel) then
				jlabel = jlabel --.. " [[" .. help_functions.i18n.noarabiclabel .. "|" .. entityId .. "]]"
			end
		end
	else --if isvalid(options.justarabic) then
		if isvalid(arlabel) then
			jlabel = arlabel
		else
			jlabel = nil
		end
	end

	if isvalid(jlabel) then
		--mw.log('jlabel' .. jlabel )
		return jlabel .. catewikidatainfo(options)
	end
end

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

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

	local s = stat.value
	local P585 = stat.P585
	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
	local QPrefix
	local QSuffix
	if isntvalid(s) then s = nil end
	if s then
		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

		if isvalid(options.office2) then
			s =
				mw.getCurrentFrame():expandTemplate {
				title = "معلومات صاحب منصب/منصب ويكي بيانات2",
				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 "",
					P642 = stat.pp642
				}
			}
		end

		function qoo(Prefix, qualpref, p, Suffix)
			if isvalid(p) then
				stri = Prefix .. (qualpref or "") .. " " .. p .. Suffix
				return stri
			end
		end

		QPrefix = options.qualifierprefix or ""
		QSuffix = options.qualifiersuffix or ""
		--///////////////////

		if qp1 and options.qual1 and options.qual1 and qp1a and isvalid(options.qual1a) then
			s =
				s ..
				"، " ..
					qoo("", options.qual1pref, qp1, (options.qual1suff or "")) ..
						"، " .. qoo("", options.qp1apref, qp1a, (options.qp1asuff or ""))
		elseif qp1 and isvalid(options.qual1) then
			s = s .. "، " .. (options.qual1pref or "") .. qp1 .. (options.qual1suff or "")
		elseif qp1a and isvalid(options.qual1a) then
			s = s .. "، " .. (options.qp1apref or "") .. qp1a
		end

		if qp2 and isvalid(options.qual2) then
			q2 = qoo(QPrefix, (options.qual2pref or ""), qp2, QSuffix .. (options.qual2suff or ""))
			if options.qual2pref == "**" then
				q2 = "\n** " .. qoo(QPrefix, "", qp2, QSuffix .. (options.qual2suff or ""))
			end
			s = s .. q2
		end

		if qp3 and isvalid(options.qual3) then
			s = s .. qoo(QPrefix, options.qual3pref, qp3, QSuffix)
		end
		if qp4 and isvalid(options.qual4) then
			s = s .. qoo(QPrefix, options.qual4pref, qp4, QSuffix)
		end
		if qp5 and isvalid(options.qual5) then
			s = s .. qoo(QPrefix, options.qual5pref, qp5, QSuffix)
		end
		if isvalid(options.justthisqual) then
			if onlyqualifier then
				s = (options.qualifierprefix or "") .. 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 P585 and isvalid(options.withdate) then
			if options.withdate == "y" then
				s = s .. " (سنة " .. P585 .. ")"
			elseif options.withdate == "في" then
				s = s .. " في " .. P585
			else
				s = s .. QPrefix .. P585 .. QSuffix
			end
		end
		if awardqual and isvalid(options.awardqua) then
			s = s .. qoo(QPrefix, "", awardqual, QSuffix)
		end
		local bothdates = 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 = "(" .. tf .. ") " .. s
			else
				s = s .. qoo(QPrefix, "", tf, QSuffix)
			end
		end

		if type(ref) == 'table' or (isvalid(options.noref)) or 
		(isvalid(options.justthisqual)) 
			then
			vava = s
		else
			local t = formatReferences(statement, options)
			stat.ref = t
			if isvalid(options.justref) then
				vava = t
			elseif isvalid(options.onlyvaluewithref) then
				if isvalid(t) then
					vava = s .. t
				end
			else
				vava = s .. t
			end
		end
	end

	return {v = vava, raw = stat}
end

function filter_claims(claims, options)
	local claims = claims
	--===========
	-- options.getonly
	if isvalid(options.getonly) then
		claims = getonly(claims, options)
	end
	--===========
	-- options.dontget
	if isvalid(options.dontget) then
		claims = dontget(claims, options)
	end
	--===========
	claims = help_functions.filter_claims(claims, options)
	--===========
	return claims
end

function formatStatements(options, ref)
	local valuetable = {} -- formattedStatements
	local claims = {}
	
	if isntvalid(options.property) and isvalid(options.pid) then
		options.property = options.pid
	end
	
	if isntvalid(options.property) and isntvalid(options.pid) 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
	end
	if type(ref) == "table" then
		claims = ref[options.property] or {}
		mw.log("claims = ref[options.property]")
	else
		--===========
		--Get entity
		local qid = get_entityId(options)
		if isvalid(qid) then
			local check = mw.ustring.match( qid, "Q%d+" ) or mw.ustring.match( qid, "P%d+" )
			if check == nil then
				mw.addWarning(qid .. " لا يمثل معرف ويكي بيانات صحيح")
				return ""
			else
				options.entityId = qid
				options.qid = qid
			end
		else
			mw.addWarning("entityId غير معرف")
			return ""
		end
		local entity = nil
		if options.entity and type(options.entity) == "table" then
			entity = options.entity
		else
			entity = mw.wikibase.getEntityObject(qid)
		end
		--local property=mw.wikibase.resolvePropertyId(options.property:upper())
		local property=options.property:upper()

		if not entity then
			return ""
		end
		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 not property then
			return ""
		end
		if not entity.claims or not entity.claims[property] then
			return ""
		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
			--==========================================
			local numval1
			if isvalid(options.numval1) and type(options.numval1) ~= "number" then
				numval1 = tonumber(options.numval1)
			end
			for i, statement in pairs(claims) do
				options.num = i
				local va = formatOneStatement(statement, ref, options)
				if va.v then
					if numval1 then
						if numval1 > #valuetable then
							table.insert(valuetable, va.v)
						end
					else
						table.insert(valuetable, va.v)
					end
				end
				table.insert(statementsraw, va.raw)
			end
		end
	end
	local priff = ""
	local sep = "، و"
	if options.separator and options.separator == "" and options.conjunction and options.conjunction == "" then 
		sep = ""
	elseif isvalid(options.separator) == "br" or isvalid(options.conjunction) == "br" then 
		sep = "\n"
	elseif isvalid(options.separator) == "*" or isvalid(options.conjunction) == "*" or isvalid(options.sep) == "*" then
		priff = "\n*"
		sep = "\n*"
	elseif isvalid(options.separator) == "#" or isvalid(options.conjunction) == "#" or isvalid(options.sep) == "#" then
		priff = "\n#"
		sep = "\n#"
	elseif isvalid(options.separator) then
		sep = options.separator
	elseif isvalid(options.conjunction) then
		sep = options.conjunction
	end
	if isvalid(options.justref) then sep = "" end
	
	local tot = mw.text.listToText(valuetable, sep, sep)
	if #valuetable > 1 then tot = priff .. tot end

	if isntvalid(tot) then tot = nil 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
	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 formatReferences(statement, options)
	local reference = {}
	if statement.references then
		if Modulecite == nil then
			Modulecite = require(citetitle)
		end
		for i, ref in pairs(statement.references) do
			local s = nil
			if ref.snaks then
				s = Modulecite.citeitem( ref.snaks, ref.hash, options)
			end
			table.insert(reference, s)
		end
	end
	return table.concat(reference)
end

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

	s.ID = ""
	if statement.mainsnak.datavalue then
		s.ID = help_functions.getEntityIdFromValue(statement.mainsnak.datavalue.value)
	end

	if isvalid(options.template) then
		s.QQ1 = qua(options.Q1, "", "", options.Q1formatting)
		s.QQ2 = qua(options.Q2, "", "", options.Q2formatting)
		s.QQ3 = qua(options.Q3, "", "", options.Q3formatting)
		s.QQ4 = qua(options.Q4, "", "", options.Q4formatting)
		s.QQ5 = qua(options.Q5, "", "", options.Q5formatting)
		s.QQ6 = qua(options.Q6, "", "", options.Q6formatting)
		s.QQ7 = qua(options.Q7, "", "", options.Q7formatting)
		s.QQ8 = qua(options.Q8, "", "", options.Q8formatting)
		s.QQ9 = qua(options.Q9, "", "", options.Q9formatting)
		s.QQ10 = qua(options.Q10, "", "", options.Q10formatting)
	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 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.bothdates
	if isvalid(bothdates_option) then
		if statement.qualifiers.P580 or statement.qualifiers.P582 then
			local f = qua("P580", "true", options.modifyqualifiertime)
			if statement.qualifiers.P582 then
				local t = qua("P582", "true", options.modifyqualifiertime)
				s.tifr = f .. "–" .. t
				if not statement.qualifiers.P580 then
					s.tifr = "حتى " .. t
				end
			else
				s.tifr = "منذ " .. f
			end
		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

	function quaaal(opti, options)
		if isvalid(opti) and statement.qualifiers[opti] then
			kkk = formatStatements({property=opti,
					noref="t",
					separator = options.qualifierseparator,
					conjunction = options.qualifierconjunction,
					size = options.size,
					formatting = options.qualformatting,
					image = options.image,
					modifytime = options.modifyqualifiertime,
					enlabelcate = "t",
					langpref = options.langpref,
					showlang = options.showlang,
					illwd2 = "t",
					formatcharacters = options.formatcharacters
				},statement.qualifiers) or ""

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

	if s then
		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)
			if isntvalid(s.qp1) and options.qualformatting == "sitelink" then
				return nil
			end
		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)
			if isntvalid(s.qp2) and options.qualformatting == "sitelink" then
				return nil
			end
		end

		if isvalid(options.qual3) and statement.qualifiers[options.qual3] then
			s.qp3 = quaaal(options.qual3, options)
			if isntvalid(s.qp3) and options.qualformatting == "sitelink" then
				return nil
			end
		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
	return s
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
			if statement.qualifiers then
				s = 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 formatSnak(snak, options)
	if snak.snaktype == "somevalue" then
		if options.somevalue then
			if isntvalid(options.somevalue) then
				return nil
			else
				return {value = options.somevalue}
			end
		end
		return {value = help_functions.i18n["somevalue"]}
	elseif snak.snaktype == "novalue" then
		if options.novalue then
			if isntvalid(options.novalue) then
				return nil
			else
				return {value = options.novalue}
			end
		end
		return {value = help_functions.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 get_property1(options, item)
	--[[ function to get countries flags without reload large countries items ]]
	local property1 = options.property1
	local caca = formatStatements({property=options.property1, otherproperty = options.otherproperty1, entityId=item, 
				noref = options.noref, rank = options.property1rank, pattern = options.property1pattern, 
				formatting = options.property1formatting,  size = options.size, image = options.image, firstvalue="t"
			})
	return caca
end

function formatwikibaseitem(datavalue, datatype, options)
	--[[ datatype	wikibase-item  ]]
	local item = help_functions.getEntityIdFromValue(datavalue.value)
	local itemValue = formatEntityId(item, options).value
	local Format = options.formatting
	local Skipped = help_functions.skiip[options.property] or {}
	for k, v in pairs(Skipped) do
		if datavalue.value.id == v then
			return {value = ""}
		end
	end
	if isvalid(Format) then
		if Format == "raw" then
			--mw.log("raw: " .. item )
			return {value = item}
		elseif Format == "rawtotemplate" then
			--mw.log("options")
			--mw.log(options)
			if isvalid(options.rawtotemplate) then
				return {
					value = mw.getCurrentFrame():expandTemplate {
						title = options.rawtotemplate,
						args = {
							q = item,
							no1 = options.no1 or "",
							no2 = options.no2 or ""
						}
					} .. "\n"
				}
			end
		elseif Format == "fu" then
			fu_temp = "Cycling race/stageclassification2"
			return {value = mw.getCurrentFrame():expandTemplate {title = fu_temp, args = {item, type = "2"}}}
		elseif Format == "sitelink" then -- for Wikidata property giving Wikimedia list
			return {value = formatsitelink(datavalue.value.id, options)}
		elseif Format == "sitelink1" then
			return {value = formatsitelink1(datavalue.value.id, options)}
		else
			return {value = help_functions.formatFromPattern(help_functions.formatcharacters(datavalue.value, options), options)}
		end
	elseif isvalid(options.property1) and options.property1:upper():sub(1, 1) == "P" then
		for i, statement in pairs(datavalue) do
			caca = get_property1(options, item)
			if isvalid(itemValue) then
				if isvalid(caca) then
					cooooca = (options.property1pref or "") .. "" .. caca .. "" .. (options.property1suff or "")
					if isvalid(options.property1after) then
						return {value = itemValue .. cooooca}
					else
						return {value = cooooca .. " " .. itemValue}
					end
				else
					return {value = itemValue}
				end
			end
		end
	elseif isvalid(options.propertyimage) then
		------------------------------
		mw.log("propertyimage")
		local p_f = options.propertyimageformatting or options.formattingpropertyimage
		for i, statement in pairs(datavalue) do
			local vas = formatStatements({property=options.propertyimage,
					formatting = p_f,
					entityId=item,
					noref = options.noref,
					rank = options.rank,
					pattern = options.pattern,
					size = options.size,
					image = options.image,
					avoidvalue = options.avoidvaluepropertyimage,
					firstvalue="t",
					nolink = options.nolink
				})
			if isvalid(vas) then
				return {value = vas}
			end
		end
	elseif isvalid(options.property2) then
		------------------------------
		for i, statement in pairs(datavalue) do
			local caca = formatStatements({property=options.property2,
					entityId=item,
					noref = options.noref,
					rank = options.rank,
					pattern = options.property2pattern,
					size = options.size,
					image = options.image,
					propertyimage = options.property3,
					firstvalue="t"
				})
			if isvalid(itemValue) then
				if isvalid(caca) then
					return {value = caca .. " " .. itemValue}
				else
					return {value = itemValue}
				end
			end
		end
	elseif isvalid(options.cateforjop) then
		------------------------------
		for i, statement in pairs(datavalue) do
			local caca = formatStatements({property=options.cateforjop,
					entityId=item,
					noref="t",
					rank = options.rank,
					pattern = options.pattern,
					size = options.size,
					image = options.image,
					propertyimage = options.cateforjop1,
					firstvalue="t",
					formattingpropertyimage = options.formattingcateforjop,
					nolink = options.nolink
				})
			if isvalid(caca) then
				return {value = caca}
			else
			end
		end
	else
		return {value = formatEntityId(item, options).value, item = item}
	end
end

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

function formatcommonsMedia(datavalue, datatype, options)
	--[[  commonsMedia ]]
	local border = "border"
	if isvalid(options.center) then
		border = "center"
	end
	if isvalid(options.image) then
		tid = "[[file:" .. datavalue.value .. "|" .. (options.size or "120") .. "px|" .. border .. "]]"
	else
		tid = help_functions.formatcharacters(datavalue.value, options)
	end
	return {value = tid}
end

function formatexternalid(datavalue, datatype, options)
	local result = help_functions.formatcharacters(datavalue.value, options)
	if isntvalid(options.pattern) then
		return { value = result } --just return value
	end
	local par = options.pattern
	local patter = formatStatements({property="P1630", entityId=options.property, firstvalue="true", noref="true", rank="all"}) -- get formatter URL
	local po = help_functions.formatFromPattern(datavalue.value, {pattern = patter})
	local plabel = mw.wikibase.label(options.property) or po
	local ppp = mw.ustring.gsub(po, " ", "_")
	local tid = help_functions.formatFromPattern(result, options)

	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 isvalid(patter) then -- if P1630 are there
		if results[par] then
			tid = results[par]
		end
	else --	 P1630 are not there
		if par == "autourl" or par == "autourl2" or par == "autourl3" or par == "autourl4" then
			tid = result --just return value
		end
	end
	return {value = tid}
end

function formatcoordinate(datavalue, datatype, options)
	--[[ datatype  globe-coordinate]]
	local coord = datavalue.value
	local globe = datavalue.value.globe
	if ModuleGlobes == nil then
		ModuleGlobes = require("Module:Wikidata2/Globes")
	end
	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():expandTemplate { 
			title = "coord", args = { coord.latitude, coord.longitude, display = inline}
		} .. catewikidatainfo(options)
	end
	return {value = pro}
end

function formatquantity(datavalue, datatype, options)
	--[[ datatype quantity]]
	local amount = datavalue.value.amount
	local unit = datavalue.value.unit
	local cat
	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
		-- يتحقق اذا كان هناك اي اختصار لوحدة القياس
		local unitlab = isvalid(options.label) or 
		formatStatements({ property="P5061", entityId=unit, numval1="1", noref="t", langpref = "ar" }) 
		or ""

		if isvalid(unitlab) and isntvalid(options.nounitshort) then
			mw.addWarning("unitlab:" .. unitlab .. ", for unit: " .. unit)
			local s = formatEntityId(unit, {label = unitlab, nolink = (options.nounitlink or options.nolink)})
			unit = s.value
			cat = s.cat
		else
			local s = formatEntityId(unit, {nolink = options.nounitlink})
			unit = s.value
			cat = s.cat
		end
	end
	if options.formatcharacters and options.formatcharacters == "formatnum" then
		amount = help_functions.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, cat = cat}
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 isvalid(label) then
		pro = "[" .. va .. " " .. label .. "]"
	else
		pro = va
	end
	return {value = pro}
end

function formatmonolingualtext(datavalue, datatype, options)
	--[[ datatype	 monolingualtext ]]
	local langcode = datavalue.value.language
	local lang = mw.language.fetchLanguageName(langcode, "ar")
	local text = datavalue.value.text
	if isvalid(options.showlang) then
		text = text .. " (" .. lang .. ")"
	end
	local val = text
	if isvalid(options.langpref) then
		if options.langpref == "justlang" then
			val = lang
		elseif options.langpref == "langcode" then
			val = langcode
		elseif options.langpref == datavalue.value.language then
			val = text
		else
			val = ""
		end
	end
	return {value = val}
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,
		['external-id']			= formatexternalid,
		['globe-coordinate']	= formatcoordinate,
		['quantity']			= formatquantity,
		['url']					= formaturl,
		['monolingualtext']		= formatmonolingualtext,
		
		['time']				= help_functions.formattime,
		['tabular-data']		= help_functions.formattabulardata,
		['geo-shape']			= help_functions.formatgeoshape,
		['math']				= help_functions.formatmath,
		['string']				= help_functions.formatstring,
	}
	
	local dataformatter = dataformatters[datatype]
	if not dataformatter then
		return {value = formatError( 'unknown-data-type' )}
	end
	return dataformatter( datavalue, datatype, options )
	
end

function formatEntityId(entityId, options)
	local catinfo = catewikidatainfo( options )
	local label = options.label or mw.wikibase.label(entityId)
	if isntvalid(label) then
		label = mw.wikibase.label(entityId) or nil
	end
	local label_chart = help_functions.formatcharacters(label, options)

	local link = mw.wikibase.sitelink(entityId)
	
	local tab = {}
	tab.value = ""
	tab.label = label

	if isvalid(link) and isntvalid(options.nolink) then
		local link_chart = help_functions.formatcharacters(link, options)
		if isvalid(label) then
			tab.value = "[[" .. link .. "|" .. label_chart .. "]]" .. catinfo
			if link == label_chart then
				tab.value = "[[" .. link .. "]]" .. catinfo
			end
		else
			tab.label = link
			tab.value = "[[" .. link .. "|" .. link_chart .. "]]" .. catinfo
			if link == link_chart then
				tab.value = "[[" .. link .. "]]" .. catinfo
			end
		end
	else
		if isvalid(label) then
			local label3 = Labelfunction(entityId, label, options.label, options)
			tab.value = label3
		end
	end
	return tab
end

function formatEntityId2(entityId, options)
	local catinfo = catewikidatainfo(options)
	local label = options.label or mw.wikibase.label(entityId)
	if isntvalid(label) then
		label = mw.wikibase.label(entityId) or nil
	end 
	local label_chart = help_functions.formatcharacters(label, options)
	
	local link = mw.wikibase.sitelink(entityId)
	local link_chart = help_functions.formatcharacters(link, options)
	local tab = {}
	tab.value = ""
	tab.label = ""
	if isvalid(link) and isntvalid(options.nolink) then
		if isvalid(label) then
			tab.value = "[[" .. link .. "|" .. label_chart .. "]]" .. catinfo
		else
			tab.value = "[[" .. link_chart .. "]]" .. catinfo
			tab.label = link
		end
	else
		if label then
			tab.value = label_chart
			tab.label = label
		end
	end
	return tab
end

function sitelink(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 formatsitelink(entityId, options)
	--[[ function to get only the value with link]]
	local label = help_functions.labelIn("ar", entityId)
	if isvalid(options.label) then
		label = options.label
	end
	local link = mw.wikibase.sitelink(entityId)
	if isvalid(link) then
		if isvalid(label) then
			return "[[" .. link .. "|" .. label .. "]]"
		else
			return "[[" .. link .. "]]"
		end
	end
end

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

function formatsitelink1(entityId, options)
	local link = mw.wikibase.sitelink(entityId)
	if isvalid(link) then
		if isvalid(options.nolink) then
			return link
		else
			return "[[" .. link .. "]]"
		end
	end
end

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

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

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

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

function p.formatStatements(frame, key)

	--[[ The main function	]]
	local args = frame.args
	--If a value if already set, use it
	if isvalid(args.value) then
		return args.value
	end
	if isntvalid(args.property) and isvalid(args.pid) then
		args.property = args.pid
	end
	local valuesnumb = 0
	if isvalid(args.returnnumberofvalues) then
		mw.log("valuesnumb: " .. valuesnumb)
		s, valuesnumb = formatStatements(args, key)
		return s, valuesnumb
	end

	local prop = formatStatements(args, key)
	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.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
	return prop
end

function p.fs(frame, key)
	return p.formatStatements(frame, key)
end

function p.formatStatementsFromLua(options, key) --	 main function but to use from lua module

	if isvalid(options.value) then return options.value end			--If a value if already set, use it

	if isntvalid(options.property) and isvalid(options.pid) then
		options.property = options.pid
	end
	
	local s = formatStatements(options, key)
	if options.returnnumberofvalues == true or 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 s = options.mainprefix .. s end -- mainprefix
		if isvalid(options.mainsuffix) then s = s .. options.mainsuffix end	 -- mainsuffix 
	else
		s = nil
	end
	if options.returnnumberofvalues == true or isvalid(options.returnnumberofvalues) then
		return s, valuesnumb
	end
	return s
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 help_functions.count_Site_Links(id)
	end
	local link = sitelink(id, site)
	if isvalid(link) then
		return link
	end
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 help_functions.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 help_functions.labelIn(langcode, id)
end

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

function p.ViewSomething(frame) -- from en:Module:Wikidata
	return help_functions.ViewSomething(frame)
end
function p.Dump(frame)
	return help_functions.Dump(frame)
end

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

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

return p