## $Id: breadcrumbs.py 7700 2012-02-24 23:04:05Z henrik $
##
## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 2 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
##
""" Components to get breadcrumbs for any object.
"""
import grok
from grokcore.view.interfaces import IGrokView
from zope.component import getAdapter
from zope.publisher.browser import TestRequest

from waeup.sirp.interfaces import (
    IConfigurationContainer, ISessionConfiguration)
from waeup.sirp.interfaces import MessageFactory as _
from waeup.sirp.browser import interfaces
from waeup.sirp.browser.interfaces import (IBreadcrumb,
    IBreadcrumbIgnorable, IBreadcrumbContainer)
        
class Breadcrumb(grok.Adapter):
    """A most general breadcrumb generator.
    """
    grok.provides(IBreadcrumb)
    grok.context(interfaces.ISIRPObject)
    grok.name('index')

    _title = None
    _parent = 0
    _request = None
    parent_viewname = 'index'
    viewname = 'index'
    
    def __init__(self, context):
        """Turn a context into a breadcrumb.
        """
        self.context = context

    @property
    def title(self):
        """Get a title for a context.
        """
        if self._title is not None:
            return self._title
        if hasattr(self.context, 'title'):
            return self.context.title
        if hasattr(self.context, 'name'):
            return self.context.name            
        return None

    @property
    def parent(self):
        """Get the contexts parent object and viewname or None.
        """
        if self._parent is None:
            return None
        if self._parent is not 0:
            return (self._parent, self.parent_viewname)

        if self.viewname != 'index':
            self._parent = self.context
        else:
            site = grok.getSite()
            if self.context is not site:
                self._parent = getattr(self.context, '__parent__', None)

        if self._parent is not None:
            return (self._parent, self.parent_viewname)
        return None

    @property
    def target(self):
        return self.viewname

class UniversityBreadcrumb(Breadcrumb):
    """A breadcrumb for university index pages.
    """
    grok.context(interfaces.IUniversity)
    title = _(u'Home')
    parent = None

class PortalSettingsBreadcrumb(Breadcrumb):
    """A breadcrumb for the manage view of universities.

    Here we need a special `parent()` implementation, because the
    parent object is not a real parent (the University object has no
    valid parent in terms of breadcrumbs). Instead it is the
    ``administration`` view of the same context the ``manage`` page
    itself is bound to.
    """
    grok.context(interfaces.IUniversity)
    grok.name('manage')
    title = _(u'Portal Settings')

    @property
    def parent(self):
        """Return the 'administration' view of our context as parent.
        """
        return (self.context, 'administration')

class FacultiesContainerBreadcrumb(Breadcrumb):
    """A breadcrumb for faculty containers.
    """
    grok.context(interfaces.IFacultiesContainer)
    title = _(u'Academics')

class AdministrationBreadcrumb(Breadcrumb):
    """A breadcrumb for administration areas of University instances.
    """
    grok.context(interfaces.IUniversity)
    grok.name('administration')
    title = _(u'Administration')
    viewname = 'administration'

class ConfigurationContainerBreadcrumb(Breadcrumb):
    """A breadcrumb for the configuration container.
    """
    grok.context(IConfigurationContainer)
    title = _(u'Portal Configuration')
    parent_viewname = 'administration'

class SessionConfigurationBreadcrumb(Breadcrumb):
    """A breadcrumb for the configuration container.
    """
    grok.context(ISessionConfiguration)
    title = u'Portal Session Configuration'

    @property
    def title(self):
        session_string = self.context.getSessionString()
        return 'Session %s' % session_string

class UsersContainerBreadcrumb(Breadcrumb):
    """A breadcrumb for user containers.
    """
    grok.context(interfaces.IUsersContainer)
    title = _(u'Portal Users')
    parent_viewname = 'administration'

class DataCenterBreadcrumb(Breadcrumb):
    """A breadcrumb for data centers.
    """ 
    grok.context(interfaces.IDataCenter)
    title = _(u'Data Center')
    parent_viewname = 'administration'

class FacultyBreadcrumb(Breadcrumb):
    """A breadcrumb for faculties.
    """
    grok.context(interfaces.IFaculty)
    
    @property
    def title(self):
        return self.context.longtitle()

class DepartmentBreadcrumb(FacultyBreadcrumb):
    """A breadcrumb for departments.
    """
    grok.context(interfaces.IDepartment)
    
class CourseBreadcrumb(FacultyBreadcrumb):
    """A breadcrumb for courses.
    """
    grok.context(interfaces.ICourse)   
    
class CertificateBreadcrumb(FacultyBreadcrumb):
    """A breadcrumb for certificates.
    """
    grok.context(interfaces.ICertificate)        

class CoursesContainerBreadcrumb(Breadcrumb):
    """ We don't want course container breadcrumbs.
    """
    grok.context(interfaces.ICoursesContainer)
    grok.implements(IBreadcrumbIgnorable)

class CertificatesContainerBreadcrumb(Breadcrumb):
    """ We don't want course container breadcrumbs.
    """
    grok.context(interfaces.ICertificatesContainer)
    grok.implements(IBreadcrumbIgnorable)

class CertificateCourseBreadcrumb(Breadcrumb):
    """ We don't want course container breadcrumbs.
    """
    grok.context(interfaces.ICertificateCourse)
    @property
    def title(self):
        return self.context.longtitle()

def getBreadcrumb(obj, viewname=None):
    """ Get a breadcrumb for an object and a viewname.

    If there is no breadcrumb defined for such a combination, a
    breadcrumb for the ``index`` view will be looked up.
    """
    try:
        return getAdapter(obj, IBreadcrumb, name=viewname)
    except:
        pass
    return getAdapter(obj, IBreadcrumb, name='index')

def getBreadcrumbList(obj, viewname):
    """Get an ordered list of breadcrumbs for an object and a viewname.

    Ignorables are excluded from the result.
    """
    current = getBreadcrumb(obj, viewname)
    result = [current]
    while current.parent is not None:
        context, viewname = current.parent
        current = getBreadcrumb(context, viewname)
        if IBreadcrumbIgnorable.providedBy(current):
            # Ignore empty breadcrumbs...
            continue
        result.append(current)
    result.reverse()
    return result

def getBreadcrumbListForView(view):
    """Get an ordered list of breadcrumbs a certain view.

    Ignorables are excluded from the result.
    """
    context = getattr(view, 'context')
    viewname = getattr(view, '__name__')
    return getBreadcrumbList(context, viewname)

class BreadcrumbContainer(grok.Adapter):
    """An adapter to adapt grok views to list of breadcrumbs.
    """
    grok.context(IGrokView)
    grok.provides(IBreadcrumbContainer)

    _breadcrumbs = None
    
    def __init__(self, context):
        self.context = context
        self._breadcrumbs = getBreadcrumbListForView(self.context)

    def __iter__(self):
        """Allow iteration.
        """
        return self._breadcrumbs.__iter__()

    def getList(self):
        """Get the (ordered) list of breadcrumbs liked to the context view.
        """
        return self._breadcrumbs
