-- Erzeugt eine Sortierung von Lemmata
-- sortiert dabei Großbuchstaben als Kleinbuchstaben, ß als ss und Diakritika als diakritikalose Zeichen
-- Beispiel: arger, Arger, ärger, Ärger
-- [[Modul:Sortierung/testcases]]

local m = {}
local from = "àáâãäåāăąȁȃḃçćĉċčďđḋḍèéêëēĕėęěẽȅȇḟĝğġģĥħḣḥìíîïĩīĭįıȉȋĵķḳĺļľŀłḷ"
local frto = "aaaaaaaaaaabcccccddddeeeeeeeeeeeefgggghhhhiiiiiiiiiiijkkllllll"
from = from .. "ṁṃñńņňṅòóôõöøōŏőȍȏṗŕŗřȑȓṙṛśŝşšșṡṣţťŧṫṭùúûüũūŭůűųȕȗṿŵýÿŷȳỹźżžß"
frto = frto .. "mmnnnnnoooooooooooprrrrrrrssssssstttttuuuuuuuuuuuuvwyyyyyzzzs"


function m.sort(frame)
  
  return doSort(frame.args[1],frame.args[2],false)

end

function m.sorts(frame)
  
  return doSort(frame.args[1],frame.args[2],true)

end


-- sortiere String nach Buchstaben
function m.sortKeyAnagramm(frame)
  
  return SortKeyAnagramm(frame.args[1])

end


-- Bilde Kategorie Anagramm sortiert nach Buchstaben
-- args[1] Sprache
-- args[2] pagename
function m.KategorieAnagrammSortiert(frame)
  local ska = SortKeyAnagramm(frame.args[2])
  if ska ~= nil and mw.ustring.sub( ska, 1, 1 ) ~= " " then
   return "[[Kategorie:Anagramm sortiert (" .. frame.args[1] .. ")|" .. ska .. "]]"
  else
   return ""
  end
end


function m.sorttab(frame)

  local p2, pg, pli, pre, pdt, pdr
  local retstr

  if frame.args[1] == "Ü-Tabelle" then
    for name, value in pairs(frame.args) do
      if     name == 2           then p2 = value
      elseif name == "G"         then pg = value
      elseif name == "Ü-links"   then pli = value
      elseif name == "Ü-rechts"  then pre = value
      elseif name == "Dialekttabelle" then pdt = value
      elseif name == "D-rechts"  then pdr = value
      elseif name ~= 1 then
        return '<strong class="error">Fehler: Modul:Sortierung.sorttab unbekannter Parameter „'
               .. name .. '“</strong>'
      end
    end
  end

  pli = frame:preprocess(pli)
  pre = frame:preprocess(pre)

  if frame.args[1] then return mw.text.nowiki(pli) end

  retstr = "{{Ü-Tabelle"

  if p2 then
    retstr = retstr .. "|" .. p2
  end
  if pg then
    retstr = retstr .. "|G=" .. pg
  end

  retstr = retstr .. sortUeTab(pli,pre)

  if pdt then
    retstr = retstr .. "\n|Dialekttabelle=\n" .. pdt
  end
  if pdr then
    retstr = retstr .. "\n|D-rechts=\n" .. pdr
  end

  return retstr .. "\n}}\n"

end


function sortUeTab(pli,pre)

  local str = pli .. "\n".. pre
  local w, walt = "", ""
  local wsort = ""
  local ar = {}
  local idx = 0

  for w in ( str ):gmatch("([^\n]+)") do
    wsort = mw.ustring.gsub(w,"^%*%[%[[^|%]]*|","*[[") -- links anpassen *[[text1|text2]] -> *[[text2]]
    wsort = mw.ustring.gsub(wsort,"^%*%[%[","*") -- links anpassen *[[text]] -> *text]]
    wsort = mw.ustring.gsub(wsort,"%]%]"," ]]") -- links anpassen *text]] -> *text ]]

    if mw.ustring.find(w,"^%*%*") then
      wsort = walt .. " %Z% " .. wsort
    else
      walt = wsort
    end
    w = wsort .. " !!! " .. w  -- der text !!! sollte in der tabelle nicht vorkommen
    table.insert(ar, w)
    idx = idx + 1
  end

  table.sort(ar)

  local outstr = "|Ü-links=\n"
  local spl = {}
  local label = true

  for i,w in ipairs(ar) do

      spl = mw.text.split( w, " !!! " , true )
      if table.getn(spl) > 1 then
        w = spl[2]
      else
        w = spl[1]
      end

      if label and i > math.floor( 1 + idx / 2 ) and not mw.ustring.find(w,"^%*%*") then
        outstr = outstr .. "|Ü-rechts=\n"
        label = false
      end
      outstr = outstr .. w .. "\n"

  end

  if label then
    outstr = outstr .. "|Ü-rechts=\n"
  end
  return outstr

end


