Modul:Benutzer:Kpfiwa/Infobox Leuchtfeuer


-- TEST VIA                  Benutzer:Kpfiwa/Leuchtfeuer
frame = mw.getCurrentFrame() ---- wichtig!
coord = "{{Coordinate|text=/|NS=45.6|EW=29.89|type=building|region=UA-51|name=Oberfeuer}}<br>"
coord1 = frame:preprocess(coord)---- so werden Vorlagen hier abgearbeitet
poka =
    frame:preprocess(
    "{{Positionskarte+|Ukraine Oblast Odessa|float=center|width=250|relief=1|border=none|caption=|places={{Positionskarte~|Ukraine Oblast Odessa|label=Unterfeuer|position=left|lat=45.672939|long=29.883517|region=UA-51|mark=Legenda latarnia.svg|marksize=15}}}}"
)
tester =
    frame:preprocess(
    "{{Positionskarte+|Ukraine Oblast Odessa|float=center|width=250|relief=1|border=none|caption=|places={{Positionskarte~|Ukraine Oblast Odessa|label=Unterfeuer|position=left|lat=45.672939|long=29.883517|region=UA-51|mark=Legenda latarnia.svg|marksize=15}}}} UND DANN NOCH {{Coordinate|text=/|NS=45.6|EW=29.89|type=building|region=UA-51|name=Oberfeuer}}<br> UND MEINE FLAGGE {{Flagge|DEU}}<br>"
)

tester =
    "{{Positionskarte+|Ukraine Oblast Odessa|float=center|width=250|relief=1|border=none|caption=|places={{Positionskarte~|Ukraine Oblast Odessa|label=Unterfeuer|position=left|lat=45.672939|long=29.883517|region=UA-51|mark=Legenda latarnia.svg|marksize=15}}}} UND DANN NOCH {{Coordinate|text=/|NS=45.6|EW=29.89|type=building|region=UA-51|name=Oberfeuer}}<br> UND MEINE FLAGGE {{Flagge|DEU}}<br>"
flag = frame:preprocess("{{Flagge|DEU|v=1}}<br>[[Deutschland]]<br>")
local version = _VERSION
--[=[ Leuchtfeuer Version 1 BETA, 2021-08-01
	Formatierung der Infobox Leuchtfeuer für 2 Leichttürme am gleichen Ort (Molenfeuer, Richtfeuer etc.)
--]=]

p = {}
local wlink = 0 -- Steuert, ob Textanzeige oder Wikilink
local lang = mw.getContentLanguage():getCode()
liste = "Modul:Benutzer:Kpfiwa/Infobox Leuchtfeuer/Info_" .. lang -- Modul:Benutzer:Kpfiwa/Infobox Leuchtfeuer/Info de
info = {}
head = '\n{| class="wikitable float-right infobox hintergrundfarbe2 toptextcells"\n'
local kopfzeile = {lemma, name, altname}
-- local _TEST = version .. 'LOS\n----<br>\n' ..flag .. '\n' .. poka ..'\n' .. coord .. '\n{|
local _TEST =
    tester .. ' LOS\n----<br>\n{| class="wikitable float-right infobox hintergrundfarbe2 toptextcells"\n!Key!!Wert'
infobox = '{| class="wikitable float-right infobox hintergrundfarbe2 toptextcells"' -- Eröffnung der Box

local function fehler(txt) -- Fehlerfall;  enthält Fehlermeldung
    return '<span class="error">' .. (txt or "FEHLER") .. "</span>"
end -- function fehler

local erg, info = pcall(require, liste)
fehler("Liste nicht verfügbar")
-- hier noch auf Fehler abfragen

--- EVENTUELL ALLE FUNKTIONEN AUSLAGERN!
function round(nr, prec, dp) -- Zahl, Nachkommastellen, Dezimartrenner
    local val = nr or 0
    -- zuerst  mal unbrauchbare Zahlen, wie 1.678,90 bereinigen und zu 1678.99 wandeln
    if string.find(nr, ",") then -- also nur wenn ein Komma drin ist
        val = nr:gsub("%.", "") -- Denn Deimalkomma, dann Punkte raus
        if not dp then
            val = string.gsub(val, ",", ".") -- und Komma zum Punkt machen.
        end
    end
    local fmtStr = string.format("%%0.%sf", prec or 0)
    val = fmtStr:format(val)
    return val
