Dieses Modul ist noch im Aufbau und noch nicht voll funktionsfähig. Rückfragen an mich. ÅñŧóñŜûŝî (Ð) 17:33, 30. Apr. 2023 (CEST)

local function GetBracketData(fullname)
	fullname = string.gsub(fullname,'"','');
	local num = tonumber(string.sub(fullname,1,6)) or 0;
	local posbrackl = string.find(fullname,'(',1,true) or false;
	local posbrackr = string.find(fullname,')',1,true) or false;
	if posbrackl and posbrackr then
		return string.sub(fullname,posbrackl+1,posbrackr-1), true;
	else
		return '', false;
	end
end

--Aufteilen einer einzelnen Zeile anhand eines Separators. 
local function CutString(str,sp)
	local tbl = {};
	local text = str;
	local teil;
	sep = sp or "/";
	if #str == 0 then
		return tbl;
	end
	text = text ..sep
	for i = 1,50 do
		pos = string.find(text,sep) or 0;
		teil = string.sub(text,1,pos-1);
		if pos < 1 then
			break;
		end
		table.insert (tbl,teil);
		text = string.sub(text,pos+1);
	end
	return tbl;
end

-- Teilen einer Zeichenkette an enthaltenen Zeilenumbrüchen
local function GetLines(str)
	return CutString(str,'\n')
end

-- GetDataPage liest den Quelltext einer Datenseite aus und gibt die Zeilen im Pre-Tag in einer table zurück.
function GetDataPage(namespace,title)
	local Seite = mw.title.makeTitle(namespace, title);
	local Content = Seite:getContent()
	local Lines = {};
	local von;
	local bis;
	-- alles außerhalb des Pre-Tags entfernen
	von = string.find(Content,'<pre>',1,true) or false;
	bis = string.find(Content,'</pre>',1,true) or false;
	if von and bis then
		Content = string.sub(Content,von,bis+5);
	else
		Content = nil;
		return Lines, false;
	end
	Lines = GetLines(Content);
	Content = nil;
	return Lines, true;
end

function GetDataSet(Id)
	local Zeilen = {};
	local Fields ={};
	local Set = {};
	local Cells = {};
	local Zahl = 0;
	local SPK  = 2000000 + Id;
	local isOK;
	Zeilen, isOk = GetDataPage('Vorlage','Infobox Asteroid/Daten')
	if not isOk then
		return  Cells, Fields, false
	end
	table.remove (Zeilen , 1); -- Pre-Tag entfernen
	Fields = CutString(Zeilen[1],',');
	for row = 2, #Zeilen do
		Set = CutString(Zeilen[row],',')
		for col = 1, #Fields do
			Cells[Fields[col]] = Set[col];
		end
		Zahl = tonumber(Cells['spkid']) or 0;
		if Zahl == SPK then
			Zeilen = nil;
			return Cells, Fields, true;
		end
	end
	return Cells, Fields, false;
end

function GetOrbitPeriodString(days) -- Ausgabestring für die Umlaufdauer
	local PeriodDay =  tonumber(days) or 0;
	local PeriodYear = PeriodDay / 365.25;
	local years = 0;
	local days = 0;

	if PeriodYear  >= 100 then
		years = math.floor(PeriodYear + 0.5);
		days = false;
	elseif PeriodYear  >= 1 then
		years = math.floor(PeriodDay / 365.25);
		days =  math.floor((PeriodDay - years *365.25) + 0.5);
		if days > 364 then -- wegen Rundung möglich
			years = years + 1;
			days = days -365;
		end
	else
		years = false;
		days =math.floor(PeriodDay + 0.5);
	end
	local Periode = '';
	if years then 
		Periode = Periode .. tostring(years) .. ' [[Jahr|a]] '
	end
	if days then 
		Periode = Periode .. tostring(days) .. ' [[Tag|d]]'
	end
	return Periode;
end	

