# -*- coding: utf-8 -*-
# Copyright 2011 amanwa32 AUTHORS.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""
amanwa32_extras.mako
===================

Mako template support for amanwa32.

Learn more about Mako: http://www.makotemplates.org/
"""
import importlib

import six
import amanwa32


lookup = importlib.import_module('mako.lookup')

#: Default configuration values for this module. Keys are:
#:
#: template_path
#:     Directory for templates. Default is `templates`.
default_config = {
    'template_path': 'templates',
}


class Mako(object):
    """Wrapper for configurable and cached Mako environment.

    To used it, set it as a cached property in a base `RequestHandler`::

        import amanwa32

        from amanwa32_extras import mako

        class BaseHandler(amanwa32.RequestHandler):

            @amanwa32.cached_property
            def mako(self):
                # Returns a Mako renderer cached in the app registry.
                return mako.get_mako(app=self.app)

            def render_response(self, _template, **context):
                # Renders a template and writes the result to the response.
                rv = self.mako.render_template(_template, **context)
                self.response.write(rv)

    Then extended handlers can render templates directly::

        class MyHandler(BaseHandler):
            def get(self):
                context = {'message': 'Hello, world!'}
                self.render_response('my_template.html', **context)
    """

    #: Configuration key.
    config_key = __name__

    #: Loaded configuration.
    config = None

    def __init__(self, app, config=None):
        self.config = config = app.config.load_config(
            self.config_key,
            default_values=default_config,
            user_values=config,
            required_keys=None
        )

        directories = config.get('template_path')
        if isinstance(directories, six.string_types):
            directories = [directories]

        self.environment = lookup.TemplateLookup(directories=directories,
                                                 output_encoding='utf-8',
                                                 encoding_errors='replace')

    def render_template(self, _filename, **context):
        """Renders a template and returns a response object.

        :param _filename:
            The template filename, related to the templates directory.
        :param context:
            Keyword arguments used as variables in the rendered template.
            These will override values set in the request context.
        :returns:
            A rendered template.
        """
        template = self.environment.get_template(_filename)
        return template.render_unicode(**context)


# Factories -------------------------------------------------------------------


#: Key used to store :class:`Mako` in the app registry.
_registry_key = 'amanwa32_extras.mako.Mako'


def get_mako(factory=Mako, key=_registry_key, app=None):
    """Returns an instance of :class:`Mako` from the app registry.

    It'll try to get it from the current app registry, and if it is not
    registered it'll be instantiated and registered. A second call to this
    function will return the same instance.

    :param factory:
        The callable used to build and register the instance if it is not yet
        registered. The default is the class :class:`Mako` itself.
    :param key:
        The key used to store the instance in the registry. A default is used
        if it is not set.
    :param app:
        A :class:`amanwa32.WSGIApplication` instance used to store the instance.
        The active app is used if it is not set.
    """
    app = app or amanwa32.get_app()
    mako = app.registry.get(key)
    if not mako:
        mako = app.registry[key] = factory(app)

    return mako


def set_mako(mako, key=_registry_key, app=None):
    """Sets an instance of :class:`Mako` in the app registry.

    :param store:
        An instance of :class:`Mako`.
    :param key:
        The key used to retrieve the instance from the registry. A default
        is used if it is not set.
    :param request:
        A :class:`amanwa32.WSGIApplication` instance used to retrieve the
        instance. The active app is used if it is not set.
    """
    app = app or amanwa32.get_app()
    app.registry[key] = mako
