# -*- coding: utf-8 -*-
"""
    jinja.plugin
    ~~~~~~~~~~~~

    Support for the `GeneralTemplateInterface`__ and the Buffet interface.

    Do not use this module on your own. We don't recommend those interfaces!
    If you are able to, you should really use Jinja without those abstraction
    layers.

    __ http://trac.pocoo.org/wiki/GeneralTemplateInterface

    :copyright: 2007 by Armin Ronacher.
    :license: BSD, see LICENSE for more details.
"""
from warnings import warn
from jinja.environment import Environment
from jinja.loaders import FunctionLoader, FileSystemLoader, PackageLoader
from jinja.exceptions import TemplateNotFound


class BuffetPlugin(object):
    """
    Implements the Jinja buffet plugin. Well. It works for pylons and should
    work for TurboGears too if their plugin system would work.
    """

    def __init__(self, extra_vars_func=None, options=None):
        if 'jinja.environment' in options:
            self.env = options['jinja.environment']
        else:
            opt = {}
            for key, value in options.iteritems():
                if key.startswith('jinja.') and key != 'jinja.extension':
                    opt[key[6:]] = value
            loader_func = opt.pop('loader_func', None)
            getmtime_func = opt.pop('getmtime_func', None)
            use_memcache = opt.pop('use_memcache', False)
            memcache_size = opt.pop('memcache_size', 40)
            cache_folder = opt.pop('cache_folder', None)
            auto_reload = opt.pop('auto_reload', True)
            if 'searchpath' in opt:
                opt['loader'] = FileSystemLoader(opt.pop('searchpath'),
                                                 use_memcache, memcache_size,
                                                 cache_folder, auto_reload)
            elif 'package' in opt:
                opt['loader'] = PackageLoader(opt.pop('package'),
                                              opt.pop('package_path', ''),
                                              use_memcache, memcache_size,
                                              cache_folder, auto_reload)
            elif loader_func is not None:
                opt['loader'] = FunctionLoader(loader_func, getmtime_func,
                                               use_memcache, memcache_size,
                                               cache_folder, auto_reload)
            self.env = Environment(**opt)

        self.extra_vars_func = extra_vars_func
        self.extension = options.pop('jinja.extension', 'html')

    def load_template(self, templatename, template_string=None):
        if template_string is not None:
            return self.env.from_string(template_string)
        if templatename.startswith('!'):
            jinja_name = templatename[1:]
        else:
            jinja_name = templatename.replace('.', '/') + '.' + self.extension
        return self.env.get_template(jinja_name)

    def render(self, info, format='html', fragment=False, template=None):
        if isinstance(template, basestring):
            template = self.load_template(template)
        if self.extra_vars_func:
            info.update(self.extra_vars_func())
        return template.render(info)


def jinja_plugin_factory(options):
    """
    Basic implementation of the `GeneralTemplateInterface`.

    Supports ``loader_func`` and ``getmtime_func``, as well as
    string and file loading but ignores ``mode`` since it's a
    text based template engine.

    All options passed to this function are forwarded to the
    jinja environment. Exceptions are the following keys:

    =================== =================================================
    ``environment``     If this is provided it must be the only
                        configuration value and it's used as jinja
                        environment.
    ``searchpath``      If provided a new file system loader with this
                        search path is instanciated.
    ``package``         Name of the python package containing the
                        templates. If this and ``package_path`` is
                        defined a `PackageLoader` is used.
    ``package_path``    Path to the templates inside of a package.
    ``loader_func``     Function that takes the name of the template to
                        load. If it returns a string or unicode object
                        it's used to load a template. If the return
                        value is None it's considered missing.
    ``getmtime_func``   Function used to check if templates requires
                        reloading. Has to return the UNIX timestamp of
                        the last template change or 0 if this template
                        does not exist or requires updates at any cost.
    ``use_memcache``    Set this to ``True`` to enable memory caching.
                        This is usually a good idea in production mode,
                        but disable it during development since it won't
                        reload template changes automatically.
                        This only works in persistent environments like
                        FastCGI.
    ``memcache_size``   Number of template instance you want to cache.
                        Defaults to ``40``.
    ``cache_folder``    Set this to an existing directory to enable
                        caching of templates on the file system. Note
                        that this only affects templates transformed
                        into python code. Default is ``None`` which means
                        that caching is disabled.
    ``auto_reload``     Set this to `False` for a slightly better
                        performance. In that case of `getmtime_func`
                        not being provided this won't have an effect.
    =================== =================================================
    """
    warn(DeprecationWarning('general plugin interface implementation '
                            'deprecated because not an accepted '
                            'standard.'))

    if 'environment' in options:
        env = options['environment']
        if not len(options) == 1:
            raise TypeError('if environment provided no other '
                            'arguments are allowed')
    else:
        loader_func = options.pop('loader_func', None)
        getmtime_func = options.pop('getmtime_func', None)
        use_memcache = options.pop('use_memcache', False)
        memcache_size = options.pop('memcache_size', 40)
        cache_folder = options.pop('cache_folder', None)
        auto_reload = options.pop('auto_reload', True)
        if 'searchpath' in options:
            options['loader'] = FileSystemLoader(options.pop('searchpath'),
                                                 use_memcache, memcache_size,
                                                 cache_folder, auto_reload)
        elif 'package' in options:
            options['loader'] = PackageLoader(options.pop('package'),
                                              options.pop('package_path', ''),
                                              use_memcache, memcache_size,
                                              cache_folder, auto_reload)
        elif loader_func is not None:
            options['loader'] = FunctionLoader(loader_func, getmtime_func,
                                               use_memcache, memcache_size,
                                               cache_folder, auto_reload)
        env = Environment(**options)

    def render_function(template, values, options):
        if options.get('is_string'):
            tmpl = env.from_string(template)
        else:
            try:
                tmpl = env.get_template(template)
            except TemplateNotFound:
                return
        return tmpl.render(**values)

    return render_function