function GetRotationString(hours) -- Ausgabestring für die Rotation
	local Tage = 0;
	local Std = 0;
	local Min = 0
	local Sek = 0;
	local RotStr='';
	local Rotation= tonumber(hours) or 0;
	Rotation = math.floor(Rotation * 3600 + 0.5); -- in ganze Sekunden umwandeln
	-- hier liegt die Rotation in Sekunden vor. 
	if Rotation >= 8638200 then -- >= 99 Tage und 23,5 Stunden; Ausgabe nur ganze Tage
		Tage = math.floor(Rotation/86400 + 0.5);
		RotStr = tostring(Tage) .. ' [[Tag|d]] ';
	elseif Rotation >= 86400 then -- 1 Tag  bis < 99 Tage 23,5 Stunden, Ausgabe Tage und Stunden
		Tage = math.floor(Rotation/86400);
		Std = math.floor((Rotation - Tage * 86400)/3600 + 0.5);
		if Std == 24 then
			Tage = Tage + 1;
			Std = 0;
		end
		RotStr = tostring(Tage) .. ' [[Tag|d]] ' .. tostring(Std) .. ' [[Stunde|h]] '; 
	elseif  Rotation >= 3600 then -- Eine Stunde bis < 1 Tag, Ausgabe Stunden und Minuten
		Rotation = math.floor(Rotation / 60 + 0.5); 
		-- Rotation in diesem case in Minuten, gerundet auf ganze Zahl
		Std = math.floor(Rotation /60);
		Min = Rotation % 60;
		RotStr =  tostring(Std) .. ' [[Stunde|h]] ' ..  tostring(Min) .. ' [[Minute|min]] '; 
	elseif Rotation > 0 then -- unter einer Stunde, aber > Null
		Min = math.floor(Rotation /60);
		Sek = Rotation % 60;
		RotStr = RotStr .. tostring(Min) .. ' [[Minute|min]] '; 
		RotStr = RotStr .. tostring(Sek) .. ' [[Sekunde|s]]'; 
	else -- Wert nicht positiv
		RotStr = ''
	end
	return RotStr;
end

local p = {}

