-- --


--[=[ 2015-11-22
Unterstützung für {{Patent}}
]=]


-- Global
local Selbst = "Vorlage:Patent"
local KategorieBeginn  =  "Kategorie:Wikipedia:Vorlagenfehler/" .. Selbst
local Kategorien       =
     { Intern       =  { s = "/Interner Fehler" },
       Parameter    =  { s = "/Parameterfehler" },
       TypCode      =  { s = "Vorlagenfehler/"..Selbst.."/Typ und Code",
                         x = true },       
       Datum        =  { s = "Vorlagenfehler/"..Selbst.."/Parameter:Datumsformat",
                         x = true },
       KeinLink     =  { s = "Vorlagenfehler/"..Selbst.."/Ohne Verknüpfung",
                         x = true }
     }
local Fehler   = false
local Frame    = false
local Resultat
local Zitation

local Parameter = [==[
|A-Datum
|Anmelder
|Code
|DB
|Erfinder
|KeinLink
|Kommentar
|Land
|Online
|Titel
|Typ
|V-Datum
|V-Nr
]==]

local function fault( a )
    -- Formatiere Fehler mit class=error
    -- Parameter:
    --     a  -- string mit Text
    return string.format( "<span class=\"error\">%s</span>", a )
end -- fault()
 
 
 
local function fehler( art, anzeige )
    -- Ein Fehler ist aufgetreten
    -- Parameter:
    --     art      -- string mit Schlüsselwort zum Typ
    --     anzeige  -- string mit Einzelheiten
    local t
    if not Fehler then
    	Fehler = { Intern    = { s = "Interner Fehler",
                                 k = "Intern" },
                   Modul     = { s = "Modul-Seite fehlt",
                                 k = "Intern" },
                   Vorlage   = { s = "Vorlagen-Seite fehlt",
                                 k = "Intern" },
                   Konflikt  = { s = "Parameterkonflikt",
                                 k = "Parameter" },
                   Parameter = { s = "Parameterfehler",
                                 k = "Parameter" },
                   Pflicht   = { s = "Pflichtparameter fehlt",
                                 k = "Parameter" },
                   Wert      = { s = "Werte ungültig",
                                 k = "Parameter" },
                   Doppelt   = { s = "Mehrfache Angabe von Parametern",
                                 k = "Parameter" }
                 }
    end
    t = Fehler[ art ]
    if t then
       
        if t.e then
            t.e  =  string.format( "%s; %s", t.e, anzeige )
        elseif anzeige then
            t.e  =  anzeige
        else
            t.e  =  ""
        end
        if t.k then
            local wk  =  Kategorien[ t.k ]
            if wk then
                wk.e  =  true
            else
                Fehler.Intern.e      =  string.format( "Wartungskat %s", wk )
                Kategorien.Intern.e  =  true
            end
        end
    else
        Fehler.Intern.e      =  string.format( "fehler(%s) %s", art, anzeige )
        Kategorien.Intern.e  =  true
    end
end -- fehler()
 
 
 
local function fehlerliste()
    -- Auflistung aller Fehlermeldungen
    -- Rückgabewert: string mit formatiertem Ergebnis
    local r = ""
    local sep = ""
    if Fehler then
        for k, v in pairs( Fehler ) do
             if v.e then
                r = string.format( "%s%s*** %s: %s", r, sep, v.s or "", v.e)
                sep = " "
            end
        end -- for k, v
        r = "<br />" .. fault( r )
    end
    return r
end -- fehlerliste()
 
 
 
local function fire( art )
    -- Melde Kategorie an
    -- Parameter:
    --     art  -- string mit Schlagwort zum Typ
    local t = Kategorien[ art ]
    if t then
        t.e  =  true
    else
        fehler( "Intern",  "Kategorie:" .. art )
    end
end -- fire()
 
 
 
local function firelist()
    -- Auflistung aller gemeldeten Kategorien
    -- Returns: string mit allen Kategorien
    local r  =  ""
    local s
    for k, v in pairs( Kategorien ) do
        if v.e then
            if v.x then
                s  =  "Kategorie:Wikipedia:"
            else
                s  =  KategorieBeginn
            end
            r = string.format( "%s[[%s%s]]", r, s, v.s )
        end
    end -- for k, v
    return r
end -- firelist()



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

local function urlencode( a )
    if not Frame then
        Frame = mw.getCurrentFrame()
    end
    return Frame:callParserFunction( "urlencode", a )
