require('strict')

local p = {}

local getArgs = require('Module:Arguments').getArgs
local yesno = require('Module:Yesno')
local error_message = require('Module:Error')['error']

-- Begin things that need localization
local SCANNED_FILE_NAME = "Gesenius' Hebrew Grammar (1910 Kautzsch-Cowley edition).djvu"
local current_frame = mw.getCurrentFrame()

-- See also:
-- * romanPages in p._page
-- * "Invalid book name"

-- End things that need localization

function p._pageCalc(number)
	if not number then
		return nil
	end
	
	local romanPages = {
		i = 5,
		ii = 6,
		iii = 7,
		iv = 8,
		v = 9,
		vi = 10,
		vii = 11,
		viii = 12,
		ix = 13,
		x = 14,
		xi = 15,
		xii = 16,
		xiii = 17,
		xiv = 18,
		xv = 19,
		xvi = 20,
		xviii = 22,
		xix = 23
	}
	
	if romanPages[number] then
		return romanPages[number]
	end
	
	return(number + 24)
end

function p._page(number)
	if not number then
		return nil
	end
	
	return "[[Page:" .. SCANNED_FILE_NAME .. "/" .. p._pageCalc(number) .. "|" .. number .. "]]"
end

function p.page(frame)
	local args = getArgs(frame)
	return p._page(args[1])
end

function p.pages(frame)
	local args = getArgs(frame)
	
	local section = args["section"]
	
	local layout = current_frame:expandTemplate {
		title = "Default layout",
		args = {"Layout 2"}
	}
	local pagesTag = current_frame:extensionTag {
		name = "pages",
		content = "",
		args = {
			index = SCANNED_FILE_NAME,
			from = p._pageCalc(args["from"]),
			to = p._pageCalc(args["to"]),
			fromsection = section,
			tosection = section
		}
	}
	
	return layout .. pagesTag
end

-- Converts a number to a Hebrew ("Gematria") number.
-- This doesn't cover all the Hebrew numbers, but only what is needed for
-- Bible chapters and verses.
local function toHebrewNumber(numberStr)
	local hebrewNumber = ""
	local numberNum = tonumber(numberStr) or 0
	
	if (numberNum >= 100) then
		hebrewNumber = hebrewNumber .. "ק"
	end
	
	local modulo100 = numberNum % 100
	if (modulo100 == 15) then
		return hebrewNumber .. "טו"
	end
	if (modulo100 == 16) then
		return hebrewNumber .. "טז"
	end
	
	local onesNumber = numberNum % 10
	local tensNumber = math.floor(modulo100 / 10)
	local tensLetter = {
		"י",
		"כ",
		"ל",
		"מ",
		"נ",
		"ס",
		"ע",
		"פ",
		"צ"
	}
	if (tensNumber ~= 0) then
		hebrewNumber = hebrewNumber .. tensLetter[tensNumber]
	end
	
	local onesLetter = {
		"א",
		"ב",
		"ג",
		"ד",
		"ה",
		"ו",
		"ז",
		"ח",
		"ט"
	}
	if (onesNumber ~= 0) then
		hebrewNumber = hebrewNumber .. onesLetter[onesNumber]
	end
	
	return hebrewNumber
end

-- Converts a number to a Greek numeral.
-- This doesn't cover all the Greek numbers, but only what is needed for
-- Bible chapters and verses.
local function toGreekNumber(numberStr)
	local numberNum = tonumber(numberStr, 10)
	local greekNumber = ""
	
	local onesLetter = { "Α", "Β", "Γ", "Δ", "Ε", "ΣΤ", "Ζ", "Η", "Θ" }
	local tensLetter = { "Ι", "Κ", "Λ", "Μ", "Ν", "Ξ",  "Ο", "Π", "ϟ" }
	
	if (numberNum >= 10) then
		tensNumber = math.floor(numberNum / 10)
		greekNumber = greekNumber .. tensLetter[tensNumber]
	end
	
	local onesNumber = numberNum % 10
	if (onesNumber > 0) then
		greekNumber = greekNumber .. onesLetter[onesNumber]
	end
	greekNumber = greekNumber .. "'"
	
	return greekNumber
end

