Modulo:Cielo/sandbox
--[[
* Modulo che implementa il template Cielo.
]]--

require('strict')

local getArgs = require('Modulo:Arguments').getArgs
local mRaDec = require('Modulo:RaDec/sandbox')
local errorCategory = '[[Categoria:Voci con errori del modulo Cielo]]'

-- Error handler per xpcall, formatta l'errore.
--
-- @param {string} msg
-- @return {string}
local function errhandler(msg)
	local cat = mw.title.getCurrentTitle().namespace == 0 and errorCategory or ''
	return string.format('<span class="error">%s</span>%s', msg, cat)
end

-- Restituisce il numero arrotondato al numero di cifre decimali richiesto.
-- http://lua-users.org/wiki/SimpleRound
--
-- @param {number} num
-- @param {number} idp
-- @return {number}
local function round(num, idp)
	local mult = 10 ^ (idp or 0)
	return math.floor(num * mult + 0.5) / mult
end

-- Restituisce la stringa "0 + numero" quando il numero è di una sola cifra, altrimenti lo stesso numero.
--
-- @param {number} num
-- @return {string}
local function padleft0(num)
	return (num > -10 and num < 10) and
		   ((num < 0 and '-0' or '0') .. math.abs(num)) or num
end

-- Parsifica i parametri posizionali standard e restituisce due table,
-- per l'ascensione retta e per la declinazione.
--
-- @param {table} args
-- @return {table} ascensione retta, con chiavi 'h', 'm' e 's' di tipo number
-- @return {table} declinazione, con chiavi 'sign', d', 'm' e 's' di tipo number
local function parsePosArgs(args)
	local ra, dec, h, d, m, s, sign

	-- ascensione retta
	args[3] = args[3] and args[3]:gsub(',', '.') or nil
	h, m, s = tonumber(args[1]), tonumber(args[2]), tonumber(args[3])
	if h and m and s then
		ra = { h = h, m = m, s = s }
	end
	-- declinazione
	args[7] = args[7] and args[7]:gsub(',', '.') or nil
	d, m, s = tonumber(args[5]), tonumber(args[6]), tonumber(args[7])
	if d and m and s then
		sign = (args[4] == '-' or args[4] == '−') and -1 or 1
		dec = { sign = sign, d = math.abs(d), m = m, s = s }
	end

	return ra, dec
end

-- Restituisce un tag span con id=coordinates contenente le coordinate celesti specificate
-- come link esterno al sito web wikisky.org.
--
-- @param {table} ra
-- @param {table} dec
-- @param {number} distance
-- @return {string}
local function getHTML(ra, dec, distance)
	local otherPars = 'show_grid=1&show_constellation_lines=1&show_constellation_boundaries=1' ..
					  '&show_const_names=1&show_galaxies=1&img_source=IMG_all'
	local raPar = ra.h + ra.m / 60 + ra.s / 3600
	local dePar = dec.sign * (dec.d + dec.m / 60 + dec.s / 3600)
	local zoomPar = round(math.log(distance or 100000) / math.log(10) + 1, 0)
	local target = string.format('http://www.wikisky.org/?ra=%s&de=%s&zoom=%s&%s', raPar, dePar, zoomPar, otherPars) 
	local text = string.format('%s<sup>h</sup> %s<sup>m</sup> %s<sup>s</sup>, %s%s° %s′ %s″',
							   padleft0(ra.h), padleft0(ra.m), padleft0(ra.s),
							   dec.sign == 1 and '+' or '-',
							   padleft0(dec.d), padleft0(dec.m), padleft0(dec.s))
	local extlink = string.format('[%s %s]', target, text)
	local root = mw.html.create('span')
	root
		:addClass('plainlinks nourlexpansion')
		:attr('id', 'coordinates')
		:wikitext('[[Coordinate celesti|Coordinate]]: [[File:Celestia.png|20px|link=|Carta celeste]] ' .. extlink)

	return tostring(root)
end

-- =============================================================================
--                            Funzioni esportate
-- =============================================================================

local p = {}

-- Funzione per l'utilizzo da un altro modulo.
function p._main(args)
	local ra, dec, distance

	if args.RA and args.DEC then
		ra = mRaDec.parseRA(args.RA)
		dec = mRaDec.parseDEC(args.DEC)
		distance = tonumber(args.distanza)
	else
		ra, dec = parsePosArgs(args)
		distance = tonumber(args[8])
	end

	return (ra and dec) and getHTML(ra, dec, distance) or nil
end

-- Funzione per il template {{Cielo}}.
function p.main(frame)
	return select(2, xpcall(function()
		return p._main(getArgs(frame, { parentOnly = true }))
	end, errhandler))
end

return p