-- --


local Literatur = { serial = "2022-10-20",
                    selbst = "Vorlage:Literatur",
                    kats   = { ["/"]     = "Wikipedia:Vorlagenfehler",
                               Datum     = { s = "Datum" },
                               Intern    = { s = "/Interner Fehler" },
                               Parameter = { s = "/Parameterfehler" },
                               Temp1     = { s = "/Temp1" },
                               Temp2     = { s = "/Temp2" },
                               Temp3     = { s = "/Temp3" },
                               Temp4     = { s = "/Temp4" },
                             },
                    export = { },
                    fehler = false,
                    schrei = false }
--[=[
Unterstützung für {{Literatur}}
]=]


if mw.site.server:find( ".beta.wmflabs.org", 4, true ) then
    require( "strict" )
end



-- Global
local Zitation



local function fehler( art, anzeige )
    -- Ein Fehler ist aufgetreten
    -- Parameter:
    --     art      -- string mit Schlüsselwort zum Typ
    --     anzeige  -- string mit Einzelheiten, oder nil
    local t
    if not Literatur.fehler then
        Literatur.fehler = { Intern    = { s = "Interner Fehler",
                                           k = "Intern" },
                             Modul     = { s = "Modul-Seite fehlt",
                                           k = "Intern" },
                             Datum     = { s = "Datum",
                                           k = "Datum" },
                             Format    = { s = "Parameterformat" },
                             Konflikt  = { s = "Parameterkonflikt",
                                           k = "Parameter" },
                             Parameter = { s = "Parameterfehler",
                                           k = "Parameter" },
                             Wert      = { s = "Werte ungültig",
                                           k = "Parameter" },
                             Temp1     = { k = "Temp1" },
                             Temp2     = { k = "Temp2" },
                             Temp3     = { k = "Temp3" },
                             Temp4     = { k = "Temp4" }
                           }
    end
    t = Literatur.fehler[ art ]
    if t then
        if t.s  and  not t.e then
            t.e = ""
        end
        if anzeige then
            local s = mw.text.nowiki( anzeige )
            if t.e then
                t.e = string.format( "%s; %s", t.e, s )
            else
                t.e = s
            end
        end
        if t.k then
            local wk = Literatur.kats[ t.k ]
            if wk then
                wk.e = true
            else
                Literatur.fehler.Intern.e = "Wartungskat " .. wk
                Literatur.kats.Intern.e   = true
            end
        end
    else
        Literatur.fehler.Intern.e = string.format( "fehler(%s) %s",
                                                    art,
                                                    anzeige or "???" )
        Literatur.kats.Intern.e   = true
    end
end -- fehler()



local function fehlerliste()
    -- Auflistung aller Fehlermeldungen und Kategorien
    -- Rückgabewert: string mit formatiertem Ergebnis
    local r = ""
    local s
    if Literatur.fehler then
        local sep = ""
        local suffix
        for k, v in pairs( Literatur.fehler  ) do
             if v.e then
                if v.e:sub( 1, 1 ) == ";" then
                    suffix = v.s .. v.e
                elseif v.s then
                    suffix = string.format( "%s: %s", v.s, v.e )
                else
                    suffix = v.e
                end
                Literatur.schrei = string.format( "%s%s*** %s",
                                                  Literatur.schrei or "",
                                                  sep,
                                                  suffix )
                sep    = " "
            end
        end -- for k, v
    end
    for k, v in pairs( Literatur.kats ) do
        if v.e then
            if v.s:sub( 1, 1 ) == "/" then
                s = Literatur.selbst
            else
                s = "Parameter:"
            end
            r = string.format( "%s[[Kategorie:%s/%s%s]]",
                               r,
                               Literatur.kats[ "/" ],
                               s,
                               v.s )
        end
    end -- for k, v
    return r
end -- fehlerliste()



local folder = function ()
    -- Parameter-Konfiguration laden
    local s = string.format( "Module:%s/params", Literatur.selbst )
    local lucky, params = pcall( mw.loadData, s )
    if type( params ) == "table" then
        Literatur.export.params = Literatur.export.flat( params )
    else
        error( string.format( "[[%s]] fehlt", s ) )
    end
end -- folder()



-------------------------------------------------------------------------



Literatur.export.flat = function ( adapt )
    -- Deep copy
    -- Parameter:
    --     adapt  -- something
    -- Returns atomic value, or deep copy of a table with no metatable
    local r
    if type( adapt ) == "table" then
        r = { }
        for k, v in pairs( adapt ) do
            r[ k ] = Literatur.export.flat( v )
        end -- for k, v
    else
        r = adapt
    end
    return r