local function verseLink(targetLanguage, linkTargetTitle, chapter, verseStr)
	local verseNum = string.match(verseStr, "[0-9]+")
	local verseLinkWikitext = "[[:" .. targetLanguage .. ":" .. linkTargetTitle
	
	if (targetLanguage == "he") then
		verseLinkWikitext = verseLinkWikitext .. " " .. toHebrewNumber(chapter) .. " " .. toHebrewNumber(verseNum) .. "|" .. verseStr
		
		if (string.match(verseStr, "f$")) then
			verseLinkWikitext = verseLinkWikitext .. "."
		end
		verseLinkWikitext = verseLinkWikitext .. "]]"
	else
		-- Greek Wikisource doesn't support verses at the moment
	end
	
	return verseLinkWikitext
end

local function verseLinks(targetLanguage, linkTargetTitle, chapter, versesStr)
	-- Greek Wikisource and Hebrew Sirac don't support verses at the moment
	if (targetLanguage == "el" or linkTargetTitle == "בן סירא") then
		return versesStr
	end
	
	local formattedLinks = {}
	
	local verseStrs = mw.text.split(versesStr or "", "%." )
	
	for i, verse in ipairs(verseStrs) do
		if verse then
			formattedLinks[i] = verseLink(
				targetLanguage,
				linkTargetTitle,
				chapter,
				verse
			)
		end
	end
	
	local wholeVersesString = table.concat(formattedLinks, ".")
	
	-- Remove repeated periods (can appear after f./ff.)
	wholeVersesString = mw.ustring.gsub( wholeVersesString, "%.%]%]%.", "]].")
	
	-- Remove spaces in the beginning of links
	wholeVersesString = mw.ustring.gsub( wholeVersesString, "%| ", "|")
	wholeVersesString = mw.ustring.gsub( wholeVersesString, "f%]%]%.%[%[", "f]]. [[")
	
	return wholeVersesString
end

