--[[  
Modul ini disalin dari modul dengan nama yang sama di Wikimedia Commons.

This module is intended to be the engine behind "Template:Title"

Authors and maintainers:
* User:Jarekt - original version 
]]

require('strict') -- used for debugging purposes as it detects cases of unintended global variables
local core      = require('Module:Core')
local createTag = require('Module:TagQS').createTag

-- ==================================================
-- === Internal functions ===========================
-- ==================================================

local function langSwitch_(list,userLang)
	local langList = mw.language.getFallbacksFor(userLang)
	table.insert(langList,1,userLang)
	for _,language in ipairs(langList) do
		if list[language] then
			return list[language], language
		end
	end
	return nil, nil
end

------------------------------------------------------------------------------
-- Based on frame structure create "args" table with all the input parameters.
-- All inputs are not not case-sensitive and underscored are treated the same 
-- way as speces. Input values are trimmed and empty string are converted to 
-- nils. If "lang" is not provided than we substitute user's prefered language.
local function getArgs(frame)
	local function normalize_input_args(input_args, output_args)
		for name, value in pairs( input_args ) do 
			if type(name)=='string' and value ~= '' then 
				output_args[string.lower(name)] = value
			end
		end
		return output_args
	end
	local args = {}
	args = normalize_input_args(frame:getParent().args, args)
	args = normalize_input_args(frame.args, args)
	return args
end

-- ====================================================================
local function style(str, textLang)
-- based on [[Template:Title/style]]
	if not str or #str==0 then
		return nil
	end
	str = mw.text.trim(str)
	local LUT = {ar='%s',he='%s' ,et='„%s“' ,ja='『%s』' ,mk='„%s“' ,ru='«%s»' ,zh='《%s》', ['zh-hans']='《%s》', en='<i>%s</i>'}
	--str = mw.language:ucfirst(str)
	local form = core.langSwitch(LUT, textLang)
	str = mw.ustring.format( form,  str) -- place quotes
	local dir = mw.language.new( textLang ):getDir()
    str = string.format('<span dir="%s" lang="%s">%s</span>', dir, textLang, str)
	return str
end

-- ===========================================================================
-- === get wikidata item ID (qid) based on P6243 stored in SDC             ===
-- ===========================================================================
local function qid_from_SDC()
	local page = mw.title.getCurrentTitle()
	if page.namespace==6 then -- File namespace
		local entity = mw.wikibase.getEntity()
		if entity and entity.statements and entity.statements.P6243 then
			local statement = entity.statements.P6243[1]
			return statement.mainsnak.datavalue.value.id
		end
	end
	return nil
end

-- ====================================================================
local function harvest_wikidata(entity, userLang)
	local data = {} -- structure similar to "args" but filled with wikidata data
	data.userLang = userLang
	if not entity then
		return data
	end

	-- get title (from 3 properties and label)
	local property = {P1476 = 'title', P1448='official_name', P1705='native_label'}
	for prop, field in pairs( property ) do
		local titleList = {}
		for _, statement in pairs( entity:getBestStatements(field)) do 
			if (statement.mainsnak.snaktype == "value") then 
				local val = statement.mainsnak.datavalue.value
				titleList[val.language] = val.text -- look for multiple values each with a language code
				data.title, data.lang = val.text, val.language -- in case we have title in some odd language: capture it
			end
		end
		if #titleList>1 then
			local title, language = langSwitch_(titleList, userLang)
			if title then
				data.title, data.lang = title, language
			end
		end
		if data.title then
			data.title = data.title .. core.editAtWikidata(entity.id, prop, userLang)
			break -- title found so no need for other property
		end	
	end
	
	-- get labels in all the langguages
	if entity.labels then
		for _, val in pairs(entity.labels) do -- loop over all labels
			if val.language~=data.lang then
				data[val.language] = val.value
			end
		end
	end
	
	return data
end

local function quote(str)
	return '"' .. str .. '"'
end

