יחידה:תאריך עברי


mtable = {"ינואר", "פברואר", "מרץ", "אפריל", "מאי", "יוני",
	"יולי", "אוגוסט", "ספטמבר", "אוקטובר", "נובמבר", "דצמבר", }

monthtable = {
	["תשרי"] = 7, ["חשוון"] = 8, ["כסלו"] = 9, ["טבת"] = 10,
	["שבט"] = 11, ["אדר א'"] = 12, ["אדר ב'"] = 13, ["אדר"] = 13,
	["ניסן"] = 1, ["אייר"] = 2, ["סיוון"] = 3, ["תמוז"] = 4,
	["אב"] = 5, ["אלול"] = 6,
	}

typomonthtable = {["חשון"] = "חשוון", ["כסליו"] = "כסלו",
	["חשון"] = "חשוון", ["סיון"] = "סיוון",
	["מרחשון"] = "חשוון", ["מרחשוון"] = "חשוון", ["מר-חשוון"] = "חשוון",
	["מנחם אב"] = "אב", ["מנחם-אב"] = "אב",
	["שבט (חודש)|שבט"] = "שבט", ["שבט (חודש)"] = "שבט"
	}

lastletters = {["כ"] = "ך", ["מ"] = "ם", ["נ"] = "ן", ["פ"] = "ף", ["צ"] = "ץ"}

function sub1(str, from, to)
	return mw.ustring.sub(str, from, to)
end

function find1(str, what, where)
	return mw.ustring.find(str, what, where, true) or 0
end

function len1(s)
	if (s == nil) then
		return 0 end
	return mw.ustring.len(s)
end

function hebnum(s)
	numberstable = {
	["א"] = 1, ["ב"] = 2, ["ג"] = 3, ["ד"] = 4, ["ה"] = 5,
	["ו"] = 6, ["ז"] = 7, ["ח"] = 8, ["ט"] = 9, ["י"] = 10, 
	["כ"] = 20, ["ך"] = 20, ["ל"] = 30, ["מ"] = 40, ["ם"] = 40, 
	["נ"] = 50, ["ן"] = 50, ["ס"] = 60, ["ע"] = 70, ["פ"] = 80, 
	["ף"] = 80, ["צ"] = 90, ["ץ"] = 90, ["ק"] = 100, ["ר"] = 200, 
	["ש"] = 300, ["ת"] = 400, ["'"] = 0, ["\""] = 0,}
	local ans = 0
	local str = s
	while len1(str) > 0 do
		ans = ans + numberstable[sub1(str, 1, 1)]
		str = sub1(str, 2, len1(str))
	end
	return ans
end

function mindate(fix)
	local indenttable = {176, 206, 235, 265, 294, 324, 0, 30, 59, 88, 117, 147, 147}
	return same("28-08-" .. takeyear(fix[3]) .. " + " .. (indenttable[monthtable[sub1(fix[2], 2)]]
		+ hebnum(fix[1]) - 1) .. " days")
end

function takeyear(year)
	local new
	if 0 < find1(year, "אלפים")
		then new = hebnum(sub1(year, 1, 2)) * 1000
		else new = hebnum(sub1(year, 3, len1(year))) + 1000
		* hebnum(sub1((year), 1, 2)) end
	return frame:callParserFunction("padleft", {new - 3761, 4})
end

function exacttdate(hdate, mindate, format)
	local count = 0
	local ans
	local greg
	while (count < 82) do
		ans = mindate .. " + " .. count .. " days"
		if (remove(from(ans)) == hdate) then
			greg = same(ans)
			local diffs = diff(greg)
			if diffs < 0 then diffs = 0 end
			greg = same(greg .. " - ".. diffs .. "days")
			checkcasp(greg)
			if makeformat then
				return frame:callParserFunction("#זמןמ:" .. makeformat, greg)
			end
			return format(greg) end
		count = count + 1
	end
	error("Date not found", 0)
