# runtime.py
# Copyright (C) 2006, 2007, 2008 Michael Bayer mike_mp@zzzcomputing.com
#
# This module is part of Mako and is released under
# the MIT License: http://www.opensource.org/licenses/mit-license.php

"""provides runtime services for templates, including Context, Namespace, and various helper functions."""

from mako import exceptions, util
import __builtin__, inspect, sys

class Context(object):
    """provides runtime namespace, output buffer, and various callstacks for templates."""
    def __init__(self, buffer, **data):
        self._buffer_stack = [buffer]
        self._orig = data  # original data, minus the builtins
        self._data = __builtin__.__dict__.copy() # the context data which includes builtins
        self._data.update(data)
        self._kwargs = data.copy()
        self._with_template = None
        self.namespaces = {}
        
        # "capture" function which proxies to the generic "capture" function
        self._data['capture'] = lambda x, *args, **kwargs: capture(self, x, *args, **kwargs)
        
        # "caller" stack used by def calls with content
        self.caller_stack = self._data['caller'] = CallerStack()
        
    lookup = property(lambda self:self._with_template.lookup)
    kwargs = property(lambda self:self._kwargs.copy())
    
    def push_caller(self, caller):
        self.caller_stack.append(caller)
        
    def pop_caller(self):
        del self.caller_stack[-1]
        
    def keys(self):
        return self._data.keys()
        
    def __getitem__(self, key):
        return self._data[key]

    def _push_writer(self):
        """push a capturing buffer onto this Context and return the new Writer function."""
        
        buf = util.FastEncodingBuffer()
        self._buffer_stack.append(buf)
        return buf.write

    def _pop_buffer_and_writer(self):
        """pop the most recent capturing buffer from this Context 
        and return the current writer after the pop.
        
        """

        buf = self._buffer_stack.pop()
        return buf, self._buffer_stack[-1].write
        
    def _push_buffer(self):
        """push a capturing buffer onto this Context."""
        
        self._push_writer()
        
    def _pop_buffer(self):
        """pop the most recent capturing buffer from this Context."""
        
        return self._buffer_stack.pop()
        
    def get(self, key, default=None):
        return self._data.get(key, default)
        
    def write(self, string):
        """write a string to this Context's underlying output buffer."""
        
        self._buffer_stack[-1].write(string)
        
    def writer(self):
        """return the current writer function"""

        return self._buffer_stack[-1].write

    def _copy(self):
        c = Context.__new__(Context)
        c._buffer_stack = self._buffer_stack
        c._data = self._data.copy()
        c._orig = self._orig
        c._kwargs = self._kwargs
        c._with_template = self._with_template
        c.namespaces = self.namespaces
        c.caller_stack = self.caller_stack
        return c
    def locals_(self, d):
        """create a new Context with a copy of this Context's current state, updated with the given dictionary."""
        if len(d) == 0:
            return self
        c = self._copy()
        c._data.update(d)
        return c
    def _clean_inheritance_tokens(self):
        """create a new copy of this Context with tokens related to inheritance state removed."""
        c = self._copy()
        x = c._data
        x.pop('self', None)
        x.pop('parent', None)
        x.pop('next', None)
        return c

class CallerStack(list):
    def __init__(self):
        self.nextcaller = None
    def __nonzero__(self):
        return self._get_caller() and True or False
    def _get_caller(self):
        return self[-1]
    def __getattr__(self, key):
        return getattr(self._get_caller(), key)
    def _push_frame(self):
        self.append(self.nextcaller or None)
        self.nextcaller = None
    def _pop_frame(self):
        self.nextcaller = self.pop()
        
        
class Undefined(object):
    """represents an undefined value in a template."""
    def __str__(self):
        raise NameError("Undefined")
    def __nonzero__(self):
        return False

UNDEFINED = Undefined()

class _NSAttr(object):
    def __init__(self, parent):
        self.__parent = parent
    def __getattr__(self, key):
        ns = self.__parent
        while ns:
            if hasattr(ns.module, key):
                return getattr(ns.module, key)
            else:
                ns = ns.inherits
        raise AttributeError(key)    
    
