# yacon.models.content.py
import logging, traceback

from django.http import Http404
from django.template import RequestContext, Template
from django.utils.safestring import mark_safe

logger = logging.getLogger(__name__)

# ============================================================================
# PermissionHandler Objects
# ============================================================================

class PermissionHandler(object):
    """Base class for permissions used by ContentHandler.  Default denies all
    permissions to everyone."""
    CAN_VIEW = 1;
    CAN_EDIT = 2;

    def has_permission(self, request, mode):
        logger.debug('returning False')
        return False

    def permission_denied_content(self, request):
        logger.debug('returning default denied message')
        return '<p>Permission denied to this component</p>'


class AlwaysYesPermissionHandler(PermissionHandler):
    """PermissionHandler that grants everyone permission always.  Probably
    shouldn't be used in production, good for testing."""
    def has_permission(self, request, mode): 
        logger.debug('returning True')
        return True


# ============================================================================
# ContentHandler Objects
# ============================================================================

class ContentRenderingException(Exception):
    pass


class ContentHandler(object):
    """Base class for content handlers, these specify how to retrieve content
    and make it available to the page renderers."""

    def __init__(self, block_type, parms):
        self.parms = parms
        self.block_type = block_type

    def internal_render(self, request, context, block):
        """Method that inheritors should over-ride to return content.  Called
        by render()"""
        pass

    def render(self, request, context, block):
        """Wraps internal_render() by adding information to any exceptions 
        caught and marking what is returned as safe."""
        try:
            return mark_safe(self.internal_render(request, context, block))
        except Http404 as h:
            # don't want special handling for 404s, just pass them up
            raise h
        except Exception as e:
            et = e.__class__.__name__
            ot = self.__class__.__name__
            msg = \
"""
An exception was caught while rendering using the user specified 
ContentHandler "%s".  The exception was: "%s" 
with the message:

%s

Typical causes are errors in the internal_render() method.
""" % (ot, et, e)

            cre = ContentRenderingException(msg)
            logger.exception(msg)
            raise cre


# ----------------------------------------------------------------------------
# System ContentHandlers

class FlatContent(ContentHandler):
    """ContentHandler for content that requires no permission checking or
    other work, essentially just outputs what is in the db for the block"""
    def internal_render(self, request, context, block):
        c = RequestContext(request)
        t = Template(block.content)
        return t.render(c)


class DynamicContent(ContentHandler):
    """ContentHandler for content generated by user defined function.  The
    name of the function and the module it is in should be passed in to the
    "parameters" block of the ContentHandler using the keys "module" and
    "function", respectively.  

    The function name will be called, expecting three parameters, the request,
    the context for the request and the block firing the ContentHandler.  The
    function should return a string containing the content to be rendered. """
    def internal_render(self, request, context, block):
        mod = __import__(self.parms['module'], 
            fromlist=[self.parms['function']])
        f = getattr(mod, self.parms['function'])
        try:
            return f(request, context, block)
        except Http404 as h:
            # don't want special handling for 404s, just pass them up
            raise h
        except Exception as e:
            et = e.__class__.__name__
            msg = \
"""
An exception was caught during rendering using the DynamicContent content
handler.   The exception was: "%s" with the message:

%s

Stack trace was:

%s
""" % (et, e, traceback.format_exc())

            cre = ContentRenderingException(msg)
            raise cre