end

function exacttdate1(hyear)
	local wyear = frame:callParserFunction("padleft", {hebnum(sub1(hyear, 3, len1(hyear))) + 1000
		* hebnum(sub1(hyear, 1, 2)) - 3761, 4})
	checkcasp("01-01-" .. wyear)
	return wyear .. "-" .. frame:callParserFunction("padleft", {wyear + 1, 4})
end

function opposite(gdate, format)
	if samesame == true
		then samesame = false
			return format(gdate) end
end

function from(gdate)
	local ans = opposite(gdate, to)
	if ans ~= nil
		then return ans end
	if frame.args["links"] == "yes"
		then return "[[" .. frame:callParserFunction("#זמןמ:xhxjj xjx", gdate) .. "]] [["
			.. frame:callParserFunction("#זמןמ:xhxjY", gdate) .. "]]" end
	return frame:callParserFunction("#זמןמ:xhxjj xjx xhxjY", gdate)
end

function frommonth(gdate)
	local ans = opposite(gdate, tomonth)
	if ans ~= nil
		then return ans end
	if frame.args["links"] == "yes"
		then return "[[" .. frame:callParserFunction("#זמןמ:xjF", gdate) .. "]] [["
			.. frame:callParserFunction("#זמןמ:xhxjY", gdate) .. "]]" end
	return frame:callParserFunction("#זמןמ:xjF xhxjY", gdate)
end

function fromonlymonth(gdate)
	local ans = opposite(gdate, toonlymonth)
	if ans ~= nil
		then return ans end
	if frame.args["links"] == "yes"
		then return "[[" .. frame:callParserFunction("#זמןמ:xjF", gdate) .. "]]" end
	return frame:callParserFunction("#זמןמ:xjF", gdate)
end

function fromyear(gdate)
	local ans = opposite(gdate, toyear)
	if ans ~= nil
		then return ans end
	if frame.args["links"] == "yes"
		then return "[[" .. frame:callParserFunction("#זמןמ:xhxjY", gdate) .. "]]" end
	return frame:callParserFunction("#זמןמ:xhxjY", gdate)
end

function same(gdate)
	return frame:callParserFunction("#זמןמ:d-m-Y", gdate)
end

function makeyear(gdate)
	local year = frame:callParserFunction("#זמןמ:Y", gdate)
	if tonumber(year) < 1000 and which
		then year = sub1(year, 2)
	end
	return year
end

function to(gdate)
	local year = makeyear(gdate)
	if frame.args["links"] == "yes"
		then return "[[" .. frame:callParserFunction("#זמןמ:j בF", gdate) .. "]] [["
			.. year .. "]]" end
	return frame:callParserFunction("#זמןמ:j בF", gdate) .. " " .. year
end

function tomonth(gdate)
	local year = makeyear(gdate)
	if frame.args["links"] == "yes"
		then return "[[" .. frame:callParserFunction("#זמןמ:F", gdate) .. "]] [["
			.. year .. "]]" end
	return frame:callParserFunction("#זמןמ:F", gdate) .. " " .. year
end

function toonlymonth(gdate)
	if frame.args["links"] == "yes"
		then return "[[" .. frame:callParserFunction("#זמןמ:F", gdate) .. "]]" end
	return frame:callParserFunction("#זמןמ:F", gdate)
end

function toyear(gdate)
	local year = makeyear(gdate)
	if frame.args["links"] == "yes"
		then return "[[" .. year .. "]]" end
	return year
end

function fixmonth(hdate)
	local point
	local max = 0
	local place = 0
	for m, mm in pairs(typomonthtable) do
		point = find1(hdate, m)
		if point > 0 and max < len1(m)
			then max = len1(m)
				place = m end
	end
	if max > 0
		then point = find1(hdate, place)
			return sub1(hdate, 1, point - 1) .. typomonthtable[place] .. sub1(hdate, point + len1(place)) end
	return hdate
