לדלג לתוכן

יחידה:ספרי קודש

מתוך חב"דפדיה, אנציקלופדיה חב"דית חופשית

ניתן ליצור תיעוד על היחידה הזאת בדף יחידה:ספרי קודש/תיעוד

--[[
    Module for handling Hebrew numerical values and scripture references
    Provides functionality for converting between Hebrew letters and numbers,
    and validating scripture references.
]]

local p = {}

-- Cached MediaWiki functions
local ustring = mw.ustring
local len = ustring.len
local sub = ustring.sub
local find = ustring.find

-- Constants
local MAX_HEBREW_NUMBER = 899
local USER_NAMESPACE = 3
local ARTICLE_NAMESPACE = 0
local TEMPLATE_NAME = ""

-- Hebrew number conversion table
local HEBREW_NUMBERS = {
    ["א"] = 1, ["ב"] = 2, ["ג"] = 3, ["ד"] = 4, ["ה"] = 5,
    ["ו"] = 6, ["ז"] = 7, ["ח"] = 8, ["ט"] = 9, ["י"] = 10, 
    ["כ"] = 20, ["ל"] = 30, ["מ"] = 40, ["נ"] = 50, ["ס"] = 60,
    ["ע"] = 70, ["פ"] = 80, ["צ"] = 90, ["ק"] = 100, ["ר"] = 200,
    ["ש"] = 300, ["ת"] = 400, ["תק"] = 500, ["תר"] = 600,
    ["תש"] = 700, ["תת"] = 800
}

-- Error category prefix based on namespace
local function getErrorCategory()
    local currentTitle = mw.title.getCurrentTitle()
    if currentTitle["namespace"] == ARTICLE_NAMESPACE then
        return "[[קטגוריה:שגיאות קריאה לתבניות ספרי קודש]] "
    end
    return "[[קטגוריה:שגיאות קריאה לתבניות ספרי קודש מחוץ למרחב הערכים]] "
end

-- Error handling
local function logAndThrowError(message)
    local errorPrefix = getErrorCategory() .. " (בקריאה ל[[תבנית:" .. TEMPLATE_NAME .. "]]) "
    mw.log(message)
    error(errorPrefix .. message, 0)
end

-- String utility functions
local function safeLen(s)
    return s and len(s) or 0
end

local function safeSub(str, from, to)
    return sub(str, from, to)
end

local function safeFind(str, what, where)
    return find(str, what, where, true) or 0
end

-- Hebrew number conversion functions
local function fromHebrewNumber(num)
    local result = 0
    local str = num
    
    while safeLen(str) > 0 do
        local firstChar = safeSub(str, 1, 1)
        
        -- Check for invalid characters
        if ustring.byte(firstChar) == 226 then
            logAndThrowError("יש להקליד את כל התבנית מחדש")
        end
        
        local value = HEBREW_NUMBERS[firstChar]
        if not value then
            if firstChar == " " then
                logAndThrowError("רווח מיותר בתוך פרמטר " .. firstChar)
            else
                logAndThrowError("אות עברית לא ידועה " .. firstChar)
            end
        end
        
        result = result + value
        str = safeSub(str, 2, safeLen(str))
    end
    
    return result
end

local function toHebrewDigit(digit)
    if digit == 0 then
        return ""
    end
    
    for hebrew, value in pairs(HEBREW_NUMBERS) do
        if digit == value then
            return hebrew
        end
    end
    
    logAndThrowError("ספרה" .. digit .. "לא נמצאה")
end

local function toHebrewNumber(num)
    if num > MAX_HEBREW_NUMBER then
        logAndThrowError("המספר " .. num .. " גדול מדי")
    end
    
    local units = num % 10
    local tens = (((num - units) / 10) % 10) * 10
    local hundreds = num - units - tens
    
    local result = {
        toHebrewDigit(hundreds),
        toHebrewDigit(tens),
        toHebrewDigit(units)
    }
    
    -- Special cases for numbers 15 and 16
    if tens == 10 then
        if units == 5 then
            result[2] = "ט"
            result[3] = "ו"
        elseif units == 6 then
            result[2] = "ט"
            result[3] = "ז"
        end
    end
    
    return table.concat(result)
end

-- Validation functions
local function validateHebrewNumber(hebrewNum)
    if hebrewNum == "שדמ" then
        return fromHebrewNumber(hebrewNum)
    elseif hebrewNum == "פתיחתא" then
        return 0
    end
    
    local numericValue = fromHebrewNumber(hebrewNum)
    if toHebrewNumber(numericValue) == hebrewNum then
        return numericValue
    end
    
    logAndThrowError("מספר עברי " .. hebrewNum .. " לא מוכר")
end