end -- urlencode()



local function addzeros( a, c)
	local r = a or ""
	for i = string.len(a), c-1, 1 do
		r = "0" .. r
	end
    return r
end -- urlencode()



local function formatdate( a , param, sonderformat)
    -- Analysiere Datumszeichenkette und gib sie formatiert zurück
    -- Parameter:
    --     a            -- Datumsangabe
    --     param        -- Name des Datumsparameters oder leer
    --     formatstring -- ggf. erzwungendes Ausgabeformat; nil >> Standardformat
    -- Rückgabewerte:
    --     1  -- string mit formatiertem Code
    --     2  -- true wenn valide
    local DateTime = Zitation.fetch( "DateTime" )
    local r
    local o = DateTime( a )
    local valid = true
    local ausgabeformat = sonderformat or "T._Monat JJJJ"
 
    param = param or ""
 
    if o then
        -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
        -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --    	
    	-- ToDo: Benutzereinstellungen übernehmen
        -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
        -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
        r = o:format( ausgabeformat, { lang = "de"})

        -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
        -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --    	
    	-- Prüfung: Datum liegt in der Zukunft
    	-- Prüfung: Datum liegt vor 1800
        -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
        -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 
        if o:format( "Ymd", { lang = "de"}) > os.date('%Y%m%d')  then
        	fehler( "Wert", "'"..param.."'")
        	valid = false
        elseif tonumber(o:format( "Y", { lang = "de"})) < 1800  then
        	fehler( "Wert", "'"..param.."'")
        	valid = false        	
        end
    else
        r = a  -- nowrap( a ) ?
        fehler( "Wert", "'"..param.."'")
        fire( "Datum" )
        valid = false
    end
    return r or "", valid
end -- formatdate()



local function Werktitel( a, abschluss )
    -- Formatiere einen Werktitel, das Sammelwerk, ggf. Reihe
    -- Parameter:
    --     a          -- string
    --     abschluss  -- true: Satzendezeichen sicherstellen
    -- Rückgabewert: string mit formatiertem Werktitel
    local Text = Zitation.fetch( "Text" )
    local sep = ""
    if abschluss then
        if not Text.sentenceTerminated( a ) then
            sep = "."
        end
    end

    return string.format( "<cite style=\"font-style:italic\">%s%s</cite>",
                          Text.uprightNonlatin( a ),
                          sep)
end -- Werktitel()


local GetDBURL = function (args)
	local r
	
	if not args.KeinLink then
		if args.Land and args["V-Nr"] then
			if args.DB == "DEPATIS" then 
				r = "http://depatisnet.dpma.de/DepatisNet/depatisnet?action=bibdat&docid=" .. args.Land .. addzeros(args["V-Nr"], 12) .. (args.Code or "A")
			elseif args.DB == "USPTO" then 
				r = "http://patft.uspto.gov/netacgi/nph-Parser?TERM1=" .. args["V-Nr"] .. "&Sect1=PTO1&Sect2=HITOFF&d=PALL&p=1&u=%2Fnetahtml%2FPTO%2Fsrchnum.htm&r=0&f=S&l=50"
			elseif args.DB == "WIPO" then 
				r = "http://patentscope.wipo.int/search/de/detail.jsf?docId=" .. args.Land .. args["V-Nr"]
				--r = "http://www.wipo.int/pctdb/en/wo.jsp?" .. args.Land .. "=" .. args["V-Nr"]
			elseif args.DB == "Google" then 
				r =	"http://www.google.com/patents/" .. args.Land .. args["V-Nr"] .. (args.Code or "")
			else
				r = "http://worldwide.espacenet.com/publicationDetails/biblio?locale=de_EP&CC=" .. args.Land .. "&NR=" .. args["V-Nr"]
				if args.Code then
					r = r .. "&FT=D&KC=" .. args.Code
				end
				if args.DB and (args.DB:lower() ~= "espacenet") then
					fehler( "Wert", "Datenbank " .. args.DB .. " wird nicht unterstützt und durch espacenet.com ersetzt." )
				end
			end
		end
	else
		if not args.KeinLink:lower() == "ja" then
			fehler( "Wert", "'KeinLink'" )	
		end
		fire( "KeinLink" )	
	end
	return r
end -- GetDBURL ()