end

function fixdate(hdate1)
	local hdate = fixmonth(hdate1)
	if 1 == find1(hdate, "ראש חודש")
		then hdate = "א' ב" .. sub1(hdate, 10) end
	local h1, h2, h3 = parts(hdate)
--[=[
	local s1 = find1(hdate, " ")
	local s2 = find1(hdate, " ", s1 + 1)
	local s3 = find1(hdate, " ", s2 + 1)
	if (s3 > 0) then
		s2 = s3 end
	h1 = sub1(hdate, 1, s1 - 1)
	h2 = sub1(hdate, s1 + 1, s2 - 1)
	h3 = sub1(hdate, s2 + 1, len1(hdate))
]=]
	if (len1(h3) > 1 and sub1(h3, 2, 2) ~= "'") then
		h3 = "ה'" .. h3 end
--[=[
	for m, mm in pairs(typomonthtable) do
		if h2 == "ב" .. m
		then h2 = "ב" .. mm end
	end
]=]
	for y, yy in pairs(lastletters) do
		if sub1(h3, len1(h3)) == y
		then h3 = sub1(h3, 1, len1(h3) - 1) .. yy end
	end
	return {h1, h2, h3, h1 .. " " .. h2 .. " " .. h3}
end

function fixerror(message)
	if message == "---"
		then return "" end
	return frame:preprocess(message)
end

function aserror(message)
	error(message .. "[[קטגוריה:דפים עם שגיאות בתאריך]]", 0)
end

function takenumbers(wdate)
	local s1 = find1(wdate, " ")
	local s2 = find1(wdate, " ", s1 + 1)
	local h1 = sub1(wdate, 1, s1 - 1)
	local h2 = sub1(wdate, s1 + 1, s2 - 1)
	local h3 = sub1(wdate, s2 + 1, len1(wdate))
	for f, ff in pairs(mtable) do
		if "ב" .. ff == h2 then
			return h1 .. "-" .. frame:callParserFunction("padleft", {f, 2})
				.. "-" .. frame:callParserFunction("padleft", {h3, 4}) end
	end
end

function numtonums(wdate)
	local s1 = find1(wdate, "-")
	local s2 = find1(wdate, "-", s1 + 1)
	return {tonumber(sub1(wdate, 1, s1 - 1)),
			tonumber(sub1(wdate, s1 + 1, s2 - 1)),
		    tonumber(sub1(wdate, s2 + 1, len1(wdate)))}
end

function diff(gdate)
	local ans
	local wdate = numtonums(gdate)
	local wday = wdate[1]
	local wmonth = wdate[2]
	local wyear = wdate[3]
	if wyear > 1582 or (wyear == 1582 and (wmonth > 10 or (wmonth == 10 and wday > 14)))
		then ans = 0
		else local ytable = {200, 300, 500, 600, 700, 900, 1000, 1100, 1300, 1400, 1500}
			ans = 10
			if wmonth < 3
				then wyear = wyear - 1 end
			for y, yy in pairs(ytable) do
				if yy > wyear
					then ans = ans - 1 end
			end end
	return ans
end

function remove(dateStr) -- Thanks to Eran
	dateStr = mw.ustring.gsub( dateStr, "[%[%]]", "" )
	dateStr = mw.ustring.gsub(dateStr, "(\127UNIQ[^\127]+QINU\127)", "")
	dateStr = mw.ustring.gsub(dateStr, "&rlm;","")
	dateStr = mw.ustring.gsub(dateStr, "&lrm;","")
	return dateStr
end

function checkcasp(wdate)
	local wnumbers = numtonums(wdate)
	if wnumbers[3] < 360 or wnumbers[3] > 4357 or
			(wnumbers[3] == 1582 and wnumbers[2] == 10 and wnumbers[1] > 4 and wnumbers[1] < 15)
		then error("The date is not in the allowed casp", 0) end
end