-- Entfernt führende und abschließende Whitespaces
-- Entfernt Diakritika z.B.: "äöü" -> "aou"
-- Erzeugt aus "Ärger" -> "arger ärger äRGER" + FF + "Ärger"
-- zuerst kleinschreibung zur Gruppierung diakritischer Zeichen
-- dann kleingeschriebene Diakritika zur Gruppierung ebensolcher
-- dann Reihenfolge für Klein/Großbuchstaben
-- dann Formfeed + Originalinput, um diesen nach dem Sort rekonstuieren zu können

function toSortOrder(w)

  local n

  local w_trim = mw.ustring.gsub(w,"^%s*","")
  w_trim = mw.ustring.gsub(w_trim,"%s*$","")

  w,n = mw.ustring.gsub(w_trim,"ß","ßß")
  w,n = mw.ustring.gsub(w,"ẞ","ẞẞ")

  local strlow = mw.ustring.lower(w)
  local strswap = ""
  local idx = 0
  local cp = 0
  local newcp = 0
  local newstr = ""
  local swapcase = false
  local wcp = 0
  local wclow = ""
  local wcupp = ""

  local i = 1
  for cp in mw.ustring.gcodepoint(strlow) do
    newcp = cp
    if cp > 122 then
      for idx = 1, mw.ustring.len( from ) do
        if (cp == mw.ustring.codepoint( from, idx)) then
          newcp = mw.ustring.codepoint( frto, idx)
        end
      end
    end

    newstr = newstr .. mw.ustring.char(newcp)

    wcp = mw.ustring.codepoint(w,i)
    wclow = mw.ustring.lower(mw.ustring.char(wcp))
    wcupp = mw.ustring.upper(mw.ustring.char(wcp))
  
    swapcase = wcupp < wclow
    if swapcase then
      if wcp ~= cp then
        strswap = strswap .. wclow
      else
        strswap = strswap .. wcupp
      end
    else
      strswap = strswap .. mw.ustring.char(wcp)
    end
    i = i + 1
  end

  return newstr .. " " .. strlow .. " " .. strswap .. "\f" .. w_trim

end


function doSort(zeichen,str,subst)

  local i, n, idx = 0
  local w = ""
  local cp, newcp = 0
  local newstr = ""

  str,n = mw.ustring.gsub(str,"%*%s*%[%[","")
  str,n = mw.ustring.gsub(str,"%[%[","")
  str,n = mw.ustring.gsub(str,"%]%]","")

  if mw.ustring.len( str ) == 0 then
    return "-"
  end

  local ar = {}

  for w in (";" .. str .. ";"):gmatch("([^;,\n]+)%s*") do
    w = toSortOrder(w)
    table.insert(ar, w)
  end

  table.sort(ar)

  local outstr = ""
  local sep1, sep2, sep3 = ""

  if zeichen == "," then
    sep1 = "[["
    sep2 = "]]"
    sep3 = ", "
  else if zeichen == "*" then
    sep1 = "*[["
    sep2 = "]]"
    sep3 = "\n"
  else
    sep1 = "* [["
    sep2 = "]]"
    sep3 = "\n"
  end
  end

  if not subst then
    sep1 = sep1 .. "<span>"
    sep2 = "</span>" .. sep2
  end

  local walt = ""    -- doppelte Elemente entfernen
  local orgstr = false

  for i,w in ipairs(ar) do
    newstr = ""
    orgstr = false

    for cp in mw.ustring.gcodepoint(w) do
      if orgstr then
        newstr = newstr .. mw.ustring.char(cp)
      else
        orgstr = mw.ustring.char(cp) == "\f"
      end
    end

    if newstr ~= walt then
      outstr = outstr .. sep1 .. newstr .. sep2
      sep1 = sep3 .. sep1
      sep3 = ""
    end
    walt = newstr
  end

  if subst then
    return outstr
  end
  return "<pre>" .. outstr .. "</pre>"

end


function SortKeyAnagramm(w)

  local w_trim = mw.ustring.gsub(w,"^%s*","")
  w_trim = mw.ustring.gsub(w_trim,"%s*$","")

  local strlow = mw.ustring.lower(w_trim)

  local ar = {}
  local chr = ""
  local cp = 0
  local newstr = ""
  local i = 1

  for cp in mw.ustring.gcodepoint(strlow) do
    table.insert(ar, mw.ustring.char(cp))
  end

  table.sort(ar)

  for i,chr in ipairs(ar) do
    newstr = newstr .. chr
  end

-- das kleine ß durch ein großes ersetzen, damit später
-- nicht durch die Mediawiki-sortkey-Generierung ß durch 'SS' ersetzt wird
  newstr = mw.ustring.gsub(newstr,"ß","ẞ")

-- Die Zeichen * ; # : erzeugen ein \n im Returnwert, wenn sie als erstes Zeichen zurückgegeben werden
-- also in diesen Fällen ein Leerzeichen voranstellen (jetzt gelöst durch Funktion KategorieAnagrammSortiert)

--   chr = mw.ustring.char(mw.ustring.codepoint(newstr,1,1))

--   if chr == "*" or chr == ";" or chr == "#" or chr == ":" then
--     newstr = ' ' .. newstr
--   end
  return newstr

end


return m