بەڵگەدارکردنی مۆدیوول[دروست بکە]
--[[
	قورئان
	Quran
	
	created and maintained in Arabic Wikipedia 
]]
local cfg = mw.loadData('Module:Quran/Configuration')
local gdata = mw.loadData('Module:Quran/data general')
local yesno = require ('Module:Yesno')
local quran_data
local quran_norm
local aya_symbol_template = cfg.default.aya_symbol_template
local sour
local quran_shape = cfg.default.shape
local string = mw.ustring
local text = mw.text
local strspace = "[ " .. string.char(160) .. "]"
local lang = mw.getContentLanguage()

local function eastern_numbers(thenumber)
	local str_number = tostring(thenumber)
	local ret_str = ''	
	for i=1,#str_number do
		ret_str = ret_str .. string.char(0x0660 + tonumber(string.sub(str_number,i,i)))
	end
	return ret_str
end

local function shape_numbers(thenumber)
	local str_number = tostring(thenumber)
	local numbers_shape = cfg.presentation.numbers_shape
	if numbers_shape == "" then
		return str_number
	end
	local ret_str = ''
	local c_n
	for i=1,#str_number do
		c_n = tonumber(string.sub(str_number,i,i))+1
		ret_str = ret_str .. string.sub(numbers_shape, c_n,c_n)
	end
	return ret_str
end

local gtonumber = tonumber

local function tonumber(str)
	if not str then
		return nil
	end
	local thenumber = gtonumber(str) or mw.language.getContentLanguage():parseFormattedNumber(str)
	if not thenumber then
		return nil
	end
	return math.floor(thenumber)
end

local function set_quran_shape(in_shape)
	if in_shape then
		for k, shapelist in pairs(cfg.shape_aliases) do
			for _, shapevalue in ipairs(shapelist) do
				if in_shape == shapevalue then
					quran_shape = k
					return
				end
			end
		end
	end
end

local function substitute( msg, args )
	return args and mw.message.newRawMessage( msg, args ):plain() or msg;
end

local function error_comment(msg, args )
	return substitute( cfg.presentation.error, {mw.getCurrentFrame():getParent():getTitle() , substitute( msg, args )} );
end

local function some_aya(souranum,ayanum,start_word,end_word)
	if not start_word and not end_word then
		return quran_data[souranum][ayanum],true
	end
	local fullaya = true
	local ayaText = ' ' .. quran_data[souranum][ayanum] .. ' '
	local f,l,wb
	local fnorm=1
	local norm_ayaText
	if start_word then
		f=string.find(ayaText,' ' .. start_word .. ' ',1,true)
		if not f then
			if not quran_norm then
				quran_norm = mw.loadData('Module:Quran/data norm')
			end
			norm_ayaText=' ' .. quran_norm[souranum][ayanum] .. ' '
			f=string.find(string.gsub(norm_ayaText, string.char(160),' '), ' ' .. start_word .. ' ',1,true)
			fnorm=f
			if not f then
				return error_comment(cfg.msgs.from_word_err)
			end
			if quran_shape ~= 'text' and string.sub(norm_ayaText,f,f)==string.char(160) then
				ff=1
				tmp=1
				while tmp do
					tmp = string.find(string.sub(norm_ayaText,1,f),' ',ff+1,true)
					if tmp then
						ff=tmp
					end
				end
				f=ff
			end
			_, wb = string.gsub(string.sub(norm_ayaText,1,f-1),strspace," ")
			f=1
			for i=1,wb do
				f=string.find(ayaText," ",f+1)
			end
		end
	end
	f=f or 1
	if end_word then
		
		l=string.find(ayaText,' ' .. end_word .. ' ',f,true)
		if l then
			l=l + end_word:len()
		else
			if not quran_norm then
				quran_norm = mw.loadData('Module:Quran/data norm')
			end
			norm_ayaText=' ' .. quran_norm[souranum][ayanum] .. ' '
			l = string.find(string.gsub(norm_ayaText,string.char(160),' '),' ' .. end_word .. ' ',fnorm,true)
			if not l then
				return error_comment(cfg.msgs.to_word_err)
			end
			l=l + string.len(end_word)
			_, wb =string.gsub(string.sub(norm_ayaText,1,l-1),strspace," ")
			l=1
			for i=1,wb do
				l=string.find(ayaText, " ",l+1)
			end
		end
		if l<#ayaText then
			fullaya=false
		end
	end
	return text.trim(string.sub(ayaText,f,l)),fullaya
end