function fromhebrewyear(hyear)
	ans = fromhebrewdate("א' בניסן " .. hyear, toyear)
	if frame.args["exact"] ~= "כן"
		then ans = ans .. "-" .. fromhebrewdate("א' בתשרי " .. hyear, toyear)
	end
	return ans
end

function fromhebrewmonth(hdate)
	if frame.args["exact"] == "כן"
		then return fromhebrewdate('ט"ו ב' .. hdate, tomonth) end
	local date1 = fromhebrewdate("א' ב" .. hdate, same)
	local month1 = toonlymonth(date1)
	local year1 = toyear(date1)
	local date2 = same(date1 .. " + 30 days")
	date2 = frommonth(date2)
	date2 = fromhebrewdate("א' ב" .. date2, same)
	date2 = same(date2 .. " - 1 days")
	local month2 = toonlymonth(date2)
	local year2 = toyear(date2)
	if year1 ~= year2
		then return month1 .. " " .. year1 .. " - " .. month2 .. " " .. year2
		elseif month1 ~= month2
			then return month1 .. "-" .. month2 .. " " .. year1
			else return month1 .. " " .. year1 end
end

function fromhebrewdate(rem, format)
	local fix = fixdate(remove(rem))
	return exacttdate(fix[4], mindate(fix), format)
end

function fromhebrew1(hdate)
	local ht, rem = findhdatetype(fixmonth(hdate))
	if ht == "dmy"
		then return ifwhich(fromhebrewdate(rem, to))
		elseif ht == "my"
			then return ifwhich(fromhebrewmonth(rem))
			elseif ht == "y"
				then return ifwhich(fromhebrewyear(rem))
					else error("Wrong type: " .. ht, 0) end
end

function findhdatetype(hdate)
	local rem = mw.text.trim(remove(hdate))
	local day, month, year = parts(hdate)
	if day ~= nil
		then return "dmy", rem end
	if month ~= nil
		then return "my", rem end
	return "y", rem
--[=[
	for m, mm in pairs(monthtable) do
		if find1(rem, m) == 1 then
			return "my", rem end
	end
	if find1(rem, " ") == 0 then
		return "y", rem end
	return "dmy", rem
]=]
end

function fromhebrew(f)
	which = true
	return fromhebrewandverify(f)
end

function fromhebrewformat(f)
	which = true
	makeformat = f.args["format"]
	return fromhebrewandverify(f)
end

function verify(f)
	frame = f
	which = false
	local success, res = pcall(pick1, frame.args[1], frame.args[2], "[[קטגוריה:חוסר מתאם בין תאריך עברי לתאריך לועזי]]")
	if not success
		then res = "" end
	local ans = ""
	if f.args[2] ~= ""
		then ans = tohebrew0(f.args[2]) end
	if f.args[1] ~= ""
		then ans = ans .. fromhebrewandverify(f) end
	return res .. ans
end

function fromhebrewandverify(f)
	frame = f
	local success, res = pcall(fromhebrew1, frame.args[1])
	if success
		then return ifwhich(res)
		elseif frame.args["about"] == "כן" and
				frame:expandTemplate({title = "גיל לערכי אישים/מקורב", args = {str = frame.args[1]}}) ~= ""
			then return ifwhich(frame.args[1], "[[קטגוריה:דפים עם תאריך עברי מקורב]]")
		elseif frame.args["error"] == nil
			then return aserror(res) end
	return fixerror(frame.args["error"])
end

function tohebrewyear(gyear)
	ans = tohebrewnum("01-01-" .. gyear, fromyear)
	if frame.args["exact"] ~= "כן"
		then ans = ans .. "-" .. tohebrewnum("01-12-" .. gyear, fromyear)
	end
	return ifwhich(ans)
end