local Land = function ( args )
    local r = args.Land
    if r then
    	if string.len(r) ~= 2 then
        	fehler( "Wert", "'Land' besteht immer aus zwei Großbuchstaben" )
       	end
    else
    	fehler( "Pflicht", "'Land'")	
    end
    return r
end -- Land()



local Nummer = function ( args )
    local r = args["V-Nr"]
	if not r then
    	fehler( "Pflicht", "'V-Nr'")	
    elseif not r:match( "^[D]?%d+$" ) then
		fehler( "Wert", "'V-Nr'" )	
	end 
	if args.Land == "WO" then
		if string.len(r) == 10 then
			local jahrnr = r:gsub("^([12]%d%d%d)(%d+)$","%1")
			local jahr, valid = formatdate(args["V-Datum"],"Veröffentlichungsdatum","Y")
			if args["V-Datum"] and jahr and jahrnr then
	       		if jahrnr ~= jahr then
					fehler( "Wert", "'Veröffentlichungsdatum' passt nicht zu 'V-Nr'.")
				end
			end
			r = r:gsub("^([12]%d%d%d)(%d+)$","%1/%2")
		end
	end
    return r
end -- Nummer()



local Schriftart = function ( args )
    local r = ""
    local code = args.Code or ""
    
    -- ToDo: Vollständige Implementation
    -- Verinfachte Klassifizierung in 3-4 Typen
	if args.Land == "US" and (args.Code == "S" or args["V-Nr"]:match( "^[D][%d%.]+$") ) then
		r = "Geschmacksmuster"
    -- US 1836–2000 1–ca. 6 167 568 A Patentschrift
	elseif args.Land == "US" and (args.Code == "A") then
		r = "Patentschrift"
    elseif code:match( "^A%d?" ) then
    	r = "Patentanmeldung" -- aka Offenlegungsschrift
    elseif code:match( "^U%d?" ) or code:match( "^Y%d?" ) or code:match( "^I%d?" ) then
    	r = "Gebrauchsmuster"
    elseif code ~="" then
    	r = "Patentschrift"
    end
    
    -- AT A5 Recherchebericht
    -- CA 1948–1989 ab 445931 A Patent
    

    -- Patent, Patentanmeldung, Gebrauchsmuster // Alte Implementation
    if r and args.Typ then
    	--fehler( "Doppelt", "'Typ' redundant zu 'Land' & 'Code'")
    	fire( "TypCode" )	
    elseif args.Typ then
    	r = args.Typ
    	if (r ~= "Patent" and r ~= "Patentanmeldung" and r ~= "Gebrauchsmuster") then
        	fehler( "Wert", "'Typ' zurzeit nur 'Patent', 'Patentanmeldung' oder 'Gebrauchsmuster'" )
        	r = "Patent"
        end
    end
    
    if r=="" then
    	r = "Patent"	
    end
    
    return r
end -- Typ()



local Erfinder = function ( args )
    local r = args.Erfinder or args.Erfinderin
    if r then
        if  args.Erfinder and args.Erfinderin then
            fehler( "Doppel", "'Erfinder' und 'Erfinderin'" )
        end
    end
    return r
end -- Erfinder()



local function Kommentarklammer( args )
    -- Inhalt der Klammer am Ende der bibliografischen Angaben.
    -- Parameter:
    --     args  -- table mit neutralem Datenkatalog
    -- Rückgabewert: string mit Inhalt, oder false
    local r   = ""
    local sep = ""
 
    if args.Kommentar then
        r = string.format( "%s%s%s", r, sep, args.Kommentar )
        sep = "; "
    end
    if r == "" then
        r = false
    end
    return r
end -- Kommentarklammer()