end -- Literatur.export.flat()



Literatur.export.Datum = function ( args )
    local r = args.Jahr
    local shit
    if r then
        if r:match( "^%d+$" ) then
            local DateTime = Zitation.fetch( "DateTime" )
            local o = DateTime( r )
            if args.Woche and o then
                o.week = tonumber( args.Woche )
                if tostring( o.week ) ~= args.Woche then
                    fehler( "Wert", "'Woche'=" .. args.Woche )
                    r = false
                end
            elseif args.Monat then
                local s
                if mw.title.getCurrentTitle().namespace == 0 then
                    shit = "'Monat=' ist nicht mehr zulässig"
                end
                if args.Monat:match( "%l" ) then
                    local dm = DateTime( args.Monat )
                    if dm and o and dm.month then
                        o.month = dm.month
                    else
                        shit = "'Monat'=" .. args.Monat
                        if args.Nummer then
                            args.Nummer = string.format( "%s, %s",
                                                         args.Nummer,
                                                         args.Monat )
                        else
                            args.Nummer = args.Monat
                        end
                        if not args.Datum then
                            args.Datum = r
                        end
                        r = false
                    end
                else
                    s = args.Monat:match( "^0?(1?%d)%.?$" )
                    if s and o then
                        o.month = tonumber( s )
                    end
                    if o and tostring( o.month ) ~= s then
                        shit = "'Monat'=" .. args.Monat
                        r = false
                    elseif s ~= args.Monat  and
                           "0" .. s ~= args.Monat then
                        shit = "'Monat'=" .. args.Monat
                    end
                end
                if o and o.month and args.Tag then
                    s = args.Tag:match( "^0?([123]?%d)%.?$" )
                    if s then
                        o.dom = tonumber( s )
                    end
                    if tostring( o.dom ) ~= s then
                        shit = "'Tag'=" .. args.Tag
                        r = false
                    elseif s ~= args.Tag  and
                           "0" .. s ~= args.Tag  and
                           s .. "." ~= args.Tag then
                        shit = "'Tag'=" .. args.Tag
                    end
                end
            elseif args.Tag then
                shit = "'Tag' ohne 'Monat'"
                r = false
            end
            if r and o then
                r = o
                args.Datum = o
            end
        elseif r:match( "^%[%[%d%d%d%d%]%]$" ) then
            args.Datum = r:match( "^%[%[(%d+)%]%]$" )
            fehler( "Wert",  "'Jahr' verlinkt" )
        elseif r:match( "^%[%d%d%d%d%]$" ) then
            args.Datum = r:match( "^%[(%d+)%]$" )
            if args.Kommentar then
                args.Kommentar = ", " .. args.Kommentar
            else
                args.Kommentar = ""
            end
            args.Kommentar  = string.format( "o. J. %s%s",
                                             args.Jahr, args.Kommentar )
            fehler( "Wert", "'Datum'=o.J." )
        else
            if args.Datum then
                fehler( "Wert",  "'Jahr'=" .. args.Jahr )
            else
                args.Datum = args.Jahr
            end
        end
    elseif args.Monat or args.Woche or args.Tag then
        fehler( "Konflikt", "'Jahr' fehlt bei spezifischem Datum" )
    else
        r = args.Datum
    end
    if shit then
        fehler( "Datum", shit )
    end
    return r
end -- Literatur.export.Datum()



local Band = function ( args )
    --    OBSOLET   nach Übernahme in Zentralmodul
    if args.Band  and  not args.Sammelwerk then
        if args.Reihe  and  not args.BandReihe then
            args.BandReihe = args.Band
            args.Band      = nil
            fehler( "Parameter", "Band= meint BandReihe=" )
        elseif args.Titel  and
               args.Titel:find( " In: " ) then
            fehler( "Parameter", "Band= ohne Sammelwerk=" )
        end
    end
end -- Band()



local Nummer = function ( args )
    --    OBSOLET   nach Übernahme in Zentralmodul
    if args.Nummer  and  not args.Sammelwerk then
        if args.Reihe  and  not args.NummerReihe then
            args.NummerReihe = args.Nummer
            args.Nummer      = nil
            fehler( "Parameter", "Nummer= meint NummerReihe=" )
        elseif args.Titel  and
               args.Titel:find( " In: " ) then
            fehler( "Wert", "'In:' im Titel" )
        end
    end
end -- Nummer()