local function argument_wrapper(arg)
	local nilargs = {}
	return setmetatable({},
	{
		__index = function ( tbl, k )
			local v = rawget(tbl,k)
			if v then
				return v
			elseif nilargs[k] then
				return nil
			end
			local list = cfg.aliases[k];
			for _,arglist in ipairs(arg) do
				if type( list ) == 'table' then
					for _, alias_key in ipairs( list ) do
						if arglist[alias_key] then
							v = arglist[alias_key]
							break;
						end
					end
				elseif list ~= nil then
					v = arglist[list]
				end

				if v then
					break;
				end
			end
			if v == nil then
				nilargs[k] = true
			elseif string.len(v) == 0 then
				nilargs[k] = true
				v = nil
			else
				rawset( tbl, k, v )
			end
			return v
		end,
	});
end

local function soura_number( str_soura )
	for i=1,114 do
		if sour[i].name == str_soura then
			return i
		end
	end

	for i=1,114 do
		for _, v in ipairs(sour[i].search) do
			if v == str_soura then
				return i
			end
		end
	end

	return nil
end

local function arg2soura_num(arg_soura)
	local soura_num = tonumber(arg_soura)
	
	if soura_num and (soura_num < 1 or soura_num > 114) then
		return  0, error_comment(cfg.msgs.soura_num_err)
	end
	
	if not soura_num then
		soura_num = soura_number(arg_soura)
		if not soura_num then
			return 0, error_comment(cfg.msgs.soura_name_err)
		end
	end
	return soura_num, ""
end

local function load_data()
	quran_data =  mw.loadData('Module:Quran/data ' .. quran_shape) 
end

local function aya_number(aya_num, frame)
	if aya_symbol_template then
		if cfg.presentation[aya_symbol_template] then
			return substitute(cfg.presentation[aya_symbol_template], shape_numbers(aya_num))
		else
			return frame:expandTemplate{ title = aya_symbol_template, args = { aya_num } }
		end
	else
		return '&#x06DD;' .. eastern_numbers(aya_num)
	end
end