-- ==================================================
-- === External functions ===========================
-- ==================================================
local p = {}

-- ===========================================================================
-- === Version of the function to be called from other LUA codes
-- ===========================================================================
function p.title_(args)
	local line1, line2, Title, text, lang
	local qsTable = {}

	if args.lang and args.title then -- == Case 1: original language to be displayed ==
		args.lang = string.lower(args.lang)
		line1 = style(args.title, args.lang) -- first line
		if args.lang==args.userLang then -- user's language = title's language
			Title = mw.ustring.format( '<span style="font-weight:bold">%s</span>', line1 or '')
		else -- user's language != title's language
			-- line 1 original language 
			local langName = mw.language.fetchLanguageName( args.lang, args.userLang  )
			local colon    = mw.message.new( "colon" ):inLanguage(args.userLang ):plain()
			local wordsep  = mw.message.new( "Word-separator" ):inLanguage(args.userLang ):plain()
			line1 = langName .. colon .. wordsep .. line1 -- add language name to line #1
			if args.transliteration then 
				line1 = line1 .. '&#32;- '  .. args.transliteration
			end
			line1 = mw.ustring.format( '<span style="font-size:0.9em">%s</span>', line1)

			--  line 2 translation
			if args.translation then 
				line2 = args.translation
			else
				text, lang = langSwitch_(args, args.userLang)
				line2 = style(text, lang)
			end
			if line2 then
				line2 = mw.ustring.format( '<br/><span style="font-weight:bold">%s</span>', line2)
			end 
			Title = line1 .. (line2 or '')
		end
		if not args.title_ then -- make sure title did not originated on wikidata
			table.insert( qsTable, createTag('title', 'P1476', args.lang .. ':' .. quote(args.title)) )
			table.insert( qsTable, createTag('label', 'L'..args.lang, quote(args.title)) )
		end
	else -- == Case 2: original language not relevant ==
		if args.title then 
			Title = args.title
		else
			text, lang = langSwitch_(args, args.userLang)
			Title = style(text, lang)
		end
		if Title then
			Title = mw.ustring.format( '<span style="font-weight:bold">%s</span>', Title)
		end
	end
	Title = Title or ''
	if args.comment then
		Title = mw.ustring.format( '%s<br /><span style="font-size:0.9em">%s<br /></span>', title, args.comment)
	end

	-- add text of invisible tag brodcasted by the template which allows creation of QuickStatements command used to add this info to Wikidata
	for lang, text in pairs( args ) do 
		if mw.language.isSupportedLanguage(lang) and not args[lang..'_'] then -- lang has tobe a valid language and the statement is not from wikidata
			table.insert( qsTable, createTag('label', 'L'..lang, quote(text)) )
		end
	end

	return Title .. table.concat( qsTable, '\n')
end

function p.wikidata_title(entity, userLang)
	return p.title_(harvest_wikidata(entity, userLang))
end

-- ===========================================================================
-- === Versions of the function to be called from template namespace
-- ===========================================================================
function p.title(frame)
	local args = getArgs(frame)
	args.userLang = args.userlang
	if not (args.userLang and mw.language.isSupportedLanguage(args.userLang)) then 
		args.userLang = frame:callParserFunction( "int", "lang" ) -- get user's chosen language
	end 

	-- merge wikidata with local variables
	local qid = args.wikidata or qid_from_SDC() -- get wikidata item ID based on P6243 stored in SDC
	if qid then 
		local entity = mw.wikibase.getEntity(qid)
		if entity then
			local data = harvest_wikidata(entity, args.userLang)
			if not args.title and data.title and not args.lang and data.lang then
				args.title = data.title -- get title from wikidata
				args.lang  = data.lang
				args.title_ = 'from wikidata'
			end
			for lang, text in pairs( data ) do 
				if mw.language.isSupportedLanguage(lang) and not args[lang] then 
					args[lang] = text
					args[lang..'_'] = 'from wikidata'
				end
			end
		end
	end
	return p.title_(args)
end

return p