local Herausgeber = function ( args )
    --    OBSOLET   nach Übernahme in Zentralmodul
    if args.Autor  and  args.Autor:find( "H", 2 )   and
       args.Autor:find( "[(%[]H", 1 )   and
       ( args.Autor:find( "[(%[]%Hr?s?g?g%.?%[)%]]" )  or
         args.Autor:find( "[(%[]%Herausge?b?e?r?%.?%[)%]]" ) )
       then
        fehler( "Wert",
                "Autor= mit Klammer (Hrsg.); dafür Hrsg= verwenden" )
    end
end -- Herausgeber()



local Online = function ( args )
    --    OBSOLET   nach Übernahme in Zentralmodul
    if args.Online  and  args.ISBN  and
       args.Online:find( "://www.worldcat.org/oclc", 4, true ) then
        args.Online = nil
        args.Abruf  = nil
        fehler( "Konflikt", "ISBN vorhanden; worldcat-URL redundant" )
    end
end -- Online()



local Sprache = function ( args )
    --    OBSOLET   nach Bereinigung im Benutzerbereich
    if args.Originalsprache  and
       not args.Originaltitel  and
       not args["Übersetzer"]  and
       not args.Sprache then
        local t = mw.title.getCurrentTitle()
        if t.namespace == 2  or  t.namespace == 3 then
            args.Sprache         = args.Originalsprache
            args.Originalsprache = nil
            fehler( "Parameter",
                    "Sprache= nutzen statt Originalsprache="
                                                        .. args.Sprache )
            fehler( "Temp1" )
        end
    end
end -- Sprache()



local Zugriff = function ( args )
    --    OBSOLET   nach Bereinigung im Benutzerbereich usw.
    if args.Zugriff then
        local t = mw.title.getCurrentTitle()
        if not args.Abruf then
            args.Abruf   = args.Zugriff
            args.Zugriff = nil
        end
        if t.namespace == 0 then
            fehler( "Parameter",  "Abruf= nutzen statt Zugriff=" )
        end
    end
end -- Zugriff()



local arxiv = function ( args )
    --    OBSOLET   nach Bereinigung im Benutzerbereich usw.
    if args.arxiv then
        local t = mw.title.getCurrentTitle()
        if not args.arXiv then
           if args.arXiv ~= "" then
                args.arXiv = args.arxiv
            end
            args.arxiv = nil
        end
        if t.namespace == 0 then
            fehler( "Parameter",  "arXiv= nutzen statt arxiv=" )
        end
    end
end -- arxiv()



local format = function ( args )
    -- Analysiere Argumente und bilde formatierte Zitation
    -- Parameter:
    --     args    -- table mit Vorlagenparametern
    -- Rückgabewert: string mit formatierter Zitation
    local pars = Zitation.filter( args, Literatur.export.params.valid )
    local r, schrott
    Literatur.export.Datum( pars )
    Herausgeber( pars )
    Band( pars )
    Nummer( pars )
    Sprache( pars )
    Online( pars )
    Zugriff( pars )
    arxiv( pars )
    Zitation.filler( pars, Literatur.export.params.map )
    if Zitation.o then
        Zitation.fill( "leise",  "leiser",   true )
        Zitation.fill( "leise",
                       "Vorlage",
                       pars.Vorlage or Literatur.selbst )
        Zitation.o.coins = true
    end
    r, schrott = Zitation.format()
    if schrott then
        if Literatur.schrei then
            Literatur.schrei = string.format( "%s *** %s",
                                              Literatur.schrei,
                                              schrott )
        else
            Literatur.schrei = schrott
        end
    end
    return r
end -- format()



local function f( arglist, frame )
    -- Hauptfunktion zur Steuerung des Gesamtablaufs
    -- Parameter:
    --     arglist  -- table, mit Vorlagenparametern
    --     frame    -- object, oder nil
    -- Rückgabewert: string mit formatiertem Gesamtergebnis
    --                      einschließlich Fehlerliste und Kategorien
    local lucky, r = pcall( require, "Modul:Zitation" )
    if type( r ) == "table" then
        Zitation       = r.Zitation()
        Zitation.frame = frame
        folder()
        r = string.format( "%s%s%s",
                           format( arglist ),
                           fehlerliste(),
                           Zitation.failure( Literatur.schrei ) )
    else
        fehler( "Modul", r )
        r = fehlerliste()
    end
    return r
end -- f()



-- Literatur.export
local p = {}

function p.export()
    folder()
    return Literatur.export
end

function p.test( a )
    local lucky, r = pcall( f, a )
    return r
end

function p.f( frame )
    local lucky, r = pcall( f, frame:getParent().args, frame )
    if not lucky then
        fehler( "Intern", r )
        r = fehlerliste()
    end
    return r
end

function p.failsafe()
    return Literatur.serial
end

return p