-- Aufruf der Infobox mit eingelesenen Werten
function p.CreateTemplate(frame)
	local ID =  frame.args['SSD_ID'] or 0;
	if ID == 0 then
		return '<div class="error float-right">Es wurde keine gültige ID angegeben!</div>';
	end
	local Felder = {};
	local Werte = {};
	local isOk = false;
	Werte, Felder, isOk = GetDataSet(ID);
	if not isOk then
		return '<div class="error float-right">Es wurde kein gültiger Datensatz gefunden!</div>';
	end
	local a = tonumber(Werte['a'] or '') or -1;
	local e = tonumber(Werte['e'] or '') or -1;
	local i = tonumber(Werte['i'] or '') or -1;
	local Perihel = a * (1 - e);
	local Aphel   = a * (1 + e);
	local TNO = ''; if a > 30 then TNO = 'ja'; end
	local Smass  = Werte['spec_B'] or '';
	Smass=mw.ustring.gsub(Smass, '"','');
	local Tholen = Werte['spec_T'] or '';
	Tholen=mw.ustring.gsub(Tholen, '"','');
	local Albedo = Werte['albedo'] or '';
	local H =  Werte['H'] or '';
	local Knoten =  tonumber(Werte['om'] or '') or '';
	local Periwinkel = tonumber(Werte['w'] or '') or '';
	local PeriJD = tonumber(Werte['tp'] or '') or '';
	local Epoche = tonumber(Werte['epoch'] or '') or '';
	local Durchmesser = tonumber(Werte['diameter'] or '') or 0;
	local Abmessungen = Werte['extent'] or '';
	Abmessungen = mw.ustring.gsub( Abmessungen, 'x',' × ');
	Abmessungen = mw.ustring.gsub( Abmessungen, '"','');
	local Rotation = tonumber(Werte['rot_per']) or 0;
	local Tage = 0;
	local Std = 0;
	local Min = 0
	local Sek = 0;
	local RotStr='';
	if Rotation > 0 then

		Rotation= math.floor(Rotation * 3600 + 0.5); -- in ganze Sekunden umwandeln
		Tage = math.floor(Rotation/86400);
		Std = math.floor((Rotation - Tage * 86400)/3600);
		Min = math.floor((Rotation - Tage * 86400 - Std * 3600) /60);
		Sek = Rotation % 60;
		if Tage > 0 then
			RotStr = tostring(Tage) .. ' [[Tag|d]] ';
		end
		if Tage	< 100 then
			RotStr = RotStr .. tostring(Std) .. ' [[Stunde|h]] '; 
		end
		if Tage	< 10 then
			RotStr = RotStr .. tostring(Min) .. ' [[Stunde|min]] '; 
		end
		if Tage	== 0 then
			RotStr = RotStr .. tostring(Sek) .. ' [[Sekunde|s]]'; 
		end
	end

	local Dichte = '';
	local Masse = '';
	local GM = tonumber(Werte['GM'] or '') or 0;
	Masse = GM / 6.67430 * math.pow(10,20);
	if Durchmesser > 0 and Masse > 0 then
		Dichte = Masse / ( math.pow(10,12)* Durchmesser * Durchmesser * Durchmesser * 3.1415926538 /6  )
		Dichte = string.format('%5.3f',Dichte); 
	else
		Dichte = ''; 
	end
	if Masse == 0 then
		Massetext = '';
	else
		Masse =  string.format('%7.5E',Masse);
		local pos = string.find(Masse,"E") or 0
		if pos > 0 then
			Massetext = string.sub(Masse,pos-1) .. '&nbsp;&#183;&nbsp;10<sup>' ..  string.sub(Masse,pos+1) .. '</sup>'
		else
			Massetext = '';
		end
	end
	local Name = Werte['name'] or '';
	local SysName = GetBracketData(Werte['full_name'] or '')
	-- unbenannte Asteroiden bekommen den syst. Namen
	if Name =='' then
		Name = SysName;
		SysName = ''
	end
	local PeriodDay =  tonumber(Werte['per'] or 0)
	local PeriodYear = PeriodDay / 365.25;
	local years = 0;
	local days = 0;

	if PeriodYear  >= 100 then
		years = math.floor(PeriodYear + 0.5);
		days = false;
	elseif PeriodYear  >= 1 then
		years = math.floor(PeriodDay / 365.25);
		days =  math.floor((PeriodDay - years *365.25) + 0.5);
		if days > 364 then
			years = years + 1;
			days = days -365;
		end
	else
		years = false;
		days =math.floor(PeriodDay + 0.5);
	end
	local Umlaufdauer = '';
	if years then 
		Umlaufdauer = Umlaufdauer .. tostring(years) .. ' a '
	end
	if days then 
		Umlaufdauer = Umlaufdauer .. tostring(days) .. ' d'
	end
	
	-- Es fehlt noch die Umrechnung für Bahngeschwindigkeit

	local Args = frame.args; -- Vorbelegung von Args mit den übergebenen Werten

	-- einige nicht angegebene Parameter werden durch die ausgelesenen ersetzt:
	if Args['Name']         == '' then Args['Name'] = Name; end
	if Args['anderer_Name'] == '' then Args['anderer_Name'] = SysName; end
	Args['Tholen'] = Tholen;
	Args['TholenRef']=''
	Args['Smass'] = Smass;
	Args['SmassRef']=''

	if a > 0 then
		Args['Große_Halbachse'] = string.format('%9.4f',a);
	else
		Args['Große_Halbachse'] = '';
	end
	if e >= 0 then
		Args['Exzentrizität'] =  string.format('%6.4f',e);
	else
		Args['Exzentrizität'] = '';
	end
	if i >= 0 then
		Args['Bahnneigung'] =  string.format('%7.2f',i);
	else
		Args['Bahnneigung'] = '';
	end
	if a > 0 and e >= 0 then
		Args['Perihel'] =  string.format('%.3f',Perihel);
		Args['Aphel']   =  string.format('%.3f',Aphel);
	else
		Args['Perihel'] = '';
		Args['Aphel'] = '';
	end
	if Knoten ~='' then
		Args['Knoten'] =  string.format('%7.2f',Knoten);
	else
		Args['Knoten'] = '';
	end
	if Periwinkel ~='' then
		Args['Periwinkel'] =  string.format('%7.2f',Periwinkel);
	else
		Args['Periwinkel'] = '';
	end
	if Epoche ~='' then
		Args['Epoche'] =  string.format('%10.1f',Epoche);
	else
		Args['Epoche'] = '';
	end
	if PeriJD ~='' then
		Args['PeriJD'] =  string.format('%10.1f',PeriJD);
	else
		Args['PeriJD'] = '';
	end
	Args['Rotationsperiode'] = Rotation;
	Args['Masse'] = Massetext;
	Args['Dichte'] = Dichte;
	Args['Albedo'] = Albedo;

	if H ~='' then
		Args['Absolute_Helligkeit'] =  string.format('%8.3f',H);
	else
		Args['Absolute_Helligkeit'] = '';
	end

	Args['Abmessungen'] = Abmessungen;
	Args['Umlaufdauer'] = Umlaufdauer;
	Args['Rotationsperiode'] = RotStr;
	Args['Umlaufgeschwindigkeit'] = '';
	Args['SSD_TNO'] = TNO ;
	if frame.args['test'] or '' ~= '' then
		local S =  tostring(#Args) ..'\n';
		S = S .. '\n* SSD_ID = ' ..tostring(Args['SSD_ID']	or 'nil')
		S = S .. '\n* SSD_TNO = ' ..tostring(Args['SSD_TNO']	or 'nil')
		S = S .. '\n* Name = ' ..tostring(Args['Name']	or 'nil')
		S = S .. '\n* anderer_Name = ' ..tostring(Args['anderer_Name']	or 'nil')
		S = S .. '\n* Tholen = ' ..tostring(Args['Tholen']	or 'nil')
		S = S .. '\n* Smass = ' ..tostring(Args['Smass'] or 'nil')
		S = S .. '\n* Große_Halbachse = ' ..tostring(Args['Große_Halbachse']	or 'nil')
		S = S .. '\n* Exzentrizität = ' ..tostring(Args['Exzentrizität']	or 'nil')
		S = S .. '\n* Bahnneigung = ' ..tostring(Args['Bahnneigung']	or 'nil')
		S = S .. '\n* Perihel = ' ..tostring(Args['Perihel']	or 'nil')
		S = S .. '\n* Aphel = ' ..tostring(Args['Aphel']	or 'nil')
		S = S .. '\n* Knoten = ' ..tostring(Args['Knoten']	or 'nil')
		S = S .. '\n* Periwinkel = ' ..tostring(Args['Periwinkel']	or 'nil')
		S = S .. '\n* Epoche = ' ..tostring(Args['Epoche']	or 'nil')
		S = S .. '\n* PeriJD = ' ..tostring(Args['PeriJD']	or 'nil')
		S = S .. '\n* Rotationsperiode = ' ..tostring(Args['Rotationsperiode']	or 'nil')
		S = S .. '\n* Masse = ' ..tostring(Args['Masse']	or 'nil')
		S = S .. '\n* Dichte = ' ..tostring(Args['Dichte']	or 'nil')
		S = S .. '\n* Albedo = ' ..tostring(Args['Albedo']	or 'nil')
		S = S .. '\n* Absolute_Helligkeit = ' ..tostring(Args['Absolute_Helligkeit']	or 'nil')
		S = S .. '\n* Abmessungen = ' ..tostring(Args['Abmessungen']	or 'nil')
		S = S .. '\n* Umlaufdauer = ' ..tostring(Args['Umlaufdauer']	or 'nil')
		S = S .. '\n* Umlaufgeschwindigkeit = ' ..tostring(Args['Umlaufgeschwindigkeit']	or 'nil')
		return S;
	end
	local Text = frame:expandTemplate{ title = 'Vorlage:Infobox Asteroid/Extrabox', args = Args }
	return Text;
end

function p.CheckData(frame)
	local Seite = mw.title.makeTitle('Vorlage','Infobox Asteroid/Daten');
	local Content = Seite:getContent()
	local c;
	local von;
	local bis;
	-- alles außerhalb des Pre-Tags entfernen
	von,c = string.find(Content,'<pre>',1,true);
	c, bis = string.find(Content,'</pre>',1,true);
	Content = string.sub(Content,von,bis);
	return string.sub(Content,1, frame.args[1]);
end

function p.OrbitPeriod(frame)
	local Tage =  tonumber(frame.args[1]) or -1;
	local Text = "";
	if Tage >= 0 then
		Text = GetOrbitPeriodString(Tage);
	else
		Text = frame.args[1]; -- wenn keine Zahl, dann unverändert zurück
	end
	return Text;
end

function p.Rotation(frame)
	local Stunden = tonumber(frame.args[1]) or 0;
	local Text = "";
	if Stunden > 0 then
		Text = GetRotationString(Stunden)
	else
		Text = frame.args[1]; -- wenn keine Zahl, dann unverändert zurück
	end
	return Text;
end

return p
--[[
Auftrag: In einem tabellarischen Seiteninhalt eine Zeile suchen und die
Werte der Spalten in eine Wiki-Schablone einfügen.
Bedeutung der Spalten in der ersten Zeile
]]