local function validateBook(book, names, renames, syntax, suggestions)
    local originalName = book
    
    -- Check for invalid characters
    local str = book
    while safeLen(str) > 0 do
        if ustring.byte(safeSub(str, 1, 1)) == 226 then
            logAndThrowError("יש להקליד את כל התבנית מחדש")
        end
        str = safeSub(str, 2, safeLen(str))
    end
    
    -- Check for renamed books
    book = renames[book] or book
    
    -- Look up book in names table
    for n, nn in pairs(names) do
        if nn == book then
            return n
        end
    end
    
    -- Check for common errors
    if safeFind(book, syntax["book"] .. " ") == 1 then
        logAndThrowError('יש להשמיט את מילה "' .. syntax["book"] .. '" מתוך הפרמטר')
    end
    
    if suggestions[book] then
        logAndThrowError("אין " .. syntax["book"] .. " " .. originalName ..
            ", האם הכוונה היא ל" .. suggestions[book] .. "?")
    end
    
    logAndThrowError("אין " .. syntax["book"] .. " " .. book)
end

-- Main function
function p.main(frame)
    -- Skip processing in user conversation namespace
    if mw.title.getCurrentTitle()["namespace"] == USER_NAMESPACE then
        return
    end

	TEMPLATE_NAME = frame.args["type"]
    
    -- Load configuration
    local input = require("יחידה:ספרי קודש/" .. frame.args["type"])
    local names, renames, data = input[1], input[2], input[3]
    local syntax, numbered = input[4], input[5]
    local checkparam, suggestions = input[6], input[7]
    local morechecks, getnumbers = input[8], input[9]
    
    -- Validate required parameters
    if not frame.args["book"] or frame.args["book"] == "" then
        logAndThrowError("חסר שם ה" .. syntax["book"])
    end
    
    if not frame.args["chapter"] or frame.args["chapter"] == "" then
        logAndThrowError("חסר מספר " .. syntax["chapter"])
    end
    
    -- Clean and validate parameters
    local function cleanParameter(param)
        return param and string.gsub(param, "['\"]", "") or ""
    end
    
    local book = validateBook(frame.args["book"], names, renames, syntax, suggestions)
    local chapter = validateHebrewNumber(cleanParameter(frame.args["chapter"]))
    local bookData = data[book]
    
    local par = cleanParameter(frame.args["par"])
    local par1 = cleanParameter(frame.args["par1"])
    
    -- Validate chapter and paragraph ranges
    if safeFind(frame.args["chapter"], '-') > 0 then
        logAndThrowError("יש לציין מספר " .. syntax["chapter"] .. " אחד בלבד, ניתן להפריד באמצעות |")
    end
    
    if safeFind(par .. par1, '-') > 0 then
        logAndThrowError("יש לציין מספר ".. syntax["par"] .. " אחד בלבד בכל פרמטר, ניתן להפריד באמצעות |")
    end
    
    -- Convert parameters to numbers
    local parNum = par == "" and 1 or (getnumbers and tonumber(par) or validateHebrewNumber(par))
    local par1Num = par1 == "" and 2 or (getnumbers and tonumber(par1) or validateHebrewNumber(par1))
    
    -- Validate chapter and paragraph numbers
    if (type(bookData) == "table" and chapter > #bookData) or
       (type(bookData) == "number" and chapter > bookData) then
        logAndThrowError("אין " .. syntax["chapter"] .. " " .. frame.args["chapter"]
            .. " ב" .. syntax["book"] .. " " .. frame.args["book"])
    end
    
    if --[[type(bookData) ~= "number" and]] parNum > bookData[chapter] and par ~= "" then
        logAndThrowError("אין " .. syntax["par"] .. " " .. par .. " ב" .. syntax["chapter"] .. " " ..
            frame.args["chapter"] .. " ב" .. syntax["book"] .. " " .. frame.args["book"])
    end
    
    -- Additional validation checks
    if par1 ~= "" then

		if --[[type(bookData) ~= "number" and]] par1Num > bookData[chapter] then
			logAndThrowError("אין " .. syntax["par1"] .. " " .. par1 .. " ב" .. syntax["chapter"] .. " " ..
				frame.args["chapter"] .. " ב" .. syntax["book"] .. " " .. frame.args["book"])
		end

        if par1Num == parNum then
            logAndThrowError("שני הפרמטרים המציינים אותו מספר " .. syntax["par"])
        end
        
        if par1Num < parNum then
            logAndThrowError("יש לשים את ה" .. syntax["pars"] .. " בסדר עולה")
        end
        
        if par == "" then
            logAndThrowError("אין לציין " .. syntax["par"] .. " סיום ללא " .. syntax["par"] .. " התחלה")
        end
    end
    
    -- Parent frame parameter validation
    local parentFrame = frame:getParent()
    if parentFrame then
        if parentFrame.args[tostring(numbered + 1)] then
            logAndThrowError("יש להעביר לכל היותר " .. numbered .. " פרמטרים")
        end
        
        for param, value in pairs(parentFrame.args) do
            if not checkparam(param) then
                logAndThrowError('נמצא פרמטר לא בשימוש "' .. param .. '="')
            end
        end
    end
    
    -- Additional custom checks
    if morechecks then
        morechecks({book = frame.args["book"], chapter = chapter, fpar = par})
    end
end

return p