ХӀокху модулах лаьцна хааман Модуль:AstroCoordinates/doc агӀо кхолла мега

--[[
This module is a for of Module:Coordinates

It is intended to implement the functionality of {{AstroCoord}} and related
templates.  It provides a method {{#Invoke:AstroCoordinates | coord }} -
a general function formatting and displaying astrocoordinate values.
]]

math_mod = require( "Module:Math" );
globalFrame = nil

coordinates = {};

local Display = '';

--[[ Helper function, replacement for {{coord/display/title}} ]]
function displaytitle (s, notes, globalFrame)
	return globalFrame:extensionTag{
		name = 'indicator',
		content = '[[Файл:Jupiter and moon.png|20px|link=Вторая экваториальная система координат|Экваториальные координаты]] ' .. s .. notes,
		args = { name = '0-coord' }
	};
end

--[[ Helper function, Replacement for {{coord/display/inline}} ]]
function displayinline (s, notes)
	return s .. notes
end

--[[
New function, not from Module:Coordinates
]]
function parseTags(line)
	local prefix = ''
	local postfix = ''
	
	for i = 1, 2 do
		local tag = mw.ustring.match(line, "^<span [^<>]*>");
		if tag then
			prefix = prefix .. tag
			line = mw.ustring.sub(line, mw.ustring.len(tag)+1, -1)
		end
	end
	
	for i = 1, 2 do
		local tag = mw.ustring.match(line, "</ ?span>$");
		if tag then
			postfix = tag .. postfix
			line = mw.ustring.sub(line, 1, mw.ustring.len(line)-mw.ustring.len(tag))
		end
	end
	
	local ref = mw.ustring.match(line, ".'\"`UNIQ.-.*$");
	if ref then
		postfix = ref .. postfix
		line = mw.ustring.sub(line, 1, mw.ustring.len(line)-mw.ustring.len(ref))
	end
	
	for i = 1, 2 do
		local tag = mw.ustring.match(line, "</span>.*$");
		if tag then
			postfix = tag .. postfix
			line = mw.ustring.sub(line, 1, mw.ustring.len(line)-mw.ustring.len(tag))
		end
	end
	
	line = mw.ustring.gsub(line, '&nbsp;', ' ')
	line = mw.ustring.gsub(line, '&deg;', '°')
	line = mw.ustring.gsub(line, '&prime;', '′')
	line = mw.ustring.gsub(line, '&Prime;', '″')
	return prefix, mw.text.trim(line), postfix
end

--[[
parseTempl

Transforms decimal format latitude and longitude into the a
structure to be used in displaying coordinates

Returns (table, table)
]]
function parseTempl( ra, dec, format )
	local coordinateSpec = {}
	local errors = {}
	
	local ra_prefix, ra, ra_postfix = parseTags(ra) -- TODO: $ at the end
	local ra_h, ra_m, ra_s = mw.ustring.match(ra, "^(%+?[0-9]+)<sup>ч</sup>%s*([0-9]+)<sup>м</sup>%s*([0-9,%.]+)<sup>с</sup>");
	if not ra_h then
		ra_h, ra_m = mw.ustring.match(ra, "^(%+?[0-9]+)<sup>ч</sup>%s*([0-9]+)<sup>м</sup>");
		if not ra_h then
			ra_h = mw.ustring.match(ra, "^(%+?[0-9]+)<sup>ч</sup>");
			if not ra_h then
				table.insert(errors, {'parseTempl', 'некорректное прямое восхождение: ' .. ra})
			end
		end
	end
	
	local dec_prefix, dec, dec_postfix = parseTags(dec) -- TODO: $ at the end
	local dec_h, dec_m, dec_s = mw.ustring.match(dec, "^([+%-−–]?[0-9]+)°%s*([0-9]+)′%s*([0-9,%.]+)″");
	if not dec_h then
		dec_h, dec_m = mw.ustring.match(dec, "^([+%-−–]?[0-9]+)°%s*([0-9]+)′");
		if not dec_h then
			dec_h = mw.ustring.match(dec, "^([+%-−–]?[0-9]+)°");
			if not dec_h then
				table.insert(errors, {'parseTempl', 'некорректное склонение: ' .. dec})
			end
		end
	end
	
	if #errors == 0 then
		coordinateSpec, errors = parseHMS(ra_h, ra_m, ra_s, dec_h, dec_m, dec_s, format)
		coordinateSpec['ra-prefix'] = ra_prefix
		coordinateSpec['ra-postfix'] = ra_postfix
		coordinateSpec['dec-prefix'] = dec_prefix
		coordinateSpec['dec-postfix'] = dec_postfix
	end
	
	return coordinateSpec, errors
end


--[[ Helper function, handle optional args. ]]
function optionalArg(arg, suplement, prefix, shorten)
	if arg ~= nil and arg ~= "" then
		if mw.ustring.match(arg, '[,%.]') and shorten then
			arg = mw.ustring.gsub(arg, ',', '.')
			arg = mw.ustring.format( "%.2f", arg)
		end
		arg = mw.ustring.gsub(arg, '%.', ',')
		return prefix .. arg  .. suplement
	end
	return ""
end

--[[
parseHMS

Transforms hours, minutes, seconds format right ascension and declination
into the structure to be used in displaying coordinates

Returns (table, table)
]]
function parseHMS( ra_h, ra_m, ra_s, dec_h, dec_m, dec_s, format )
	local coordinateSpec = {}
	local errors = {}
	
	dec_h = mw.ustring.gsub(dec_h, '[−–]', '-') -- minus or en dash to hyphen
	errors = validateHMS( ra_h, ra_m, ra_s, dec_h, dec_m, dec_s, 'parseHMS' );
	if #errors ~= 0 then
		return coordinateSpec, errors
	end
	
	if ra_s == '0' and dec_s == '0'  then
		ra_s, dec_s = nil, nil
		if ra_m == '0' and dec_m == '0' then
			ra_m, dec_m = nil, nil
		end
	end

	coordinateSpec['raw-hms-ra'] = ra_h .. 
		optionalArg (ra_m, "", '+') ..
		optionalArg (ra_s, "", '+')
	coordinateSpec["raw-hms-dec"] = dec_h .. 
		optionalArg (dec_m, "", '+') ..
		optionalArg (dec_s, "", '+')

	coordinateSpec["hms-ra"] = ra_h .. "<sup>ч</sup>" ..
		optionalArg (ra_m, "<sup>м</sup>", '&nbsp;') ..
		optionalArg (ra_s, "<sup>с</sup>", '&nbsp;', true)
	coordinateSpec["hms-dec"] = dec_h .. "°" ..
		optionalArg (dec_m, "&prime;", '&nbsp;') ..
		optionalArg (dec_s, "&Prime;", '&nbsp;', true)

	if format ~= "" then
		coordinateSpec.default = format
	else
		coordinateSpec.default = "hms"
	end

	return coordinateSpec, errors
end

--[[
specPrinter

Output formatter.  Takes the structure generated by either parseTempl,
or parseHMS and formats it for inclusion on Wikipedia.
]]
function specPrinter(args)
	local coordinateSpec, errors = formatTest(args)
	
	if errors ~= '' then
		return errors
	end
	if next(coordinateSpec) == nil then -- if is empty
		return ''
	end
	
	local params = coordinateSpec["param"] -- only main params, not extra_params
	local extra_params = coordinateSpec["extra_param"]
	
	local inner = ''
	local prefix = ''
	local postfix = ''
	if args.display == 'inline-ra' then
		inner = coordinateSpec['hms-ra']
		prefix = coordinateSpec['ra-prefix'] or ''
		postfix = coordinateSpec['ra-postfix'] or ''
	elseif args.display == 'inline-dec' then
		inner = coordinateSpec['hms-dec']
		prefix = coordinateSpec['dec-prefix'] or ''
		postfix = coordinateSpec['dec-postfix'] or ''
	else
		inner = coordinateSpec['hms-ra'] .. ' ' .. coordinateSpec['hms-dec']
		prefix = '' -- TODO for inline mode
		postfix = '' -- TODO for inline mode
	end
	inner = mw.ustring.gsub(inner, '-', '−') -- hyphen to minus
	
	local maplinkArgs = {
		['locale'] = 'ru',
		['ra'] = coordinateSpec['raw-hms-ra'],
		['de'] = coordinateSpec['raw-hms-dec'],
		['show_box'] = args.box or '1',
		['box_color'] = args.box_color or '',
		['box_width'] = args.box_width or args.box_size or '',
		['box_height'] = args.box_height or args.box_size or '',
		['view'] = args.view or '',
		['zoom'] = args.zoom or '6'
	}
	local uriComponents = {}
	for k, v in pairs( maplinkArgs ) do
		if v ~= '' then
			table.insert(uriComponents, k .. '=' .. v );
		end
	end

	local result = '<span class="coordinates plainlinks nourlexpansion">'
	result = result .. globalFrame:preprocess(
		prefix .. '[http://www.wikisky.org?' .. table.concat( uriComponents, '&' ) .. ' ' .. inner .. ']' .. postfix
	)
	result = result .. '</span>'
	
	return errors and result .. errors or result
end

--[[
Formats any error messages generated for display

Returns string
]]
function errorPrinter(errors)
	local result = ""
	for i,v in ipairs(errors) do
		local errorHTML = '<strong class="error">Небесные координаты: ' .. v[2] .. '</strong>'
		result = result .. errorHTML .. "<br>"
	end
	if #errors > 0 and mw.title.getCurrentTitle():inNamespace(0) then
		result = result .. '[[Категори:Википедия:Страницы с неправильными астрономическими координатами]]'
		end
	return result
end

--[[
Check the input arguments for coord to determine the kind of data being provided
and then make the necessary processing.

Returns (table, string)
]]
function formatTest(args)
	local result, errors = {}, {};
	local param, extra_param = {}, {}

	if args.ra and args.ra ~= '' and args.dec and args.dec ~= '' then
		-- template {{ra|...}}, {{dec|...}} logic
		result, errors = parseTempl( args.ra, args.dec, args['format'] )
		param = { args.ra, args.dec, args[3] };
	elseif args.ra_h and args.ra_h ~= '' and args.dec_h and args.dec_h ~= '' then
		result, errors = parseHMS( args.ra_h, args.ra_m, args.ra_s,
			args.dec_h, args.dec_m, args.dec_s, args['format'] )
		param = { args.ra_h, args.ra_m, args.ra_s,
			args.dec_h, args.dec_m, args.dec_s, args[1] };
		if args[2] ~= '' then
			table.insert( errors, { 'formatTest', 'неожиданные дополнительные параметры' } );
		end
	elseif args[1] ~= '' and args[4] ~= '' then
		-- hms logic
		result, errors = parseHMS( args[1], args[2], args[3],
			args[4], args[5], args[6], args['format'] )
		param = { args[1], args[2], args[3], args[4], args[5],
			args[6], args[7] };
		if args[8] ~= '' then
			table.insert( errors, { 'formatTest', 'неожиданные дополнительные параметры' } );
		end
	else
		return {}, ''
	end
	
	if not result then
		return nil, errorPrinter( errors )
	end

	local last = table.getn (param)
	if param[last] == '' then
		table.remove(param, last)
	end

	local extra_params = { 'box', 'box_size', 'box_width', 'box_height', 'box_color', 'view', 'zoom' }
	for _, v in ipairs( extra_params ) do
		if (args[v] or '') ~= '' then
			extra_params.v = args[v];
		end
	end

	result.param = table.concat( param , '_' );
	result.extra_param = table.concat( extra_params , '_' );

	return result, errorPrinter( errors )
end

--[[
Checks input values to for out of range errors.

Return a table
]]
function validateHMS( ra_h, ra_m, ra_s, dec_h, dec_m, dec_s, source )
	local errors = {};
	
	if ra_h == nil or ra_h == '' then
		table.insert(errors, {source, "пропущено прямое восхождение"})
	end
	if not mw.ustring.match(ra_h, '^%+?[0-9]+$') then
		table.insert(errors, {source, "некорректные часы прямого восхождения"})
	end
	if ra_m ~= nil and ra_m ~= '' and not mw.ustring.match(ra_m, '^[0-9]+$') then
		table.insert(errors, {source, "некорректные минуты прямого восхождения: " .. ra_m})
	end
	if ra_s ~= nil and ra_s ~= '' and not mw.ustring.match(ra_m, '^[0-9,\.]+$') then
		table.insert(errors, {source, "некорректные секунды прямого восхождения"})
	end
	if dec_h == nil or dec_h == '' then
		table.insert(errors, {source, "пропущено склонение"})
	end
	if not mw.ustring.match(dec_h, '^[+%-−–]?[0-9]+$') then
		table.insert(errors, {source, "некорректные часы склонения"})
	end
	if dec_m ~= nil and dec_m ~= '' and not mw.ustring.match(dec_m, '^[0-9]+$') then
		table.insert(errors, {source, "некорректные минуты склонения"})
	end
	if dec_s ~= nil and dec_s ~= '' and not mw.ustring.match(dec_m, '^[0-9,\.]+$') then
		table.insert(errors, {source, "некорректные секунды склонения"})
	end
	
	ra_h = tonumber( ra_h ) or 0;
	ra_m = tonumber( ra_m ) or 0;
	ra_s = tonumber( ra_s ) or 0;
	dec_h = tonumber( dec_h ) or 0;
	dec_m = tonumber( dec_m ) or 0;
	dec_s = tonumber( dec_s ) or 0;

	if ra_h > 24 then
		table.insert(errors, {source, "прямое восхождение > 24"})
	end
	if ra_h < 0 then
		table.insert(errors, {source, "прямое восхождение < 0"})
	end
	if ra_m > 60 then -- TODO: >=
		table.insert(errors, {source, "минуты прямого восхождения > 60"})
	end
	if ra_m < 0 then
		table.insert(errors, {source, "минуты прямого восхождения < 0"})
	end
	if ra_s > 60 then -- TODO: >=
		table.insert(errors, {source, "секунды прямого восхождения > 60"})
	end
	if ra_s < 0 then
		table.insert(errors, {source, "секунды прямого восхождения < 0"})
	end
	if dec_h > 90 then
		table.insert(errors, {source, "склонение > 90"})
	end
	if dec_h < -90 then
		table.insert(errors, {source, "склонение < -90"})
	end
	if dec_m > 60 then -- TODO: >=
		table.insert(errors, {source, "минуты склонения > 60"})
	end
	if dec_m < 0 then
		table.insert(errors, {source, "минуты склонения < 0"})
	end
	if dec_s > 60 then -- TODO: >=
		table.insert(errors, {source, "секунды склонения > 60"})
	end
	if dec_s < 0 then
		table.insert(errors, {source, "секунды склонения < 0"})
	end
	
	return errors;
end

--[[
coord

Main entry point for Lua function to implement {{AstroCoord}}
]]
function coordinates.coord(frame)
	globalFrame = frame
	local args = frame.args
	if args[1] == nil then
		local pFrame = frame:getParent();
		args = pFrame.args;
		for k,v in pairs( frame.args ) do
			args[k] = v;
		end
	end
	
	for i=1,8 do
		if args[i] == nil then
			args[i] = ""
		else
			args[i] = args[i]:match( '^%s*(.-)%s*$' );  --remove whitespace
		end
	end
	
	args['format'] = args['format'] or '';
	
	Display = string.lower(args.display or "inline")
	local contents = specPrinter(args)
	local Notes = args.notes or ""
	if Display == '' then
		Display = 'inline';
	end
	
	local text = ''
	if contents ~= '' then
		if string.find( Display, 'inline' ) ~= nil then
			text = displayinline(contents, Notes)
		end
		if string.find( Display, 'title' ) ~= nil then
			text = text .. displaytitle(contents, Notes, frame)
		end
	end
	return text
end

return coordinates