class Namespace(object):
    """provides access to collections of rendering methods, which can be local, from other templates, or from imported modules"""
    def __init__(self, name, context, module=None, template=None, templateuri=None, callables=None, inherits=None, populate_self=True, calling_uri=None):
        self.name = name
        if module is not None:
            mod = __import__(module)
            for token in module.split('.')[1:]:
                mod = getattr(mod, token)
            self._module = mod
        else:
            self._module = None
        if templateuri is not None:
            self.template = _lookup_template(context, templateuri, calling_uri)
            self._templateuri = self.template.module._template_uri
        else:
            self.template = template
            if self.template is not None:
                self._templateuri = self.template.module._template_uri
        self.context = context
        self.inherits = inherits
        if callables is not None:
            self.callables = dict([(c.func_name, c) for c in callables])
        else:
            self.callables = None
        if populate_self and self.template is not None:
            (lclcallable, lclcontext) = _populate_self_namespace(context, self.template, self_ns=self)
        
    module = property(lambda s:s._module or s.template.module)
    filename = property(lambda s:s._module and s._module.__file__ or s.template.filename)
    uri = property(lambda s:s.template.uri)
    
    def attr(self):
        if not hasattr(self, '_attr'):
            self._attr = _NSAttr(self)
        return self._attr
    attr = property(attr)

    def get_namespace(self, uri):
        """return a namespace corresponding to the given template uri.
        
        if a relative uri, it is adjusted to that of the template of this namespace"""
        key = (self, uri)
        if self.context.namespaces.has_key(key):
            return self.context.namespaces[key]
        else:
            ns = Namespace(uri, self.context._copy(), templateuri=uri, calling_uri=self._templateuri) 
            self.context.namespaces[key] = ns
            return ns
    
    def get_template(self, uri):
        return _lookup_template(self.context, uri, self._templateuri)
        
    def get_cached(self, key, **kwargs):
        if self.template:
            if not self.template.cache_enabled:
                createfunc = kwargs.get('createfunc', None)
                if createfunc:
                    return createfunc()
                else:
                    return None
                
            if self.template.cache_dir:
                kwargs.setdefault('data_dir', self.template.cache_dir)
            if self.template.cache_type:
                kwargs.setdefault('type', self.template.cache_type)
            if self.template.cache_url:
                kwargs.setdefault('url', self.template.cache_url)
        return self.cache.get(key, **kwargs)
    
    def cache(self):
        return self.template.cache
    cache = property(cache)
    
    def include_file(self, uri, **kwargs):
        """include a file at the given uri"""
        _include_file(self.context, uri, self._templateuri, **kwargs)
        
    def _populate(self, d, l):
        for ident in l:
            if ident == '*':
                for (k, v) in self._get_star():
                    d[k] = v
            else:
                d[ident] = getattr(self, ident)
    
    def _get_star(self):
        if self.callables:
            for key in self.callables:
                yield (key, self.callables[key])
        if self.template:
            def get(key):
                callable_ = self.template.get_def(key).callable_
                return lambda *args, **kwargs:callable_(self.context, *args, **kwargs)
            for k in self.template.module._exports:
                yield (k, get(k))
        if self._module:
            def get(key):
                callable_ = getattr(self._module, key)
                return lambda *args, **kwargs:callable_(self.context, *args, **kwargs)
            for k in dir(self._module):
                if k[0] != '_':
                    yield (k, get(k))
                            
    def __getattr__(self, key):
        if self.callables and key in self.callables:
            return self.callables[key]

        if self.template and self.template.has_def(key):
            callable_ = self.template.get_def(key).callable_
            return lambda *args, **kwargs:callable_(self.context, *args, **kwargs)

        if self._module and hasattr(self._module, key):
            callable_ = getattr(self._module, key)
            return lambda *args, **kwargs:callable_(self.context, *args, **kwargs)

        if self.inherits is not None:
            return getattr(self.inherits, key)
        raise exceptions.RuntimeException("Namespace '%s' has no member '%s'" % (self.name, key))

def supports_caller(func):
    """apply a caller_stack compatibility decorator to a plain Python function."""
    def wrap_stackframe(context,  *args, **kwargs):
        context.caller_stack._push_frame()
        try:
            return func(context, *args, **kwargs)
        finally:
            context.caller_stack._pop_frame()
    return wrap_stackframe
        
def capture(context, callable_, *args, **kwargs):
    """execute the given template def, capturing the output into a buffer."""
    if not callable(callable_):
        raise exceptions.RuntimeException("capture() function expects a callable as its argument (i.e. capture(func, *args, **kwargs))")
    context._push_buffer()
    try:
        callable_(*args, **kwargs)
    finally:
        buf = context._pop_buffer()
    return buf.getvalue()
        
