class Manager(object):

    def __init__(self, *args, **kwargs):
        super(Manager, self).__init__(*args, **kwargs)

        self.tors = {}

    def store_to_db(self, pofile, locale, store_translations=False):
        language = get_lang_from_dirname(locale)
        domain = os.path.splitext(os.path.basename(pofile))[0]
        messages = polib.pofile(pofile)
        translations = TranslationEntry.objects.filter(language=language)

        tdict = {}
        for t in translations:
            if t.original not in tdict:
                tdict.update({t.original: {}})
            tdict[t.original][t.language] = t.translation

        for m in messages:
            occs = []
            for occ in m.occurrences:
                path = ":".join(occ)
                occs.append(path)

            if store_translations:
                translation = m.msgstr
            else:
                translation = ""

            locale_path = get_relative_locale_path(pofile)

            if os.path.split(pofile)[-1] == 'angularjs.po':
                locale_dir_name = ''
            else:
                locale_dir_name = get_locale_parent_dirname(pofile)
            t, created = TranslationEntry.objects.get_or_create(
                original=m.msgid,
                language=language,
                locale_path=locale_path,
                domain=domain,
                defaults={
                    "occurrences": "\n".join(occs),
                    "translation": translation,
                    "locale_parent_dir": locale_dir_name,
                    "is_published": True,
                }
            )

            if locale_path not in self.tors:
                self.tors[locale_path] = {}
            if language not in self.tors[locale_path]:
                self.tors[locale_path][language] = {}
            if domain not in self.tors[locale_path][language]:
                self.tors[locale_path][language][domain] = []
            self.tors[locale_path][language][domain].append(t.original)

    ############################################################################

    def backup_po_to_db(self):
        """ Backup Po file to db model """

        for lang, lang_name in settings.LANGUAGES:
            for path in settings.LOCALE_PATHS:
                po_pattern = os.path.join(path, get_dirname_from_lang(lang), "LC_MESSAGES", "*.po")
                for pofile in glob(po_pattern):
                    logger.debug("Backuping file {} to db".format(pofile))

                    domain = os.path.splitext(os.path.basename(pofile))[0]
                    with codecs.open(pofile, 'r', 'utf-8') as pofile_opened:
                        content = pofile_opened.read()
                        backup = TranslationBackup(
                            language=lang,
                            locale_path=get_relative_locale_path(pofile),
                            domain=domain,
                            locale_parent_dir=get_locale_parent_dirname(pofile),
                            content=content,
                        )
                        backup.save()

                    if get_settings('TRANSLATIONS_CLEAN_PO_AFTER_BACKUP'):
                        with open(pofile, 'w') as pofile_opened:
                            pofile_opened.write('')

    ############################################################################

    def update_po_from_db(self, lang):

        translations = TranslationEntry.objects.filter(
            language=lang,
            is_published=True
        ).exclude(
            translation=""
        ).order_by("original")

        locale_params = TranslationEntry.objects.filter(is_published=True).order_by('locale_path', 'domain')

        forced_locale_paths = get_settings('TRANSLATIONS_UPDATE_FORCED_LOCALE_PATHS')
        if forced_locale_paths:
            translations = translations.filter(locale_path__in=forced_locale_paths)
            locale_params = locale_params.filter(locale_path__in=forced_locale_paths)

        locale_params = locale_params.values_list('locale_path', 'domain')
        locale_params = list(set(locale_params))

        for locale_path, domain in locale_params:
            lang_dir_path = os.path.abspath(
                os.path.join(get_settings('TRANSLATIONS_BASE_DIR'), locale_path, get_dirname_from_lang(lang)))
            if not os.path.isdir(lang_dir_path):
                os.mkdir(lang_dir_path)
                os.mkdir(os.path.join(lang_dir_path, 'LC_MESSAGES'))

            pofile_path = os.path.join(get_settings('TRANSLATIONS_BASE_DIR'), locale_path, get_dirname_from_lang(lang),
                                       'LC_MESSAGES',
                                               "%s.po" % domain)
            mofile_path = os.path.join(get_settings('TRANSLATIONS_BASE_DIR'), locale_path, get_dirname_from_lang(lang),
                                       'LC_MESSAGES',
                                               "%s.mo" % domain)

            if not os.path.exists(pofile_path):
                logger.debug("Po file '{}' does't exists, it will be created".format(pofile_path))

            now = datetime.now()
            pofile = polib.POFile()
            pofile.metadata = {
                'Project-Id-Version': '0.1',
                'Report-Msgid-Bugs-To': '%s' % settings.DEFAULT_FROM_EMAIL,
                'POT-Creation-Date': now.strftime("%Y-%m-%d %H:%M:%S"),
                'PO-Revision-Date': now.strftime("%Y-%m-%d %H:%M:%S"),
                'Last-Translator': 'Server <%s>' % settings.SERVER_EMAIL,
                'Language-Team': 'English <%s>' % settings.DEFAULT_FROM_EMAIL,
                'MIME-Version': '1.0',
                'Content-Type': 'text/plain; charset=utf-8',
                'Content-Transfer-Encoding': '8bit',
            }

            for translation in translations.filter(locale_path=locale_path, domain=domain):
                entry = polib.POEntry(
                    msgid=translation.original,
                    msgstr=translation.translation,
                    occurrences=[occ.split(":") for occ in translation.occurrences.split()]
                )
                pofile.append(entry)

            pofile.save(pofile_path)
            pofile.save_as_mofile(mofile_path)

    ############################################################################

    def postprocess(self):
        TranslationEntry.objects.all().update(is_published=False)
        for locale_path, languages in self.tors.items():
            TranslationEntry.objects.filter(locale_path=locale_path).update(is_published=False)
            for language, domains in languages.items():
                for domain, tors in domains.items():
                    tors = list(set(tors))
                    TranslationEntry.objects.filter(
                        locale_path=locale_path,
                        language=language,
                        domain=domain,
                        original__in=tors
                    ).update(is_published=True)

        if get_settings('TRANSLATIONS_MODE') == TRANSLATIONS_MODE_PROMISCUOUS:
            published = TranslationEntry.objects.filter(is_published=True).order_by("original", 'language', 'locale_path')
            for trans in published:
                if VERSION[:2] in [(1, 2), (1, 3)]:
                    locale_paths = [os.path.relpath(path, get_settings('TRANSLATIONS_BASE_DIR')) for path in settings.LOCALE_PATHS]
                else:
                    locale_paths = self.tors.keys()

                for locale_path in locale_paths:
                    locale_parent_dir = get_locale_parent_dirname(
                        os.path.join(
                            get_settings('TRANSLATIONS_BASE_DIR'),
                            locale_path,
                            get_dirname_from_lang(trans.language),
                            'LC_MESSAGES',
                            "django.po"
                        )
                    )

                    t, created = TranslationEntry.objects.get_or_create(
                        original=trans.original,
                        language=trans.language,
                        locale_path=locale_path,
                        domain=trans.domain,
                        defaults={
                            "occurrences": trans.occurrences,
                            "translation": trans.translation,
                            "locale_parent_dir": locale_parent_dir,
                            "is_published": True,
                        }
                    )
            TranslationEntry.objects.filter(original__in=published.values_list('original', flat=True)).update(is_published=True)

    ############################################################################

    def load_data_from_po(self):
        import os

        for lang, lang_name in settings.LANGUAGES:
            for path in settings.LOCALE_PATHS:
                locale = get_dirname_from_lang(lang)
                po_pattern = os.path.join(path, locale, "LC_MESSAGES", "*.po")
                for pofile in glob(po_pattern):
                    logger.debug("Processing pofile {}".format(pofile))
                    self.store_to_db(pofile=pofile, locale=locale, store_translations=True)

        self.postprocess() class TranslationEntry(models.Model):
    created = models.DateTimeField(auto_now_add=True, verbose_name=_(u"admin-translation_entry-created-label"))
    changed = models.DateTimeField(auto_now=True, verbose_name=_(u"admin-translation_entry-changed-label"))
    language = models.CharField(db_index=True, max_length=7, verbose_name=_(u"admin-translation_entry-language-label"))
    original = models.TextField(verbose_name=_(u"admin-translation_entry-original-label"))
    translation = models.TextField(blank=True, verbose_name=_(u"admin-translation_entry-translation-label"))
    occurrences = models.TextField(blank=True, verbose_name=_(u"admin-translation_entry-occurrences-label"))
    is_published = models.BooleanField(default=True, editable=False, verbose_name=_(u"admin-translation_entry-is_published-label"))
    locale_path = models.CharField(db_index=True, max_length=256, verbose_name=_(u"admin-translation_entry-locale_path-label"))
    locale_parent_dir = models.CharField(db_index=True, max_length=256, verbose_name=_(u"admin-translation_entry-locale_parent_dir-label"))
    domain = models.CharField(db_index=True, max_length=256, verbose_name=_(u"admin-translation_entry-domain-label"))

    #remote_translation_entry = models.OneToOneField(RemoteTranslationEntry, null=True, on_delete=models.SET_NULL, verbose_name=_(''))

    class Meta:
        verbose_name = cf(_(u"admin-translation_entry-singular"))
        verbose_name_plural = cf(_(u"admin-translation_entry-plural"))
        ordering = ('original',)
        permissions = (
            ('load', _('admin-translation_entry-load-from-po')),
        )

    def __unicode__(self):
        return "(%s:%s:%s:%s)" % (self.pk, self.original[:64], self.language, self.locale_path)

    def __str__(self):
        return "(%s:%s:%s:%s)" % (self.pk, self.original[:64], self.language, self.locale_path)

    def get_hint(self):
        self.hint = ""

        if not self.hint:
            if hasattr(self, '_hint'):
                self.hint = self._hint
            else:
                try:
                    self.hint = self._meta.model.objects.get(domain=self.domain, locale_path=self.locale_path, original=self.original, language=get_settings('TRANSLATIONS_HINT_LANGUAGE')).translation
                except self._meta.model.DoesNotExist:
                    pass

        return self.hint
    get_hint.short_description = cf(_("admin-translation_entry-hint-label")) class TranslationBackup(models.Model):
    created = models.DateTimeField(auto_now_add=True, verbose_name=_(u"admin-translation_backup-created-label"))
    changed = models.DateTimeField(auto_now=True, verbose_name=_(u"admin-translation_backup-changed-label"))
    language = models.CharField(db_index=True, max_length=5, verbose_name=_(u"admin-translation_backup-language-label"))
    locale_path = models.CharField(db_index=True, max_length=256, verbose_name=_(u"admin-translation_backup-locale_path-label"))
    locale_parent_dir = models.CharField(db_index=True, max_length=256, verbose_name=_(u"admin-translation_backup-locale_parent_dir-label"))
    domain = models.CharField(db_index=True, max_length=256, verbose_name=_(u"admin-translation_backup-domain-label"))

    content = models.TextField(verbose_name=_(u"admin-translation_backup-content"))

    class Meta:
        verbose_name = cf(_(u"admin-translation_backup-singular"))
        verbose_name_plural = cf(_(u"admin-translation_backup-plural"))
        ordering = ('-created',)

    def restore(self):
        po_filename = os.path.join(self.locale_path, self.language, 'LC_MESSAGES',
                                   self.domain + '.mo')

        mo_filename = os.path.join(self.locale_path, self.language, 'LC_MESSAGES',
                                   self.domain + '.mo')

        with open(po_filename, 'wb') as output:
            output.write(self.content.encode('utf-8'))

        po = polib.pofile(po_filename)
        po.save_as_mofile(mo_filename)

    def __unicode__(self):
        return "(%s:%s:%s)" % (self.pk, self.language, self.locale_path)

    def __str__(self):
        return "(%s:%s:%s)" % (self.pk, self.language, self.locale_path) class RemoteTranslationEntry(models.Model):
    translation = models.TextField(blank=True, verbose_name=_(u"admin-remote_translation_entry-remote_translation-label"))
    changed = models.DateTimeField(auto_now=True, verbose_name=_(u"admin-remote_translation_entry-changed-label"))

    translation_entry = models.OneToOneField(TranslationEntry, related_name='remote_translation_entry', on_delete=models.PROTECT)

    class Meta:
        permissions = (
            ('sync', _('admin-translation_entry-sync')),
        ) class ProxyTranslationEntry(TranslationEntry):

    class Meta:
        proxy = True def add_styles(widget, styles):
    """ Helper function - adds CSS styles to widget

    """
    attrs = widget.attrs or {}
    if 'style' in attrs:
        attrs['style'] = '%s %s' % (attrs['style'], styles)
    else:
        attrs['style'] = styles
    widget.attrs = attrs def filter_queryset(qs, options):
    qs = qs.filter(is_published=True)
    if options:
        filter_ = options[0]
        q = Q(original__contains=filter_)
        for filter_ in options[1:]:
            q = q | Q(original__contains=filter_)
        qs = qs.filter(q)
    return qs def get_settings(setting):
    """
    Looks for settings in django settings or in translation_manager.defaults
    """
    return getattr(settings, setting, getattr(defaults, setting)) def makemessages_task():
