# Copyright (c) 2002-2008 Infrae. All rights reserved.
# See also LICENSE.txt
# Zope
from AccessControl import getSecurityManager
from zope import component
# Five
from Products.Five import BrowserView
from Products.Five import StandardMacros as BaseMacros
# SilvaLayout
from Products.SilvaLayout import interfaces
from Products.SilvaLayout.browser.tree import NotPublic
from AccessControl.ZopeSecurityPolicy import getRoles

# Super hacky, but it works. ;-)
class MyRolesProxy:
    def __init__(self, method):
        self.method = method

    def rolesForPermissionOn(self, value):
        context = value.im_self.aq_inner.aq_parent
        return getRoles(context, self.method,
                        getattr(context, self.method),
                        None)

class SilvaView(BrowserView):

    def __init__(self, *args):
        BrowserView.__init__(self, *args)
        self.metadata = interfaces.IMetadata(self.context.aq_inner)

    def is_preview_view(self):
        return self.request.get('silva_view_mode',None)=='preview'

    def getRootMetadata(self, set, element):
        root = self.context.aq_inner.get_root().aq_inner
        return root.service_metadata.getMetadataValue(root, set, element)

    def getPublicationMetadata(self, set, element):
        pub = self.context.aq_inner.get_publication().aq_inner
        return pub.service_metadata.getMetadataValue(pub, set, element)
        
    def title(self):
        """title for object
        """
        context = self.context.aq_inner
        return context.get_title()
    
    def render(self):
        """default public or previewable rendering
        """
        context = self.context.aq_inner
        if self.is_preview_view():
            return context.get_previewable().preview()
        else:
            return context.view()
    
    def modificationtime(self):
        context = self.context.aq_inner
        metadata = interfaces.IMetadata(context)
        return metadata('silva-extra', 'modificationtime')

    def metadata(self, set, value):
        context = self.context.aq_inner
        metadata = interfaces.IMetadata(context)
        return metadata(set, value)
        
    def HEAD(self, REQUEST, RESPONSE=None):
        """Proxy HTTP HEAD requests. 
        """
        # A bit hackish, but it works.
        context = self.context_or_default()
        func = context.HEAD
        getSecurityManager().validate(None, context, 'HEAD', func) 
        if RESPONSE is None:
            return func(REQUEST)
        return func(REQUEST, RESPONSE)

    HEAD.__roles__ = MyRolesProxy('HEAD')

class Content(SilvaView):

    def context_or_default(self):
        return self.context.aq_inner
    
    def PUT(self, REQUEST, RESPONSE=None):
        """Proxy HTTP PUT requests. 
        """
        # A bit hackish, but it works.
        context = self.context_or_default()
        func = context.PUT
        getSecurityManager().validate(None, context, 'PUT', func)
        if RESPONSE is None:
            return func(REQUEST)
        return func(REQUEST, RESPONSE)

    PUT.__roles__ = MyRolesProxy('PUT')

class Container(SilvaView):

    def context_or_default(self):
        context = self.context.aq_inner
        default = context.get_default()
        return default

    def render(self):
        """public rendering for folders
        """
        default = self.context_or_default()
        if default is None:
            return ''
            # Delegate actual rendering to the view for this object
        if not self.is_preview_view():
            view = component.getMultiAdapter((default, self.request),
                                             name='index.html')
        else:
            view = component.getMultiAdapter((default, self.request),
                                             name='preview_html')
        view = view.__of__(default)
        return view.render()
            
    def modificationtime(self):
        context = self.context_or_default()
        if not context:
            context = self.context
        metadata = interfaces.IMetadata(context)
        return metadata('silva-extra', 'modificationtime')

class ContentPreview(Content):
    def __call__(self):
        self.request.set('silva_view_mode','preview')
        view = component.getMultiAdapter((self.context,self.request), name=u'index.html')
        return view.__of__(self.context)()

class ContainerPreview(Container):
    def __call__(self):
        self.request.set('silva_view_mode','preview')
        view = component.getMultiAdapter((self.context,self.request), name=u'index.html')
        return view.__of__(self.context)()

    
class AutoTOCView(SilvaView):
    """AutoTOCView with filtering 
    """
    def __init__(self, *args, **kwargs):
        SilvaView.__init__(self, *args)
        self.filters = kwargs.get('filters', [])

    def context_or_default(self):
        return self.context.aq_inner

    def getTocNodes(self, depth=-1):
        # XXX This implementation should've reused the ITreeNode adapters;
        # filtering is handled much better there. However, the output HTML
        # for this view should be identical to Silva's core rendering
        # for AutoTOC objects and thus we mimic that rendering here.
        items = []
        context = self.context_or_default()
        container = context.get_container()
        depth_flag = None
        for indent, obj in container.get_public_tree_all():
            # Skip all items 'deeper' than the one that needed filtering
            if depth_flag is not None:
                if indent > depth_flag:
                    continue
                else:
                    depth_flag = None
            # XXX code copied from adapters.treenode. Should be refactored.
            if self._filter(obj, self.filters):
                # Continue with next object, since the current one is
                # filtered out.
                depth_flag = indent
                continue
            items.append((indent, obj.absolute_url(), obj.get_title(),))
        return items
            
    def _filter(self, object, filters):
        # XXX code copied from adapters.treenode. Should be refactored.
        for klass in filters:
            filter = klass(object) # implements ITreeNodeFilter
            if filter():
                return True
        return False
    
    def render(self):
        """public rendering for autoTOC
        """
        request = self.request
        context = self.context_or_default()
        view = component.getMultiAdapter((context, request), name='autotoc')
        view = view.__of__(context)
        return view()
