from Products.Archetypes.Schema import Schema
from Products.Archetypes.Field import StringField
from Products.Archetypes.Widget import SelectionWidget
from Products.Archetypes.config import TOOL_NAME
from Products.Archetypes.interfaces.ITemplateMixin import ITemplateMixin

from Products.CMFCore import permissions
from Products.CMFCore.utils import getToolByName
from AccessControl import ClassSecurityInfo
from Globals import InitializeClass
from Acquisition import aq_base
from Acquisition import aq_inner
from Acquisition import aq_parent
from ExtensionClass import Base

TemplateMixinSchema = Schema((
    # TemplateMixin
    StringField('layout',
                write_permission=permissions.ModifyPortalContent,
                default_method="getDefaultLayout",
                vocabulary="_voc_templates",
                # we can't use enforce because we may use the view name from the
                # type information
                #enforceVocabulary=1,
                widget=SelectionWidget(description="Choose a template that will be used for viewing this item.",
                                       description_msgid = "help_template_mixin",
                                       label = "View template",
                                       label_msgid = "label_template_mixin",
                                       i18n_domain = "plone",
                                       visible={'view' : 'hidden',
                                                'edit' : 'visible'
                                               },
                                       )),
    ))


class TemplateMixin(Base):
    __implements__ = ITemplateMixin

    schema = TemplateMixinSchema

    actions = (
        { 'id': 'view',
          'name': 'View',
          'action': 'string:${object_url}/',
          'permissions': (permissions.View,),
        },
        )

    aliases = {
        '(Default)': '',
        'index_html': '',
        'view': '',
        'gethtml': 'source_html',
        }

    # if default_view is None TemplateMixin is using the immediate_view from
    # the type information
    default_view = None
    suppl_views = ()

    security = ClassSecurityInfo()

    index_html = None # setting index_html to None forces the usage of __call__

    def __call__(self):
        """return a view based on layout"""
        v = self.getTemplateFor(self.getLayout())
        # rewrap the template in the right context
        context = aq_inner(self)
        v = v.__of__(context)
        return v(context, context.REQUEST)

    def _voc_templates(self):
        at = getToolByName(self, TOOL_NAME)
        return at.lookupTemplates(self)

    # XXX backward compatibility
    templates = _voc_templates

    security.declareProtected(permissions.View, 'getLayout')
    def getLayout(self, **kw):
        """Get the current layout or the default layout if the current one is None
        """
        if kw.has_key('schema'):
            schema = kw['schema']
        else:
            schema = self.Schema()
            kw['schema'] = schema
        value = schema['layout'].get(self, **kw)
        if value:
            return value
        else:
            return self.getDefaultLayout()

    security.declareProtected(permissions.View, 'getDefaultLayout')
    def getDefaultLayout(self):
        """Get the default layout used for TemplateMixin.

        Check the class definition for a attribute called 'default_view' then
        check the Factory Type Information (portal_types) for an attribute
        immediate_view else finally return the 'base_view' string which is a
        autogenerated form from Archetypes.
        """
        default_view = getattr(aq_base(self), 'default_view', None)
        if default_view:
            return default_view
        immediate_view = getattr(self.getTypeInfo(), 'immediate_view', None)
        if immediate_view:
            return immediate_view
        return 'base_view'

    def getTemplateFor(self, pt, default='base_view'):
        """Let the SkinManager handle this.

        But always try to show something.
        """
        pt = getattr(self, pt, None)
        if not pt:
            # default is the value of obj.default_view or base_view
            default_pt = getattr(self, 'default_view', None)
            if not default_pt:
                default_pt = default
            return getattr(self, default_pt)
        else:
            return pt


InitializeClass(TemplateMixin)

# XXX backward compatibility
schema = TemplateMixinSchema
getTemplateFor = TemplateMixin.getTemplateFor

__all__ = ('TemplateMixinSchema', 'TemplateMixin', )