function tohebrewmonth(wdate)
	if frame.args["exact"] == "כן"
		then return tohebrewdate("15 ב" .. wdate, frommonth) end
	local date1 = tohebrewdate("1 ב" .. wdate, same)
	local month1 = fromonlymonth(date1)
	local year1 = fromyear(date1)
	local date2 = same(date1 .. " + 31 days")
	date2 = tomonth(date2)
	date2 = tohebrewdate("1 ב" .. date2, same)
	date2 = same(date2 .. " - 1 days")
	local month2 = fromonlymonth(date2)
	local year2 = fromyear(date2)
	if year1 ~= year2
		then return ifwhich(month1 .. " " .. year1 .. " - " .. month2 .. " " .. year2)
		elseif month1 ~= month2
			then return ifwhich(month1 .. "-" .. month2 .. " " .. year1)
			else return ifwhich(month1 .. " " .. year1) end
end

function tohebrewdate(rem, format)
	local s1 = find1(rem, " ")
	local s2 = find1(rem, " ", s1 + 1)
	if len1(rem) - s2 == 3
		then rem = sub1(rem, 1, s2) .. "0" .. sub1(rem, s2 + 1) end
	local take = takenumbers(rem)
	if remove(to(take)) ~= rem
		then error("wrong date", 0) end
	checkcasp(take)
	take = same(take .. " + " .. diff(take) .. " days")
	return ifwhich(format(take))
end

function tohebrewnum(wdate, format)
	if find1(wdate, "-", 3) == 3 and find1(wdate, "-", 6) == 6 and len1(wdate) == 9
		then wdate = sub1(wdate, 1, 6) .. "0" .. sub1(wdate, 7, 9) end
	if same(wdate) ~= wdate
		then error("wrong date", 0) end
	checkcasp(wdate)
	wdate = same(wdate .. " + " .. diff(wdate) .. " days")
	return ifwhich(format(wdate))
end

function findwdatetype(wdate)
	local rem = mw.text.trim(remove(wdate))
	if find1(rem, "-") ~= 0 then
		return "num", rem end
	for m, mm in pairs(mtable) do
		if find1(rem, mm) == 1 then
			return "my", rem end
	end
	if tonumber(rem) ~= nil and tonumber(rem) .. "" == rem then
		return "y", rem end
	return "dmy", rem
end

function tohebrew1(wdate)
	local w, rem = findwdatetype(wdate)
	if w == "num"
		then return tohebrewnum(rem, from)
		elseif w == "dmy"
			then return tohebrewdate(rem, from)
			elseif w == "my"
				then return tohebrewmonth(rem)
				elseif w == "y"
					then return tohebrewyear(rem)
					else error("Wrong type: " .. ht, 0) end
end

function pick1(hdate, wdate, cat)
	local ht, wt, hrem, wrem, hdw, wdh, hsuccess, wsuccess, thsuccess, twsuccess
	if cat == nil
		then which = true
			ht, hrem = findhdatetype(hdate)
			wt, wrem = findwdatetype(wdate)
		else thsuccess, ht, hrem = pcall(findhdatetype, hdate)
			twsuccess, wt, wrem = pcall(findwdatetype, wdate)
			hsuccess = false
			wsuccess = false end
	if hrem == ""
		then ht = "empty"
		else hsuccess, hdw = pcall(fromhebrew1, hrem)
			if not hsuccess
				then ht = "about" end end
	if wrem == ""
		then wt = "empty"
		else wsuccess, wdh = pcall(tohebrew1, wrem)
			if not wsuccess
				then wt = "about" end end
	if cat ~= nil
		then if ht == "dmy" and wt ~= "dmy"
				then return "[[קטגוריה:חוסר מתאם בתאריכים - תאריך " 
							.. frame.args["type"] .. " עברי מדויק]]" end
			if ht ~= "dmy" and wt == "dmy"
				then return "[[קטגוריה:חוסר מתאם בתאריכים - תאריך " 
							.. frame.args["type"] .. " לועזי מדויק]]" end
