"""i18n_subsites plugin creates i18n-ized subsites of the default site"""



import os
import six
import logging
from itertools import chain
from collections import defaultdict, OrderedDict

import gettext

from pelican import signals
from pelican.contents import Page, Article
from pelican.settings import configure_settings

from ._regenerate_context_helpers import regenerate_context_articles



# Global vars
_main_site_generated = False
_main_site_lang = "en"
_main_siteurl = ''
_lang_siteurls = None
logger = logging.getLogger(__name__)



def disable_lang_vars(pelican_obj):
    """Set lang specific url and save_as vars to the non-lang defaults

    e.g. ARTICLE_LANG_URL = ARTICLE_URL
    They would conflict with this plugin otherwise
    """
    global _main_site_lang, _main_siteurl, _lang_siteurls
    s = pelican_obj.settings
    for content in ['ARTICLE', 'PAGE']:
        for meta in ['_URL', '_SAVE_AS']:
            s[content + '_LANG' + meta] = s[content + meta]
    if not _main_site_generated:
        _main_site_lang = s['DEFAULT_LANG']
        _main_siteurl = s['SITEURL']
        _lang_siteurls = [(lang, _main_siteurl + '/' + lang) for lang in s.get('I18N_SUBSITES', {}).keys()]
        # To be able to use url for main site root when SITEURL == '' (e.g. when developing)
        _lang_siteurls = [(_main_site_lang, ('/' if _main_siteurl == '' else _main_siteurl))] + _lang_siteurls
        _lang_siteurls = OrderedDict(_lang_siteurls)
        

    
def create_lang_subsites(pelican_obj):
    """For each language create a subsite using the lang-specific config

    for each generated lang append language subpath to SITEURL and OUTPUT_PATH
    and set DEFAULT_LANG to the language code to change perception of what is translated
    and set DELETE_OUTPUT_DIRECTORY to False to prevent deleting output from previous runs
    Then generate the subsite using a PELICAN_CLASS instance and its run method.
    """
    global _main_site_generated
    if _main_site_generated:      # make sure this is only called once
        return
    else:
        _main_site_generated = True

    orig_settings = pelican_obj.settings
    for lang, overrides in orig_settings.get('I18N_SUBSITES', {}).items():
        settings = orig_settings.copy()
        settings.update(overrides)
        settings['SITEURL'] = _lang_siteurls[lang]
        settings['OUTPUT_PATH'] = os.path.join(orig_settings['OUTPUT_PATH'], lang, '')
        settings['DEFAULT_LANG'] = lang   # to change what is perceived as translations
        settings['DELETE_OUTPUT_DIRECTORY'] = False  # prevent deletion of previous runs
        settings = configure_settings(settings)      # to set LOCALE, etc.

        cls = settings['PELICAN_CLASS']
        if isinstance(cls, six.string_types):
            module, cls_name = cls.rsplit('.', 1)
            module = __import__(module)
            cls = getattr(module, cls_name)

        pelican_obj = cls(settings)
        logger.debug("Generating i18n subsite for lang '{}' using class '{}'".format(lang, str(cls)))
        pelican_obj.run()
    _main_site_generated = False          # for autoreload mode



def move_translations_links(content_object):
    """This function points translations links to the sub-sites

    by prepending their location with the language code
    or directs an original DEFAULT_LANG translation back to top level site
    """
    for translation in content_object.translations:
        if translation.lang == _main_site_lang:
        # cannot prepend, must take to top level
            lang_prepend = '../'
        else:
            lang_prepend = translation.lang + '/'
        translation.override_url =  lang_prepend + translation.url



def update_generator_contents(generator, *args):
    """Update the contents lists of a generator

    Empty the (hidden_)translation attribute of article and pages generators
    to prevent generating the translations as they will be generated in the lang sub-site
    and point the content translations links to the sub-sites

    Hide content without a translation for current DEFAULT_LANG
    if HIDE_UNTRANSLATED_CONTENT is True
    """
    generator.translations = []
    is_pages_gen = hasattr(generator, 'pages')
    if is_pages_gen:
        generator.hidden_translations = []
        for page in chain(generator.pages, generator.hidden_pages):
            move_translations_links(page)
    else:                                    # is an article generator
        for article in chain(generator.articles, generator.drafts):
            move_translations_links(article)

    if not generator.settings.get('HIDE_UNTRANSLATED_CONTENT', True):
        return
    contents = generator.pages if is_pages_gen else generator.articles
    hidden_contents = generator.hidden_pages if is_pages_gen else generator.drafts
    default_lang = generator.settings['DEFAULT_LANG']
    for content_object in contents[:]:   # loop over copy for removing
        if content_object.lang != default_lang:
            if isinstance(content_object, Article):
                content_object.status = 'draft'
            elif isinstance(content_object, Page):
                content_object.status = 'hidden'
            contents.remove(content_object)
            hidden_contents.append(content_object)
    if not is_pages_gen: # regenerate categories, tags, etc. for articles
        if hasattr(generator, '_generate_context_aggregate'):                  # if implemented
            # Simulate __init__ for fields that need it
            generator.dates = {}
            generator.tags = defaultdict(list)
            generator.categories = defaultdict(list)
            generator.authors = defaultdict(list)
            generator._generate_context_aggregate()
        else:                             # fallback for Pelican 3.3.0
            regenerate_context_articles(generator)



def install_templates_translations(generator):
    """Install gettext translations for current DEFAULT_LANG in the jinja2.Environment

    if the 'jinja2.ext.i18n' jinja2 extension is enabled
    adds some useful variables into the template context
    """
    generator.context['main_siteurl'] = _main_siteurl
    generator.context['main_lang'] = _main_site_lang
    generator.context['lang_siteurls'] = _lang_siteurls
    current_def_lang = generator.settings['DEFAULT_LANG']
    extra_siteurls = _lang_siteurls.copy()
    extra_siteurls.pop(current_def_lang)
    generator.context['extra_siteurls'] = extra_siteurls
    
    if 'jinja2.ext.i18n' not in generator.settings['JINJA_EXTENSIONS']:
        return
    domain = generator.settings.get('I18N_GETTEXT_DOMAIN', 'messages')
    localedir = generator.settings.get('I18N_GETTEXT_LOCALEDIR')
    if localedir is None:
        localedir = os.path.join(generator.theme, 'translations')
    if current_def_lang == generator.settings.get('I18N_TEMPLATES_LANG', _main_site_lang):
        translations = gettext.NullTranslations()
    else:
        languages = [current_def_lang]
        try:
            translations = gettext.translation(domain, localedir, languages)
        except (IOError, OSError):
            logger.error("Cannot find translations for language '{}' in '{}' with domain '{}'. Installing NullTranslations.".format(languages[0], localedir, domain))
            translations = gettext.NullTranslations()
    newstyle = generator.settings.get('I18N_GETTEXT_NEWSTYLE', True)
    generator.env.install_gettext_translations(translations, newstyle)    



def register():
    signals.initialized.connect(disable_lang_vars)
    signals.generator_init.connect(install_templates_translations)
    signals.article_generator_finalized.connect(update_generator_contents)
    signals.page_generator_finalized.connect(update_generator_contents)
    signals.finalized.connect(create_lang_subsites)