def _include_file(context, uri, calling_uri, **kwargs):
    """locate the template from the given uri and include it in the current output."""
    template = _lookup_template(context, uri, calling_uri)
    (callable_, ctx) = _populate_self_namespace(context._clean_inheritance_tokens(), template)
    callable_(ctx, **_kwargs_for_callable(callable_, context._orig, **kwargs))
        
def _inherit_from(context, uri, calling_uri):
    """called by the _inherit method in template modules to set up the inheritance chain at the start
    of a template's execution."""
    if uri is None:
        return None
    template = _lookup_template(context, uri, calling_uri)
    self_ns = context['self']
    ih = self_ns
    while ih.inherits is not None:
        ih = ih.inherits
    lclcontext = context.locals_({'next':ih})
    ih.inherits = Namespace("self:%s" % template.uri, lclcontext, template = template, populate_self=False)
    context._data['parent'] = lclcontext._data['local'] = ih.inherits
    callable_ = getattr(template.module, '_mako_inherit', None)
    if callable_ is not None:
        ret = callable_(template, lclcontext)
        if ret:
            return ret

    gen_ns = getattr(template.module, '_mako_generate_namespaces', None)
    if gen_ns is not None:
        gen_ns(context)
    return (template.callable_, lclcontext)

def _lookup_template(context, uri, relativeto):
    lookup = context._with_template.lookup
    if lookup is None:
        raise exceptions.TemplateLookupException("Template '%s' has no TemplateLookup associated" % context._with_template.uri)
    uri = lookup.adjust_uri(uri, relativeto)
    try:
        return lookup.get_template(uri)
    except exceptions.TopLevelLookupException, e:
        raise exceptions.TemplateLookupException(str(e))

def _populate_self_namespace(context, template, self_ns=None):
    if self_ns is None:
        self_ns = Namespace('self:%s' % template.uri, context, template=template, populate_self=False)
    context._data['self'] = context._data['local'] = self_ns
    if hasattr(template.module, '_mako_inherit'):
        ret = template.module._mako_inherit(template, context)
        if ret:
            return ret
    return (template.callable_, context)

def _render(template, callable_, args, data, as_unicode=False):
    """create a Context and return the string output of the given template and template callable."""

    if as_unicode:
        buf = util.FastEncodingBuffer(unicode=True)
    elif template.output_encoding:
        buf = util.FastEncodingBuffer(unicode=as_unicode, encoding=template.output_encoding, errors=template.encoding_errors)
    else:
        buf = util.StringIO()
    context = Context(buf, **data)
    context._with_template = template
    _render_context(template, callable_, context, *args, **_kwargs_for_callable(callable_, data))
    return context._pop_buffer().getvalue()

def _kwargs_for_callable(callable_, data, **kwargs):
    argspec = inspect.getargspec(callable_)
    namedargs = argspec[0] + [v for v in argspec[1:3] if v is not None]
    for arg in namedargs:
        if arg != 'context' and arg in data and arg not in kwargs:
            kwargs[arg] = data[arg]
    return kwargs
    
def _render_context(tmpl, callable_, context, *args, **kwargs):
    import mako.template as template
    # create polymorphic 'self' namespace for this template with possibly updated context
    if not isinstance(tmpl, template.DefTemplate):
        # if main render method, call from the base of the inheritance stack
        (inherit, lclcontext) = _populate_self_namespace(context, tmpl)
        _exec_template(inherit, lclcontext, args=args, kwargs=kwargs)
    else:
        # otherwise, call the actual rendering method specified
        (inherit, lclcontext) = _populate_self_namespace(context, tmpl.parent)
        _exec_template(callable_, context, args=args, kwargs=kwargs)
        
def _exec_template(callable_, context, args=None, kwargs=None):
    """execute a rendering callable given the callable, a Context, and optional explicit arguments

    the contextual Template will be located if it exists, and the error handling options specified
    on that Template will be interpreted here.
    """
    template = context._with_template
    if template is not None and (template.format_exceptions or template.error_handler):
        error = None
        try:
            callable_(context, *args, **kwargs)
        except Exception, e:
            error = e
        except:                
            e = sys.exc_info()[0]
            error = e
        if error:
            if template.error_handler:
                result = template.error_handler(context, error)
                if not result:
                    raise error
            else:
                error_template = exceptions.html_error_template()
                context._buffer_stack[:] = [util.FastEncodingBuffer(error_template.output_encoding, error_template.encoding_errors)]
                context._with_template = error_template
                error_template.render_context(context, error=error)
    else:
        callable_(context, *args, **kwargs)