def makemessages_task():
import logging
import requests
from functools import update_wrapper
from django.contrib import admin
    from django.core.urlresolvers import reverse
    from django.urls import reverse
from django.db.models import F
from django.http import HttpResponseRedirect, JsonResponse
from django.http.response import HttpResponseBadRequest
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext_lazy as _
from django.conf import settings
from rest_framework.status import is_success
from .manager import Manager
from .models import TranslationEntry, TranslationBackup, RemoteTranslationEntry, ProxyTranslationEntry
from .signals import post_save
from .widgets import add_styles
from .utils import filter_queryset
from .settings import get_settings
from translation_manager import tasks
from django.core.cache import cache
    from .filters import TranslationStateFilter, CustomFilter
        from django.conf.urls import url
        from .views import TranslationChangeList
        self.message_user(request, _("admin-translation_manager-translations_made"))
        return HttpResponseRedirect(reverse("admin:translation_manager_translationentry_changelist"))

    def compile_translations_view(self, request):
        manager = Manager()
        for language, language_name in settings.LANGUAGES:
            manager.update_po_from_db(lang=language)
        post_save.send(sender=None, request=request)

        self.message_user(request, _("admin-translation_manager-translations_compiled"))
        return HttpResponseRedirect(reverse("admin:translation_manager_translationentry_changelist"))

    def get_changelist(self, request, **kwargs):

        return TranslationChangeList

    def sync_translations(self, request):
        if not request.user.has_perm('translation_manager.sync'):
            return HttpResponseRedirect(reverse("admin:translation_manager_translationentry_changelist"))

        url = '{}?token={}'.format(
            get_settings('TRANSLATIONS_SYNC_REMOTE_URL'),
            get_settings('TRANSLATIONS_SYNC_REMOTE_TOKEN'),
        )

        remote_user = get_settings('TRANSLATIONS_SYNC_REMOTE_USER')
        remote_password = get_settings('TRANSLATIONS_SYNC_REMOTE_PASSWORD')

        if remote_user is not None and remote_password is not None:
            response = requests.get(url, verify=get_settings('TRANSLATIONS_SYNC_VERIFY_SSL'), auth=(remote_user, remote_password))
        else:
            response = requests.get(url, verify=get_settings('TRANSLATIONS_SYNC_VERIFY_SSL'))

        if not is_success(response.status_code):
            return HttpResponseBadRequest('Wrong response from remote TRM URL')

        data = response.json()

        RemoteTranslationEntry.objects.all().delete()

        for language, domains in data.items():
            for domain, translation_entries in domains.items():
                for original, translation_entry in translation_entries.items():
                    try:
                        main_entry = TranslationEntry.objects.get(language=language, original=original, domain=domain)
                    except TranslationEntry.DoesNotExist as e:
                        logger.debug('Missing: {} {} {}'.format(language, original, domain))
                        continue

                    RemoteTranslationEntry.objects.create(
                        translation=translation_entry['translation'],
                        changed=translation_entry['changed'],
                        translation_entry=main_entry
                    )

        return HttpResponseRedirect(reverse('admin:translation_manager_proxytranslationentry_changelist'))


