from pyramid.interfaces import ILocaleNegotiator, ITranslationDirectories

from pyramid.exceptions import ConfigurationError
from pyramid.path import AssetResolver

from pyramid.config.actions import action_method


class I18NConfiguratorMixin(object):
    @action_method
    def set_locale_negotiator(self, negotiator):
        """
        Set the :term:`locale negotiator` for this application.  The
        :term:`locale negotiator` is a callable which accepts a
        :term:`request` object and which returns a :term:`locale
        name`.  The ``negotiator`` argument should be the locale
        negotiator implementation or a :term:`dotted Python name`
        which refers to such an implementation.

        Later calls to this method override earlier calls; there can
        be only one locale negotiator active at a time within an
        application.  See :ref:`activating_translation` for more
        information.

        .. note::

           Using the ``locale_negotiator`` argument to the
           :class:`pyramid.config.Configurator` constructor can be used to
           achieve the same purpose.
        """

        def register():
            self._set_locale_negotiator(negotiator)

        intr = self.introspectable(
            'locale negotiator',
            None,
            self.object_description(negotiator),
            'locale negotiator',
        )
        intr['negotiator'] = negotiator
        self.action(ILocaleNegotiator, register, introspectables=(intr,))

    def _set_locale_negotiator(self, negotiator):
        locale_negotiator = self.maybe_dotted(negotiator)
        self.registry.registerUtility(locale_negotiator, ILocaleNegotiator)

    @action_method
    def add_translation_dirs(self, *specs, **kw):
        """ Add one or more :term:`translation directory` paths to the
        current configuration state.  The ``specs`` argument is a
        sequence that may contain absolute directory paths
        (e.g. ``/usr/share/locale``) or :term:`asset specification`
        names naming a directory path (e.g. ``some.package:locale``)
        or a combination of the two.

        Example:

        .. code-block:: python

           config.add_translation_dirs('/usr/share/locale',
                                       'some.package:locale')

        The translation directories are defined as a list in which
        translations defined later have precedence over translations defined
        earlier.

        By default, consecutive calls to ``add_translation_dirs`` will add
        directories to the start of the list. This means later calls to
        ``add_translation_dirs`` will have their translations trumped by
        earlier calls. If you explicitly need this call to trump an earlier
        call then you may set ``override`` to ``True``.

        If multiple specs are provided in a single call to
        ``add_translation_dirs``, the directories will be inserted in the
        order they're provided (earlier items are trumped by later items).

        .. versionchanged:: 1.8

           The ``override`` parameter was added to allow a later call
           to ``add_translation_dirs`` to override an earlier call, inserting
           folders at the beginning of the translation directory list.

        """
        introspectables = []
        override = kw.pop('override', False)
        if kw:
            raise TypeError('invalid keyword arguments: %s', sorted(kw.keys()))

        def register():
            directories = []
            resolver = AssetResolver(self.package_name)

            # defer spec resolution until register to allow for asset
            # overrides to take place in an earlier config phase
            for spec in specs:
                # the trailing slash helps match asset overrides for folders
                if not spec.endswith('/'):
                    spec += '/'
                asset = resolver.resolve(spec)
                directory = asset.abspath()
                if not asset.isdir():
                    raise ConfigurationError(
                        '"%s" is not a directory' % directory
                    )
                intr = self.introspectable(
                    'translation directories',
                    directory,
                    spec,
                    'translation directory',
                )
                intr['directory'] = directory
                intr['spec'] = spec
                introspectables.append(intr)
                directories.append(directory)

            tdirs = self.registry.queryUtility(ITranslationDirectories)
            if tdirs is None:
                tdirs = []
                self.registry.registerUtility(tdirs, ITranslationDirectories)
            if override:
                tdirs.extend(directories)
            else:
                for directory in reversed(directories):
                    tdirs.insert(0, directory)

        self.action(None, register, introspectables=introspectables)