end -- function round()

function trim(s) -- führende und hintere Leerzeichen entfernen
    return s:match "^%s*(.*%S)" or ""
end -- function trim(s)

local function tprint(t)
    local tprint_cache = {}
    local function sub_tprint(t, indent)
        if (tprint_cache[tostring(t)]) then
            print(indent .. "*" .. tostring(t))
        else
            tprint_cache[tostring(t)] = true
            if (type(t) == "table") then
                for pos, val in pairs(t) do
                    if (type(val) == "table") then
                        print(indent .. "[" .. pos .. "] => " .. tostring(t) .. " {")
                        sub_tprint(val, indent .. string.rep(" ", string.len(pos) + 8))
                        print(indent .. string.rep(" ", string.len(pos) + 6) .. "}")
                    elseif (type(val) == "string") then
                        print(indent, pos, trim(val))
                    else
                        print(indent .. "[" .. pos .. "] => " .. tostring(val))
                    end
                end
            else
                print(indent .. tostring(t))
            end
        end
    end
    if (type(t) == "table") then
        print(tostring(t) .. " {")
        sub_tprint(t, "  ")
        print("}")
    else
        sub_tprint(t, "  ")
    end
end -- function tprint(tbl)

function nolink(a)-- extrahiert aus www bzw wikilinks den Text
    local ret, a = "", a or ""
    ret = a:gsub("[%[%]]*", "") -- alle eckigen Klammern rasieren
    if #ret + 4 == #a then -- Wikilink mit '|' www mit ' ', was dann kommt, wird gebraucht
        search = "%|"
    else
        search = "%s"
    end
    return trim(ret:sub((ret:find(search) or 0) + 1, #a)) -- komm packt!
end


--[[
Ausgbe in x sm  (y km) oder 1:1, wenn z km vorgegeben. Wenn n val nur Zahl oder als  sm oder nm, dann umrechnen
--]]
function val2sm_km(val)
    val = string.lower(val or "") -- falls jemand z.B. Sm oder Kilometre schreibt
    --sn = "%s-[sn]"
    if tonumber(val) or val:find("[sn]") then -- wenn sm oder nm
        local sn = 1
        val = val:gsub("[^%.,%d]*", "") -- Alles ausser 0-9 , und . muss raus
        val = round(val) -- qusi val 'putzen'
        local ret = val .. "&nbsp;[[Seemeile|sm]] (" .. round(val * 1.852, 1, 1) .. "&nbsp;[[Meter#km|km]])"
        -- Sprachtypischer Dezimaltrenner, könnte erweitert werden
        if lang == "de" then
            ret = ret:gsub("%.", ",")
        end
        return ret
    else
        return val -- bei km-Angabe bleibt es einfach so
    end
end --function val2sm_km(val)

-- berechnet aus 2 Positionen die Mitte(lat/lon in decimal (gerundet), Distanz in sm und km, und dim bzw. osmzoom
function dist(lat1, lon1, lat2, lon2)
    if not (lat1 and lon1 and lat2 and lon2) then
        return fehler("Positionsangaben inkorrekt")
    end
    lat0 = (lat1 + lat2) / 2 -- Mitte aus Latitude
    lon0 = (lon1 + lon2) / 2 -- Mitte aus Longitude
    lat = (lat1 + lat2) / 2 * 0.01745 -- Entfernung  aus Latitude
    dx = 111.3 * math.cos(lat) * (lon1 - lon2)
    dy = 111.3 * (lat1 - lat2)
    km = math.sqrt(dx * dx + dy * dy)
    dim = km * 1000 + 200.5
    osmzoom = round(dim / 10000) -- das ist noch nicht korrekt!! Formel?
    sm = round(km / 1.852, 1)
    return km, sm, lat0, lon0, dim, osmzoom
end

local function div(k) -- Trenner ("Listeneinträge"), wenn was an Listen geboten, ggf. auch für Bemerkungsblock
    -- hier ggf. check, ob überhaupt Listeinträge vorhanden sind
    local ret = '|-\n!colspan="3"|'
    if k == "Listen" then
        ret = ret .. "Listeneinträge"
    else
        ret = ret .. "<hr>"
    end
    return ret
end -- function div()

local function finito() -- Tabellenabschluss , ggf. entbehrlich
    return "\n|}\n{{All Coordinates}}" -- ggf. noch Kategorien
end -- function finito()

local wlink = 0 -- Steuert, ob Textanzeige oder Wikilink

local function visirow(lbl, l, r) -- lbl= Label; linke, rechte Spalte
    if wlink == 0 then
        twl = "[[Tragweite_(Licht)#Nautische_Sichtweite|Nautische Sichtweite]] "
    else
        twl = "Nautische Sichtweite "
    end
    twl = '\n|-\n| style="background:#EFEFEF;"|' .. twl .. " "

    local ret = ""
    if l or r then
        l = val2sm_km(l) or "L"
        r = val2sm_km(r) or "R"
        ret = twl .. lbl .. "||"
        if l == r or r == "=" then
            ret = ret .. ' colspan="2"|' .. l
        else
            ret = ret .. l .. "||" .. r
        end
    end
    wlink = wlink + #ret
    return ret
end -- function visirow()

local function visi() -- Tragweite der jeweiligen Farben.ggf. Sonderfarbe
    wlink = 0 -- zurückseten, lls schonn verwendet
    local ret = "" -- falls es '' bleibt, dann via wd = "P2929" versuchen
    -- bei Sonstige zusammenbasteln
    if liste.FARBESONSTIG and liste.TRAGWEITESONSTIG then
        if liste.FARBESONSTIG.vl and (liste.TRAGWEITESONSTIG.vl or liste.TRAGWEITESONSTIG.vr) then
            liste.TRAGWEITESONSTIG.label = liste.FARBESONSTIG.vl
        end
    else
        liste.TRAGWEITESONSTIG, liste.FARBESONSTIG = {}, {}
    end
    if liste.TRAGWEITEWEISS and (liste.TRAGWEITEWEISS.vl or liste.TRAGWEITEWEISS.vr) then
        ret = ret .. visirow(liste.TRAGWEITEWEISS.label, liste.TRAGWEITEWEISS.vl, liste.TRAGWEITEWEISS.vr)
    end
    if liste.TRAGWEITEROT and (liste.TRAGWEITEROT.vl or liste.TRAGWEITEROT.vr) then
        ret = ret .. visirow(liste.TRAGWEITEROT.label, liste.TRAGWEITEROT.vl, liste.TRAGWEITEROT.vr)
    end
    if liste.TRAGWEITEGRN and (liste.TRAGWEITEGRN.vl or liste.TRAGWEITEGRN.vr) then
        ret = ret .. visirow(liste.TRAGWEITEGRN.label, liste.TRAGWEITEGRN.vl, liste.TRAGWEITEGRN.vr)
    end
    if liste.TRAGWEITESONSTIG and (liste.TRAGWEITESONSTIG.vl or liste.TRAGWEITESONSTIG.vr) then
        ret = ret .. visirow(liste.TRAGWEITESONSTIG.label, liste.TRAGWEITESONSTIG.vl, liste.TRAGWEITESONSTIG.vr)
    end
    if ret == "" then
    --  oder letztendlich wd = "P2929"
    end
    print(ret)
end -- function visi()

local function rem(k, c) -- Bemekungszeile (ggf (I) automatisch
    --Programm
end -- function

local function rows(k, c) -- normale Zeile, ggf. zusammengefasst wenn vr='=' oder vl==vr
    --Programm
end -- function

local function seamap(k, c) -- berechnen, wird via pos eingefügt. evtl. dort einbringen
    --Programm
end -- function

local function head(name, altname, lemma) -- Tabellenstart mit Überschriften
    local ret = '\n{| class="wikitable float-right infobox hintergrundfarbe2 toptextcells" '
    ret = ret .. 'summary="Infobox Leuchtfeuer"  id="Vorlage_Infobox_Leuchtfeuer"'
    ret = ret .. 'style="width:22em;margin-top:0;font-size:95%;"' -- width anpassen!!!!!
    ret = ret .. '\n!colspan="3" style="font-size:larger; background:#EBE085;"|'
    ret = ret .. name or lemma
    if altname then
        ret = ret .. "<hr><small>" .. altname .. "</small>"
    end
    return ret
end -- function head()

local function pic(p1, p2, c1, c2) -- Bild/er, QIX, ändern auf (k,c)
    local erg = "\n|"
    if p1 == p2 or p2 == "=" then
        erg = erg .. 'colspan="3" style="text-align:center"|[[File:' .. p1 .. "|zentriert|250x250px]]"
        if c1 then
            erg = erg .. "<br>" .. c1 -- ohne 2. Bildunterschrift
        end
    else
        erg = erg .. " ||"
        if p1 then -- 1. Bild, notfalls leer
            erg = erg .. 'style="text-align:center"|[[File:' .. p1 .. "|zentriert|120x120px]]"
            if c1 then
                erg = erg .. "<br>" .. c1
            end -- 1. Bildunterschrift
        end
        erg = erg .. "||"
        if p2 then -- 2. Bild
            erg = erg .. 'style="text-align:center"|[[File:' .. p2 .. "|zentriert|120x120px]]"
            if c2 then
                erg = erg .. "<br>" .. c2
            end -- 2. Bildunterschrift
        end
    end
    return erg
end -- function pic

local function unique(txt) -- Da UTF-8 mitunterr bei LUA knirscht, alles putzen!
    txt = txt or ""
    txt = txt:gsub("%++", "1") -- macht aus '+' 1, damit es keine Verwechslung mit Rechenoperationen geben kann
    txt = txt:upper():gsub("([^A-Z1]*)", "") -- rasiert alle Zeichen außer A-Z und 1 und wandelt alles in Versalien
    return txt
end -- function unique

function latlon(k, c)
end -- function latlon  --via pos()?
function pos(
    latlon,
    dir --[[ einheitliches Format bei Positionen, Positionsberechnung. Könnte ggf. via preprocess {{Coordinate ... abgewickelt werden --]])
    -- Seamap  berechnen, Erstellen der Lagekarte mit beiden Positionen (colspan=2)
    local ll, erg, llm, lls, ns, corr, max = {}, 0, 0, 0, 1, 360, 180
    --[[ NSOW auswerten, nur WS ist interessant da negativ; shit für Franzosen mit 'Ouest' evtl in Sprachfile (Info_fr) auslagern
	evtl über Sprache abwickeln --]]
    if dir == "[sSwW]+" or latlon:find("[wsWS]+") then -- für SW (max 90°), oder NE (180°)
        corr = 180
        max = 90
        ns = -1
        if latlon:find("[wsWS]+") then
            ns = -1
        end
    end -- if dir
    -- vorab alle Eingabefehler ausgleichen
    latlon = latlon:gsub("%s", "") -- alle Leerzeichen weg
    latlon = latlon:gsub(",", ".") -- Dezimalkomma wird Dezimalpunkt
    latlon = latlon:gsub("[%°]+", "/") -- konventionelles Gradzeichen umsetzen:° ist UTF8, deswegen separat
    latlon = latlon:gsub('[%\'"]', "/") -- konventionelle Min. umsetzen
    latlon = latlon:gsub("//", "/") -- falls Sekunden mit "''" angegeben
    ll = {string.match(latlon, "(%d+)/([%d%.]*)/*([%d%.]*)/*(%a*)")} -- Grad, min, sec, Richtung aufdröseeln
    ell = {string.match(latlon, "(%d+)/([%d%.]*)/*([%d%.]*)")} -- Grad, min, sec aufdröseeln
    erg = ll[1] * 1
    llm = ll[2] * 1
    lls = ll[3] * 1 -- billiger als tonumber
    -- Falsche Gradeingaben korrigieren (EW)>180, NS>190
    if erg > max then
        erg = erg - corr
    end
    if llm > 60 then
        llm = 60
    end -- Fehlertoleranz, zuviel ergibt dann 1°
    if lls > 60 then
        lls = 60
    end -- ergibt  1'
    erg = ((((lls / 60) + llm) / 60) + erg) * ns -- eigntliche Dezimalumrechnung
    return math.floor(erg * 10 ^ 7 + 0.5) / 10 ^ 7 -- gerundet auf max 7 Stellen, as reicht total
end -- function pos(latlon)

local function rows(label, col1, col2) -- eine Tabelenzeile zusammensetzen, ggf. übergehen
    local row = ""
    -- verarbeiten; wenn beide gleich oder col2 == '=', dann Wert zentriert einbringen mit colspan=2
    if label and (col1 or col2) then
        row = "|- " .. label .. "||"
        if col1 == col2 or col2 == "=" then -- evtl '=' noch bereinigen von Doppel-/Folgezeichen
            row = row .. 'colspan="2" align=center|' .. col1
        else
            row = row .. col1 or "" .. "||" .. col2 or ""
        end
    end
    return row
end -- function rows

--[[ 
function valinsert(tbl,nom,val) schreibt einen Wert in eine Tabelle. Die Feldnamen sind in Variaben als String verfügbar
* tbl (table, optional); Tabelle, Standard/default ist _G 
* nom (string); Name der Variablen -- z.B. 'ABC' überprüft die ggf. übergeordneten Tabellen und setzt 'ABC' auf <val>. Fehlende übergeornete Tabellen werden angelegt. Trenner ist '|'
Die Verwendung einzelner Punkte am Ende fügt den Wert an der letzten Position des Arrays ein -- z.B. 'A|' überprüft  Tabelle A und setzt A[table.getn(A)] auf <val>. Mehrere Pipes werden als String interpretiert - z.B. 'A|B.|' überprüft die Tabelle A||B. 
* val (beliebig)
--]]
function valinsert(tbl, nom, val)
    local v = "vl"
    local i = string.find(nom, "%d", -1)
    if i then
        nom = (string.sub(nom, 1, i - 1))
        v = "vr"
    end
    if type(tbl) ~= "table" then
        tbl, nom, val = _G, tbl, nom
    end -- eigentlich entbehrlich, da Tabelle i.d.R. schon existiert
    nom = nom .. "|" .. v
    local concat, key = false, ""
    string.gsub(
        nom,
        "([^%|]+)(%|*)",
        function(word, delim)
            if delim == "|" then
                if concat then
                    word = key .. word
                    concat, key = false, ""
                end
                if type(tbl[word]) ~= "table" then
                    tbl[word] = {}
                end -- evtl, entbehrlich
                tbl = tbl[word]
            else
                key = key .. word .. delim
                concat = true
            end
        end
    )
    if key == "" then
        table.insert(tbl, val)
    else
        tbl[key] = val
    end
end -- function valinsert()

function makebox(info)
    local ibox = head
    -- von BOXSORT gesteuert mit  entsprechenden Funktionen verarbeiten
    -- Die Einträge als table komplett übegeben? Retour kommt proc und col
    -- for row in BOXSORT do ibox = ibox .. _G[proc](BOXSORTKEY,col) end
    -- evtl bei jedem Eintrag auf Fehler überprüfen
    return ibox
end

local function writeval(k, v) -- schreibt Wert in k= KEY "Muttereintrag" vl, bei KEY1 nach vr
    local v = "vl"
    local i = string.find(k, "%d", -1)
    if i then
        k = (string.sub(k, 1, i - 1))
        c = "vr"
    end
    info[k][c] = v
end -- function writeval

-- https://yazz.miraheze.org/wiki/Proc:Parameter%C3%BCbergabe_an_Lua_Module#Fehlt_der_Parameterwert_oder_ist_er_leer?

function p.fire(frame)
    info.LEMMA.val = frame.args["seitenname"]
    -- falls NAME= NIL ist wird der Lemmaname übeernommen
    if info.NAME.val == NIL then
        info.NAME.val = info.LEMMA.val
    -- sollte  unter NAME geschrieben wegden, wotd ggf. überschrieben durch para NAME
    end
    _TEST = _TEST .. "\n|-\n| kopfzeile[lemma]|| " .. info.NAME.val or "NIXLEMMANAME"
    local frame = frame:getParent()
    for key, val in pairs(frame.args) do -- Alle Parameter sammeln und Zeilen zuordnen
        key = unique(key) -- Umlaute usw. vereinheitlichen, alles Versalien, dann werden Schreibfehler ausgeglichen
        -- Wert in die Tabelle schreiben
        valinsert(info, key, val)

        _TEST = _TEST .. "\n|-\n| " .. (key or 0) .. " || " .. (val or "NONIX") -- TESTVERSION
    end -- for key
    -- jetzt die Zeilen der Reihenfolge nach (siehe BOXSORT) in die entsprechende Funktion jagen und an 'infobox ' anhängen, letzter Eintrag = '\n|}\n'
    infobox = makebox(info)
    -- evtl. infobox komplett durch frame:preprocess() jagen geht hier nicht!!!
    -- infobox = frame:preprocess(infobox) -- wäre echt gut, aber will nicht
    return _TEST
end -- function p.fire(frame)
----
return p