class ProxyTranslationEntryAdmin(TranslationEntryAdmin):

    fields = ['original', 'language', 'get_hint', 'changed', 'translation', 'use_remote','remote_translation', 'remote_changed', 'domain']
    list_display = fields

    change_list_template = "admin/translation_manager/remote_change_list.html"

    def remote_translation(self, obj):
        """
        :param obj:
        :type obj: TranslationEntry
        :return:
        """
        return obj.remote_translation_entry.translation

    def remote_changed(self, obj):
        """
        :param obj:
        :type obj: TranslationEntry
        :return:
        """
        return obj.remote_translation_entry.changed

    def get_queryset(self, request):
        qs = super(ProxyTranslationEntryAdmin, self).get_queryset(request=request)
        return qs.exclude(remote_translation_entry=None).exclude(translation=F('remote_translation_entry__translation'))

    def use_remote(self, obj):
        """
        :param obj:
        :type obj: TranslationEntry
        :return:
        """

        if obj.remote_translation_entry:
            return mark_safe('<input type="button" data-id="{id}" class="btn btn-info btn-use-remote" value="{name}"/><xmp id="{id}" style="display: none">{remote_translation_value}</xmp>'.format(
                name=_("admin-translation_manager-use_remote-value"),
                remote_translation_value=obj.remote_translation_entry.translation,
                id=obj.pk
            ))

        return '-'


def restore(modeladmin, request, queryset):
    for backup in queryset:
        backup.restore()
restore.short_description = _("admin-translation_manager-backups_restore_option")


class TranslationBackupAdmin(admin.ModelAdmin):
    actions_on_bottom = True
    actions = [restore]
    save_on_top = True
    fields = ('created', 'language', 'locale_parent_dir', 'domain', 'content')
    list_display = ('created', 'language', 'locale_parent_dir', 'domain')
    list_filter = ('created', 'language', 'locale_parent_dir', 'domain')
    readonly_fields = ('created', 'language', 'locale_parent_dir', 'domain')


admin.site.register(TranslationEntry, TranslationEntryAdmin)
admin.site.register(TranslationBackup, TranslationBackupAdmin)

admin.site.register(ProxyTranslationEntry, ProxyTranslationEntryAdmin)