local function bibleRefContent(book, chapter, verse, hideBook, fullSizeVerse, actualBook)
	local linkTargetBook = {
		["Gn"] = "בראשית",
		["Gen"] = "בראשית",
		["Gn."] = "בראשית",
		["Ex"] = "שמות",
		["Lv"] = "ויקרא",
		["Lev"] = "ויקרא",
		["Lv."] = "ויקרא",
		["Nu"] = "במדבר",
		["Dt"] = "דברים",
		["Dt."] = "דברים",
		["Jos"] = "יהושע",
		["Ju"] = "שופטים",
		["Jud"] = "שופטים",
		["Ju."] = "שופטים",
		["1 S"] = "שמואל א",
		["2 S"] = "שמואל ב",
		["1 K"] = "מלכים א",
		["2 K"] = "מלכים ב",
		["Is"] = "ישעיהו",
		["Is."] = "ישעיהו",
		["Jer"] = "ירמיהו",
		["Je"] = "ירמיהו",
		["Jer."] = "ירמיהו",
		["Ez"] = "יחזקאל",
		["Ez."] = "יחזקאל",
		["Eze"] = "יחזקאל",
		["Hos"] = "הושע",
		["Ho"] = "הושע",
		["Jo"] = "יואל",
		["Joel"] = "יואל",
		["Am"] = "עמוס",
		["Amos"] = "עמוס",
		["Ob"] = "עובדיה",
		["Jon"] = "יונה",
		["Jn"] = "יונה",
		["Mi"] = "מיכה",
		["Mic"] = "מיכה",
		["Na"] = "נחום",
		["Nah"] = "נחום",
		["Hb"] = "חבקוק",
		["Hab"] = "חבקוק",
		["Zp"] = "צפניה",
		["Hag"] = "חגי",
		["Zc"] = "זכריה",
		["Mal"] = "מלאכי",
		["Mal."] = "מלאכי",
		["Ps"] = "תהלים",
		["PsPs"] = "תהלים",
		["Pr"] = "משלי",
		["Jb"] = "איוב",
		["Job"] = "איוב",
		["Ct"] = "שיר השירים",
		["Cant"] = "שיר השירים",
		["Ru"] = "רות",
		["La"] = "איכה",
		["Lam"] = "איכה",
		["Ec"] = "קהלת",
		["Est"] = "אסתר",
		["Dn"] = "דניאל",
		["Ezr"] = "עזרא",
		["Neh"] = "נחמיה",
		["Ne"] = "נחמיה",
		["1 Ch"] = "דברי הימים א",
		["1 Chr"] = "דברי הימים א",
		["2 Ch"] = "דברי הימים ב",
		["2 Chr"] = "דברי הימים ב",
		["3 Ezr"] = "Έσδρας_Α",
		["1 Macc."] = "Μακκαβαίων_Α'",
		-- The only reference that uses Ecclus is relevant for the Hebrew text
		["Ecclus"] = "בן סירא",
		["Sirac"] = "Σοφία_Σειράχ",
		["St. Mark"] = "Κατά Μάρκον",
		["John"] = "Κατά Ιωάννην",
		["Acts"] = "Πράξεις των Αποστόλων",
		["Rv"] = "Αποκάλυψις Ιωάννου"
	}
	
	if (not linkTargetBook[book]) or (actualBook and not linkTargetBook[actualBook]) then
		return "'''''[[Template:GHGbible-ref/invalid book|Invalid book name]]'''''"
	end
	
	local greekBook = {
		["3 Ezr"] = true,
		["1 Macc."] = true,
		["Sirac"] = true,
		["Mark"] = true,
		["St. Mark"] = true,
		["John"] = true,
		["Acts"] = true,
		["Rv"] = true
	}
	
	-- At least one abbreviation is known to be ambiguous in the 1910 edition:
	-- Jn may mean both Jonah and John (New Testament).
	-- There may be others.
	local linkTargetTitle = linkTargetBook[actualBook or book]
	
	local targetLanguage
	if (greekBook[book] or greekBook[actualBook]) then
		targetLanguage = "el"
	else
		targetLanguage = "he"
	end
	
	local linkBeginning = "[[:" .. targetLanguage .. ":"
	local linkEnding = "]]"
	
	local bibleRef = ""
	
	if (hideBook ~= "completely") then
		if not hideBook then
			local displayBook
			if book == "Ps" then
				displayBook = "ψ"
			elseif book == "PsPs" then
				displayBook = "ψψ"
			else
				displayBook = book
			end
			bibleRef = bibleRef .. displayBook .. " "
		end
		
		-- Obadiah has only one chapter, so the chapter number is not needed
		-- and only the verse number is shown.
		-- All the existing references to Obadiah have a verse.
		if book == "Ob" then
			bibleRef = bibleRef .. linkBeginning .. linkTargetTitle .. " א " .. toHebrewNumber(verse) .. "|" .. verse .. linkEnding
		end
		
		bibleRef = bibleRef .. linkBeginning .. linkTargetTitle
		
		if (targetLanguage == "he") then
			bibleRef = bibleRef .. " " .. toHebrewNumber(chapter)
		else
			-- This works only with some Greek books for now.
			-- See el:Συζήτηση:Η_Αγία_Γραφή#Numbering_of_chapters
			bibleRef = bibleRef .. "#Κεφάλαιον " .. toGreekNumber(chapter)
		end
		
		bibleRef = bibleRef .. "|"
		
		if hideBook and (string.match(hideBook, "^v")) then
			bibleRef = bibleRef .. hideBook .. "."
		else
			bibleRef = bibleRef .. chapter
		end
		
		bibleRef = bibleRef .. linkEnding
	end
	
	if not verse then
		local verseLinksContent = verseLinks(
			targetLanguage,
			linkTargetTitle,
			chapter,
			verse
		)
		if not fullSizeVerse then
			verseLinksContent = "<sup>" .. verseLinksContent .. "</sup>"
		end
		bibleRef = bibleRef .. verseLinksContent
	end
	
	return bibleRef
end

function p._bibleRef(book, chapter, verse, hideBook, fullSizeVerse, actualBook)
	local content = bibleRefContent(
		book,
		chapter,
		verse,
		hideBook,
		fullSizeVerse,
		actualBook
	)
	
	local formattedContent = current_frame:expandTemplate {
		title = "nowrap",
		args = {content}
	}
	
	return formattedContent
end

function p.bibleRef(frame)
	local args = getArgs(frame)
	return p._bibleRef(args["book"], args["chapter"], args["verse"], args["hidebook"], args["fullsizeverse"], args["actualbook"])
end

