# Created By: Virgil Dupras
# Created On: 2010-06-23
# Copyright 2015 Hardcoded Software (http://www.hardcoded.net)
#
# This software is licensed under the "GPLv3" License as described in the "LICENSE" file,
# which should be included with this package. The terms are also available at
# http://www.gnu.org/licenses/gpl-3.0.html

# Doing i18n with GNU gettext for the core text gets complicated, so what I do is that I make the
# GUI layer responsible for supplying a tr() function.

import locale
import logging
import os
import os.path as op
from typing import Callable, Union

from hscommon.plat import ISLINUX

_trfunc = None
_trget = None
installed_lang = None


def tr(s: str, context: Union[str, None] = None) -> str:
    if _trfunc is None:
        return s
    else:
        if context:
            return _trfunc(s, context)
        else:
            return _trfunc(s)


def trget(domain: str) -> Callable[[str], str]:
    # Returns a tr() function for the specified domain.
    if _trget is None:
        return lambda s: tr(s, domain)
    else:
        return _trget(domain)


def set_tr(
    new_tr: Callable[[str, Union[str, None]], str], new_trget: Union[Callable[[str], Callable[[str], str]], None] = None
) -> None:
    global _trfunc, _trget
    _trfunc = new_tr
    if new_trget is not None:
        _trget = new_trget


def get_locale_name(lang: str) -> Union[str, None]:
    # Removed old conversion code as windows seems to support these
    LANG2LOCALENAME = {
        "cs": "cs_CZ",
        "de": "de_DE",
        "el": "el_GR",
        "en": "en",
        "es": "es_ES",
        "fr": "fr_FR",
        "hy": "hy_AM",
        "it": "it_IT",
        "ja": "ja_JP",
        "ko": "ko_KR",
        "ms": "ms_MY",
        "nl": "nl_NL",
        "pl_PL": "pl_PL",
        "pt_BR": "pt_BR",
        "ru": "ru_RU",
        "tr": "tr_TR",
        "uk": "uk_UA",
        "vi": "vi_VN",
        "zh_CN": "zh_CN",
    }
    if lang not in LANG2LOCALENAME:
        return None
    result = LANG2LOCALENAME[lang]
    if ISLINUX:
        result += ".UTF-8"
    return result


# --- Qt
def install_qt_trans(lang: str = None) -> None:
    from PyQt5.QtCore import QCoreApplication, QTranslator, QLocale

    if not lang:
        lang = str(QLocale.system().name())[:2]
    localename = get_locale_name(lang)
    if localename is not None:
        try:
            locale.setlocale(locale.LC_ALL, localename)
        except locale.Error:
            logging.warning("Couldn't set locale %s", localename)
    else:
        lang = "en"
    qtr1 = QTranslator(QCoreApplication.instance())
    qtr1.load(":/qt_%s" % lang)
    QCoreApplication.installTranslator(qtr1)
    qtr2 = QTranslator(QCoreApplication.instance())
    qtr2.load(":/%s" % lang)
    QCoreApplication.installTranslator(qtr2)

    def qt_tr(s: str, context: Union[str, None] = "core") -> str:
        if context is None:
            context = "core"
        return str(QCoreApplication.translate(context, s, None))

    set_tr(qt_tr)


# --- gettext
def install_gettext_trans(base_folder: os.PathLike, lang: str) -> None:
    import gettext

    def gettext_trget(domain: str) -> Callable[[str], str]:
        if not lang:
            return lambda s: s
        try:
            return gettext.translation(domain, localedir=base_folder, languages=[lang]).gettext
        except OSError:
            return lambda s: s

    default_gettext = gettext_trget("core")

    def gettext_tr(s: str, context: Union[str, None] = None) -> str:
        if not context:
            return default_gettext(s)
        else:
            trfunc = gettext_trget(context)
            return trfunc(s)

    set_tr(gettext_tr, gettext_trget)
    global installed_lang
    installed_lang = lang


def install_gettext_trans_under_qt(base_folder: os.PathLike, lang: str = None) -> None:
    # So, we install the gettext locale, great, but we also should try to install qt_*.qm if
    # available so that strings that are inside Qt itself over which I have no control are in the
    # right language.
    from PyQt5.QtCore import QCoreApplication, QTranslator, QLocale, QLibraryInfo

    if not lang:
        lang = str(QLocale.system().name())[:2]
    localename = get_locale_name(lang)
    if localename is None:
        lang = "en"
        localename = get_locale_name(lang)
    try:
        locale.setlocale(locale.LC_ALL, localename)
    except locale.Error:
        logging.warning("Couldn't set locale %s", localename)
    qmname = "qt_%s" % lang
    if ISLINUX:
        # Under linux, a full Qt installation is already available in the system, we didn't bundle
        # up the qm files in our package, so we have to load translations from the system.
        qmpath = op.join(QLibraryInfo.location(QLibraryInfo.TranslationsPath), qmname)
    else:
        qmpath = op.join(base_folder, qmname)
    qtr = QTranslator(QCoreApplication.instance())
    qtr.load(qmpath)
    QCoreApplication.installTranslator(qtr)
    install_gettext_trans(base_folder, lang)