local format = function ( args )
    -- Analysiere Argumente und bilde formatierte Zitation
    -- Parameter:
    --     args  -- table mit Vorlagenparametern
    -- Rückgabewert: string mit formatierter Zitation
    local r
    local url, id, sep, s
    
    local z = { }
    local pars, schrott = Zitation.filter( args, Parameter )
    if schrott then
        fehler( "Parameter", schrott )
    end
    -- Typische Eingabeformate "tolerieren"
    pars["V-Nr"] = pars["V-Nr"]:gsub( "(%d),(%d)", "%1%2" ):gsub( "(%d)%/(%d)", "%1%2" )
    
    if args.Land == "US" and (args.Code == "S" or args["V-Nr"]:match( "^[D]%d+$") ) then
    	pars.DB = "USPTO" --"Google"
    end

    r = ""
    url = GetDBURL(pars)
    if pars["Code"] then
    	id = string.format( "%s&#160;%s&#160;%s", Land(pars), Nummer(pars), pars["Code"])
    else
    	pars["Code"] = ""
    	id = string.format( "%s&#160;%s", Land(pars), Nummer(pars))
    end
    
    if url then
    	r = string.format( "%s&nbsp;[%s %s]", Schriftart(pars), url, id)
	else
    	r = string.format( "%s&nbsp;%s", Schriftart(pars), id)
    end
	sep = ": "
    
	if pars.Titel then
		r = string.format( "%s%s%s", r, sep, Werktitel(pars.Titel,true) )
        sep = " "			
	end
	
    if pars["A-Datum"] then
       	if sep ~= ", " then
       		-- Großschreibung nach Satzzeichen außer Komma
       		r = string.format( "%s%sAngemeldet am <span style='white-space:nowrap'>%s</span>", r, sep,  formatdate(pars["A-Datum"],"Anmeldedatum") )
       	else
       		r = string.format( "%s%sangemeldet am <span style='white-space:nowrap'>%s</span>", r, sep,  formatdate(pars["A-Datum"],"Anmeldedatum") )
       	end
       	
       	if pars["V-Datum"] then
       		if formatdate(pars["A-Datum"],"Anmeldedatum","Ymd") > formatdate(pars["V-Datum"],"Veröffentlichungsdatum","Ymd") then
       			fehler( "Wert", "'Anmeldedatum' nach 'Veröffentlichungsdatum'" )
   			end
       	end
        sep = ", "
    end   	
    if pars["V-Datum"] then
       	if sep ~= ", " then
       		-- Großschreibung nach Satzzeichen außer Komma
       		r = string.format( "%s%sVeröffentlicht am <span style='white-space:nowrap'>%s</span>", r, sep,  formatdate(pars["V-Datum"],"Veröffentlichungsdatum") )
       	else
       		r = string.format( "%s%sveröffentlicht am <span style='white-space:nowrap'>%s</span>", r, sep,  formatdate(pars["V-Datum"],"Veröffentlichungsdatum") )
       	end
        sep = ", "
    end   	

    if pars["Anmelder"] then
        r = string.format( "%s%sAnmelder: %s", r, sep, pars["Anmelder"] )
        sep = ", "
    end   	
    if pars["Erfinder"] then
        r = string.format( "%s%sErfinder: %s", r, sep, pars["Erfinder"] )
        sep = ", "
    end   
    
    s = Kommentarklammer( pars )
    if s then
    	-- Entferne falsch gesetzten Punkt am Ende des Titels oder des Werks (Korrekturfunktion eigentlich nicht benötigt)
    	-- Resultat = Resultat:gsub( "cite%>%.$", "cite>" ):gsub("cite%>%.%]$", "cite>]" )
 
        -- Korrektur von Doppelklammern, stattdessen beide Klammerinhalte zusammenführen und mit Semikolon trennen
        if r:find( "%)%.*$" ) then
        	r = r:gsub( "(.*)%)[%s%.]*$", "%1" )
            sep = "; "
        else
            sep = " ("
        end
        r =string.format( "%s%s%s", r, sep, s .. ")" )
        sep = "."
    end
    
	if r then
		if (not (r:match( "%.$" ) or r:match( ".</cite>$") )) and (sep ~= "") then
        	r = r .. "."
        end
    	r = '<span class="cite">'..r..'</span>'
    end
    
    if schrott then
        fehler( "Wert", schrott )
    end
    return r
end -- format()



local function f( arglist, arrest )
    -- Hauptfunktion zur Steuerung des Gesamtablaufs
    -- Parameter:
    --     arglist  -- table mit Vorlagenparametern
    --     arrest   -- true: Reduziertes Ergebnis zur Substitution
    -- 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()
        r        = format( arglist, arrest )
    else
        fehler( "Modul", r )
    end
    return  string.format( "%s%s%s", r, fehlerliste(), firelist() )
end -- f()


-- Export
local p = {}

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

function p.f( frame )
    local frameP = frame:getParent()
    local lean   = ( frameP:getTitle() ~= Selbst )
    local lucky, params, r
    if lean then    -- subst:
        params = frame.args
    else
        params = frameP.args
    end
    lucky, r = pcall( f, params, lean )
    return r
end

return p