function p._heb(text, translate, pron, en, indexitem)
	local tag = "span" -- Will probably also support <div> in the future
	local hebElement = mw.html.create(tag)
	hebElement
		:wikitext( text )
		:attr( "lang", "hbo" )
		:attr( "dir", "rtl" )
		:addClass( "he_GHG" )
		-- Calling HTML class "he_GHG" to render Hebrew text,
		-- which is available at Template:GHGheb/styles.css.

	if (indexitem) then
		hebElement:addClass( "indexitem" )
	end
	
	local hebText = tostring( hebElement )
	
	if pron then
		hebText = hebText .. " " .. p._pron(pron)
	end
	
	if translate then
		hebText = hebText .. " " .. p._translate(translate, en, "")
	end
	
	return hebText
end

function p.heb(frame)
	local args = getArgs(frame)
	return p._heb(args["text"], args["translate"], args["pron"], args["en"], yesno(args["indexitem"]))
end

function p._pron(text)
	return current_frame:expandTemplate{
		title = "nowrap",
		args = {"''" .. text .. "''"}
	}
end

function p.pron(frame)
	local args = getArgs(frame)
	return p._pron(args[1])
end

function p._translate(text, en, lang)
	if not text then
		return ''
	end
	
	local translation = "''" .. text .. "''"
	
	if en then
		if lang then
			lang = "la"
		end
		
		local translatedElement = mw.html.create( "span" )
		translatedElement
			:wikitext( translation )
			:attr( "lang", lang )
			:attr( "title", en )
			:css( "border-bottom", "1px dotted" )
			
		translation = tostring(translatedElement)
	end
	
	return translation
end

function p.translate(frame)
	local args = getArgs(frame)
	return p._translate(args[1], args["en"], args["lang"])
end

local function margin_letter_fmt(text)
	local span = mw.html.create('span')
		:addClass('wst-serif')
		:css({['font-family'] = 'serif', ['font-style'] = 'italic'})
		:wikitext(text or '')
	return tostring(span)
end

function p._paragraph(args)
	local parNum = args[1]
	local subParLetter = args[2]
	local aOrB = args[3]
	local nonumber = yesno(args.nonumber or false)
	local nosign = yesno(args.nosign or false)
	local doublesign = yesno(args.doublesign or false)
	
	local linkText = 'Gesenius\' Hebrew Grammar/' .. (parNum or '') .. (aOrB or '')
	
	local anchorText = ''
	if subParLetter then
		anchorText = '#GHGpar-' .. (parNum or '') .. (aOrB or '') .. '-' .. subParLetter
	end
	
	local numberDisplay = ''
	if not nonumber then
		local sign = '§&thinsp;'
		if nosign then
			sign = ''
		elseif doublesign then
			sign = '§§&thinsp;'
		end
		
		local abSup = ''
		if aOrB then
			abSup = '<sup>\'\'' .. aOrB .. '\'\'</sup>'
		end
		
		numberDisplay = sign .. (parNum or '') .. abSup
	end
	
	local letterDisplay = ''
	if subParLetter then
		if numberDisplay == '' then
			letterDisplay = subParLetter
		else
			letterDisplay = '&thinsp;' .. subParLetter
		end
		letterDisplay = margin_letter_fmt(letterDisplay)
	end
	
	return '[[' .. linkText .. anchorText .. '|' .. numberDisplay .. letterDisplay .. ']]'
end

function p.paragraph(frame)
	return p._paragraph(getArgs(frame))
end

function p._translit(args)
	if not args[1] then
		return error_message({'Missing first parameter'})
	end
	
	local shortcuts = {
		['a-brev-acut'] = 'a&#x306;&#x301;',
		['a-dier-brev'] = 'a&#x308;&#x306;',
		['a-dier-macr'] = 'a&#x308;&#x304;',
		['a-di-ma-ac '] = 'a&#x308;&#x304;&#x301;',
		['a-macr-acut'] = 'a&#x304;&#x301;',
		['a-ring-macr'] = 'a&#x30A;&#x304;',
		['a-ring-brev'] = 'a&#x30A;&#x306;',
		['a-ring-circ'] = 'a&#x30A;&#x302;',
		['u-inv-brev '] = 'u&#x32f;',
		['i-inv-brev '] = 'i&#x32f;'
	}
	
	if not shortcuts[args[1]] then
		return error_message({'Error: Unknown [[' .. 'Template:GHGtranslit' .. '|GHGtranslit]] term' .. '[[Category:' .. 'GHGtranslit errors' .. ']]'})
	end
	
	return shortcuts[args[1]]
end

function p.translit(frame)
	return p._translit(getArgs(frame))
end

return p