\ProvidesPackage{mqtranslation}
\RequirePackage{mqfqname}
\RequirePackage{etoolbox}
\RequirePackage{amsmath}
\RequirePackage{mqlua}

% TODO resolve circular dependency with fqname

\begin{luacode}
    translations = translations or {} 
    -- string to append to missing translations, for debugging
    -- unknownTranslation = "???"
    -- unknownTranslation = "!UT!"
    unknownTranslation = ""
    -- language that is set in usepackage[<lang>]{babel}
    language = "\languagename"
    fallbackLanguage = "english"
    -- using additional extension because vimtex wouldnt stop compiling otherwise
    translationsFilepath = OUTDIR .. "/translations.lua.txt" or "/tmp/translations.lua.txt"

    function tlAdd(language, key, value)
        if value == "" then 
            return
        end
        if translations[language] == nil then
            translations[language] = {}
        end
        translations[language][key] = value
    end


    function tlExists(language, key)
        return not (translations[language] == nil or translations[language][key] == nil)
    end

    function tlExistsFallback(language, key)
        if tlExists(language, key) then
            return true
        end
        return tlExists(fallbackLanguage, key)
    end


    function tlGet(language, key)
        if tlExists(language, key) then
            return translations[language][key]
        end
        return string.sanitize(key .. unknownTranslation)
    end

    function tlGetFallback(language, key)
        if tlExists(language, key) then
            return translations[language][key]
        end
        if language ~= fallbackLanguage then
            if tlExists(fallbackLanguage, key) then
                return translations[fallbackLanguage][key]
            end
        end
        return string.sanitize(key .. unknownTranslation)
    end

    function tlGetCurrent(key)
        return tlGet(language, key)
    end

    function tlGetFallbackCurrent(key)
        return tlGetFallback(language, key)
    end

\end{luacode}

% Write the translations table as lua code to an auxiliary file
% If the file exists, read it when loading the package.
% This way, translations may be used before they are defined, since it will exist in the second compilation.
\begin{luacode*}
    function serialize(tbl)
        local result = {}
        for k, v in pairs(tbl) do
        local key = type(k) == "string" and ("[\"%s\"]"):format(k) or "[" .. tostring(k) .. "]"
            -- using level 2 multiline string to avoid problems when a string ends with ]
            local value = type(v) == "table" and serialize(v) or "[==[" .. tostring(v) .. "]==]"
            table.insert(result, key .. " = " .. value)
        end
        return "{" .. table.concat(result, ",\n" ) .. "}\n"
    end


    function dumpTable(tableobj, filepath)
        local file = io.open(filepath, "w")
        file:write("return " .. serialize(tableobj) .. "\n")
        file:close()
    end

    if fileExists(translationsFilepath) then
        translations = dofile(translationsFilepath) or {}
    end
\end{luacode*}
        

\AtEndDocument{\directlua{dumpTable(translations, translationsFilepath)}}

%
% TRANSLATION COMMANDS
%
% The lower case commands use \fqname based keys, the upper case absolute keys.
% Example:
%   \dt[example]{german}{Beispiel}  % defines the key \fqname:example
%   \ger[example]{Beispiel}         % defines the key \fqname:example
%   \DT[example]{german}{Beispiel}  % defines the key example
%   \Ger[example]{Beispiel}         % defines the key example
%
% For ease of use in the ttext environment and the optional argument of the \Part, \Section, ... commands,
% all "define translation" commands use \fqname as default key

% Get a translation
% expandafter required because the translation commands dont expand anything
% shortcuts for translations
% 1: key
\newcommand{\gt}[1]{\luavar{tlGetFallbackCurrent(\luastring{\fqname:#1})}}
\newrobustcmd{\robustGT}[1]{\luavar{tlGetFallbackCurrent(translateRelativeFqname(\luastring{#1}))}}
\newcommand{\GT}[1]{\luavar{tlGetFallbackCurrent(translateRelativeFqname(\luastring{#1}))}}

% text variants for use in math mode
\newcommand{\tgt}[1]{\text{\gt{#1}}}
\newcommand{\tGT}[1]{\text{\GT{#1}}}

% Define a new translation
% [1]: key, 2: lang, 3: translation
\newcommand{\dt}[3][\fqname]{%
    \directlua{
        if \luastring{#1} == \luastring{\fqname} then
            tlAdd(\luastring{#2}, \luastring{\fqname}, \luastringN{#3})
        else
            tlAdd(\luastring{#2}, \luastring{\fqname:#1}, \luastringN{#3})
        end
    }
}

% Define a new translation
% [1]: key, 2: lang, 3: translation
\newcommand{\DT}[3][\fqname]{%
    \directlua{
        if \luastring{#1} == \luastring{\fqname} then
            tlAdd(\luastring{#2}, \luastring{\fqname}, \luastringN{#3})
        else
            tlAdd(\luastring{#2}, \luastring{#1}, \luastringN{#3})
        end
    }
}
% [1]: key, 2: translation
\newcommand{\ger}[2][\fqname]{\dt[#1]{german}{#2}}
\newcommand{\eng}[2][\fqname]{\dt[#1]{english}{#2}}

\newcommand{\Ger}[2][\fqname]{\DT[#1]{german}{#2}}
\newcommand{\Eng}[2][\fqname]{\DT[#1]{english}{#2}}

\newcommand{\IfTranslationExists}[3]{%
    \directlua{
        if tlExistsFallback(language, \luastring{#1}) then
            tex.sprint(\luastringN{#2})
        else
            tex.sprint(\luastringN{#3})
        end
    }
}


% use this to define text in different languages for the key <env arg>
% the translation for <env arg> is printed when the environment ends.
% (temporarily change fqname to the \fqname:<env arg> to allow
% the use of \eng and \ger without the key parameter)
% [1]: key
\newenvironment{ttext}[1][desc]{%
    \mqfqname@enter{#1}%
}{%
    \GT{\fqname}%
    \mqfqname@leave%
}
