from __future__ import unicode_literals
import locale
import os

from django.utils.translation.trans_real import (get_supported_language_variant,
                                                 parse_accept_lang_header,
                                                 get_language_from_path,
                                                 check_for_language,
                                                 all_locale_paths,
                                                 to_locale,
                                                 _accepted)

# TODO: locale mapper (map locale in url to one of supported locales)
#       this may be convenient to design localized url first (for SEO purposes)
#       and add more locales later

def LocaleSelector(object):
    def __init__(self, check_path=False):
        from django.conf import settings
        self.supported = dict(settings.LANGUAGES)
        self.cookie_name = settings.LANGUAGE_COOKIE_NAME
        self.default_language_code = settings.LANGUAGE_CODE
        self.check_path = check_path
        self.selectors = [self.get_language_from_path,
                          self.get_language_from_session,
                          self.get_language_from_cookie,
                          self.get_language_from_header,
                          self.get_fallback_language] # last one should always return a result

    def get_language_from_path(request):
        if self.check_path:
            lang_code = get_language_from_path(request.path_info, self.supported)
            if lang_code is not None:
                return lang_code

    def get_language_from_session(request):
        if hasattr(request, 'session'):
            lang_code = request.session.get('django_language', None)
            if lang_code in self.supported and lang_code is not None and check_for_language(lang_code):
                return lang_code

    def get_language_from_cookie(request):
        lang_code = request.COOKIES.get(self.cookie_name)
        try:
            return get_supported_language_variant(lang_code, self.supported)
        except LookupError:
            pass

    def get_language_from_header(request):
        global _accepted

        accept = request.META.get('HTTP_ACCEPT_LANGUAGE', '')
        for accept_lang, unused in parse_accept_lang_header(accept):
            if accept_lang == '*':
                break

            # We have a very restricted form for our language files (no encoding
            # specifier, since they all must be UTF-8 and only one possible
            # language each time. So we avoid the overhead of gettext.find() and
            # work out the MO file manually.

            # 'normalized' is the root name of the locale in POSIX format (which is
            # the format used for the directories holding the MO files).
            normalized = locale.locale_alias.get(to_locale(accept_lang, True))
            if not normalized:
                continue
            # Remove the default encoding from locale_alias.
            normalized = normalized.split('.')[0]

            if normalized in _accepted:
                # We've seen this locale before and have an MO file for it, so no
                # need to check again.
                return _accepted[normalized]

            for lang, dirname in ((accept_lang, normalized),
                    (accept_lang.split('-')[0], normalized.split('_')[0])):
                if lang.lower() not in self.supported:
                    continue
                for path in all_locale_paths():
                    if os.path.exists(os.path.join(path, dirname, 'LC_MESSAGES', 'django.mo')):
                        _accepted[normalized] = lang
                        return lang

    def get_fallback_language(_request):
        try:
            return get_supported_language_variant(self.default_language_code, self.supported)
        except LookupError:
            return self.default_language_code

    def select(request):
        for selector in self.selectors:
            lang_code = selector(request)
            if lang_code is not None:
                return lang_code