--			if ht == "dmy" or ht == "my" or ht == "y"
--				then return "[[קטגוריה:חוסר מתאם בתאריכים - תאריך " 
--							.. frame.args["type"] .. " לועזי מדויק]]" end
			return "" end
	if wsuccess and hsuccess
		then if wt == "dmy" then return wdate
			elseif ht == "dmy" then return hdw
			elseif wt == "my" then return wdate
			elseif ht == "my" then return hdw
			elseif wt == "y" then return wdate
			else return hdw end
		elseif wsuccess then return wdate
		elseif hsuccess then return hdw
		elseif wt == "about" then return wdate
		else return hdate end
end

function checkcat(adate, cat)
	if cat == nil
		then return adate end
	return cat
end

function pick(f)
	frame = f
	local hebrew = frame.args["hebrew"]
	local world = frame.args["world"]
	local habout = false
	local wabout = false
	if frame:expandTemplate({title = "גיל לערכי אישים/מקורב", args = {str = hebrew}}) ~= ""
		then hebrew = ""
			habout = true end
	if frame:expandTemplate({title = "גיל לערכי אישים/מקורב", args = {str = world}}) ~= ""
		then world = ""
			wabout = true end
	local success, res = pcall(pick1, hebrew, world)
	if success
		then if habout and world == ""
				then return frame.args["hebrew"] end
			if wabout and hebrew == ""
				then return frame.args["world"] end
			return res
		elseif frame.args["error"] == nil
			then return aserror(res) end
	return fixerror(frame.args["error"])
end

function tohebrew0(wdate)
	local success, res = pcall(tohebrew1, wdate)
	if success
		then return res
		elseif frame.args["about"] == "כן" and
				frame:expandTemplate({title = "גיל לערכי אישים/מקורב", args = {str = wdate}}) ~= ""
			then return ifwhich(frame.args[1], "[[קטגוריה:דפים עם תאריך מקורב]]")
		elseif frame.args["error"] == nil
			then return aserror(res) end
	return fixerror(frame.args["error"])
end

function tohebrew(f)
	frame = f
	which = true
	return tohebrew0(frame.args[1])
end

function samedate(f)
	frame = f
	which = true
	samesame = true
	return tohebrew0(frame.args[1])
end

function ifwhich(ans, noans)
	if noans == nil
		then noans = "" end
	if which
		then return ans
		else return noans end
end

function parts(hdate)
	local funcs = {
	{function() return w[1] end},
	{function() return w[2], w[1] end,
	 function() return c(w[2], w[1]) end},
	{function() return w[3], w[2], w[1] end,
	 function() return c(w[3], w[2]), w[1] end,
	 function() return w[3], c(w[2], w[1]) end},
	{function() return w[4], c(w[3], w[2]), w[1] end,
	 function() return c(w[4], w[3]), w[2], w[1] end,
	 nil,
	 function() return c(w[4], w[3]), c(w[2], w[1]) end},
	{nil,
	 function() return c(w[5], w[4]), c(w[3], w[2]), w[1] end}}
	function c(x, y) return y .. " " .. x end
	w = takewords(hdate)
	local code = 1
	if 0 < find1(hdate, "אלפים")
		then code = code + 1 end
	if 1 == find1(hdate, "אדר א")
		then code = code + 2 end
	if 1 == find1(hdate, "אדר ב")
		then code = code + 2 end
	local year, month, day = funcs[#w][code]()
	return day, month, year
end

function takewords(str)
	local count = 1
	local ans = {}
	local cur = str
	while find1(cur, " ") > 0 do
		ans[count] = sub1(cur, 1, find1(cur, " ") - 1)
		count = count + 1
		cur = sub1(cur, find1(cur, " ") + 1)
	end
	ans[count] = cur
	return ans
end

return {fromhebrew = fromhebrew, tohebrew = tohebrew, verify = verify, pick = pick, samedate = samedate,
	fromhebrewformat = fromhebrewformat}