local function get_ayat(soura, start_aya, end_aya)
	local ret_text	= ''
	for aya_num = start_aya, end_aya do
		ret_text = ret_text .. quran_data[soura][aya_num] .. aya_number(aya_num)
	end
	return string.sub(ret_text,1,#ret_text -1)	
end

local function aya(frame)
	local A = argument_wrapper({frame.args, frame:getParent().args,mw.loadData("Module:Art pref/data")[cfg.main.template_name] or {}})
	local soura =  tonumber(A[1] or A.soura or A.s)
	local aya =  tonumber(A.from_aya or A.a)
	local ret = ''
	if soura> 114 or soura<1 then
		return error_comment(cfg.msgs.soura_num_err)
	end
	
	if A.shape then
		set_quran_shape(A.shape)
	end
	local soura_data = gdata.sour[soura]
	if aya <1 or aya > soura_data.ayacount then
		return error_comment(cfg.msgs.from_aya_err,{soura_data.name,soura_data.ayacount}) 
	end
	load_data()
	local ret = quran_data[soura][aya]
	if quran_shape == "KFGQPC" then
		ret= string.gsub(ret,'آ', '&#x627;&#x653;')
	end
	return ret
end

local function search(A, frame)
	local soura= A[1] or A.soura
	local start_soura
	local ret = ''
	sour = gdata.sour
	if soura then
		start_soura, errmsg = arg2soura_num(soura)
		if start_soura == 0 then
			return errmsg
		end
	end
	quran_norm = mw.loadData('Module:Quran/data norm')
	start_soura = start_soura or 1
	for soura_num=start_soura,114 do
		for aya_num=1,sour[soura_num].ayacount do
			if quran_norm[soura_num][aya_num]:gsub("\160"," "):find(A.search) then
				if not quran_data then load_data() end
				ret = ret .. "*" .. substitute(cfg.presentation.quran, { quran_shape, quran_data[soura_num][aya_num] .. ' ' .. aya_number(aya_num,frame)}) .. substitute(cfg.presentation.cite_quran, { sour[soura_num].name, ':' .. lang:formatNum(aya_num)}) .. "\n"
				if A.viewtemplate and yesno(A.viewtemplate) then
					ret = ret .. substitute("<pre>{{$1|$2|$3}}</pre>",{cfg.main.template_name,soura_num,aya_num}) .. "\n"
				end
			end
		end
	end
	if #ret==0 then
		return error_comment(cfg.msgs.no_result)
	else
		return ret
	end
end

local function ayat(frame)
	local A = argument_wrapper({frame:getParent().args, frame.args,mw.loadData("Module:Art pref/data")[cfg.main.template_name] or {}})
	local nocite = A["no-cite"] and yesno(A["no-cite"])
	local translate = A["translate"] or cfg.default.translate
	local autotranslate = yesno(translate, false)
	local translate_text = not autotranslate and yesno(translate, A["translate"]) or ""

	if A.shape and string.len(A.shape)>0 then
		set_quran_shape(A.shape)
		if quran_shape=='Text' then
			strspace = "[ " .. string.char(160) .. "]"
		else
			strspace = " "
		end
	end

	if A.aya_template and (cfg.presentation[A.aya_template] or mw.title.new("template:" .. A.aya_template).exists) then
		aya_symbol_template = A.aya_template
	end
	
	if A.search and string.len(A.search)>0 then
		return search(A,frame)	
	end

	sour = gdata.sour
	local ret_text = ""

	if A.from_aya and string.len(A.from_aya)> 0 then
		local soura_num, soura, from_aya, to_aya, errmsg
		soura_num, errmsg = arg2soura_num(A[1] or A.soura)
		if soura_num == 0 then
			return errmsg
		end

		soura = sour[soura_num]
		if string.find(A.from_aya,'-',1,true) then
			local from_aya_splits = mw.text.split(A.from_aya, '-', true )
			from_aya = tonumber(from_aya_splits[1])
			to_aya = tonumber(from_aya_splits[2])
		else
			from_aya =  tonumber(A.from_aya)
		end
		
		if not from_aya or from_aya>soura.ayacount or from_aya<1 then
			return error_comment(cfg.msgs.from_aya_err,{soura.name,soura.ayacount})
		end

		if not to_aya or to_aya>soura.ayacount then
			local arg_aya_add = A.addition_ayat
			if arg_aya_add then
				to_aya = from_aya + (tonumber(arg_aya_add) or 0)
			elseif A.to_aya then
				to_aya = tonumber(A.to_aya)
			else
				to_aya = from_aya
			end
		end
		
		if to_aya>soura.ayacount or to_aya<1 then
			return error_comment(cfg.msgs.to_aya_err,{soura.name,soura.ayacount})
		end
		
		load_data()
		for aya_num = from_aya, to_aya do
			local fullaya=true
			if (aya_num==from_aya or aya_num == to_aya) and (A.from_word or A.to_word) then
				local temp_text
				temp_text, fullaya = some_aya(soura_num,aya_num, 
					(aya_num==from_aya and A.from_word or nil), 
					(aya_num == to_aya and A.to_word or nil))
				if temp_text:find("error") then
					return temp_text
				end
				ret_text = ret_text .. temp_text
				autotranslate = false
			else
				ret_text = ret_text .. quran_data[soura_num][aya_num]
			end
			
			if fullaya then
				ret_text = ret_text .. ' ' .. aya_number(aya_num, frame) .. ' '
			end
		end
		
		if quran_shape == "KFGQPC" then
			ret_text = string.gsub(ret_text,'آ', '&#x627;&#x653;')
		end
		ret_text = substitute(cfg.presentation.quran, { quran_shape, text.trim(ret_text) }) .. ((not nocite) and (substitute(cfg.presentation.cite_quran, { soura.name, ':' .. lang:formatNum(from_aya) .. ((to_aya>from_aya) and ("–" .. lang:formatNum(to_aya)) or '')})) or "")
		if autotranslate and cfg.main.translate_page then
			for i, p in ipairs(cfg.main.translate_page) do
				if p.last >= soura_num and p.first <= soura_num then
					local soura_translate = mw.loadData('Module:' .. p.page)[soura_num + 1 - p.first]
					for aya_num = from_aya, to_aya do
						translate_text = translate_text 
							.. ((aya_num> from_aya) and '&nbsp;&nbsp;' or '')
							.. ((from_aya<to_aya) and (lang:formatNum(aya_num) .. '- ') or '')
							.. soura_translate[aya_num]
					end
					break;
				end
			end
		end
		if translate_text and translate_text ~= "" then
			ret_text = ret_text .. substitute(cfg.presentation.translate, { translate_text })
		end
		return ret_text
	else
		ret_text = substitute(cfg.presentation.quran, { quran_shape, A[1] or A.user_text })
		if A.s and string.len(A.s)>0 then
			local soura_num, errmsg = arg2soura_num(A.s)
			if soura_num == 0 then
				return errmsg
			end
			local soura=sour[soura_num]
			ret_text = ret_text .. substitute(cfg.presentation.cite_quran, { soura.name, (A.a and (":" .. A.a) or "")})
		end
		if translate_text and translate_text ~= "" then
			ret_text = ret_text .. substitute(cfg.presentation.translate, { translate_text })
		end
		return ret_text
	end
end

local function number_of_soura( frame )	
	local idx = tonumber(frame.args[1])
	if idx and idx>=1 and idx <=114 then
		return idx
	end
	sour = gdata.sour
    return soura_number(frame.args[1])
end


local function soura_name( frame )	
    sour = gdata.sour
    local idx = tonumber(frame.args[1])
	if not idx or idx<1 or idx > 114 then
		return nil
	end
	return sour[idx].name
end

local function aya_count( frame )	
	local idx = tonumber(frame.args[1])
	if not idx or idx<1 or idx > 114 then
		return nil
	end
	sour = gdata.sour
	return sour[idx].ayacount
end

return {
    aya = aya,
    ayat=ayat,
    number_of_soura = number_of_soura,
    soura_name = soura_name,
    aya_count = aya_count
}