import grok
import logging
import os
try:
    from zope.authentication.interfaces import IAuthentication
except:
    # BBB
    from zope.app.security.interfaces import IAuthentication
from zope.component import createObject, getUtilitiesFor
try:
    from zope.pluggableauth import PluggableAuthentication
except ImportError:
    # BBB
    from zope.app.authentication.authentication import PluggableAuthentication

from waeup.sirp.authentication import setup_authentication
from waeup.sirp.datacenter import DataCenter
from waeup.sirp.interfaces import (
    IUniversity, IDataCenter, IWAeUPSIRPPluggable,
    IDataCenterStorageMovedEvent)
from waeup.sirp.users import UserContainer

class University(grok.Application, grok.Container):
    """A university.
    """
    grok.implements(IUniversity)
    
    # Setup authentication for this app. Note: this is only
    # initialized, when a new instance of this app is created.
    grok.local_utility(
        PluggableAuthentication, provides = IAuthentication,
        setup = setup_authentication,)

    # The name of the university.
    name=u'Sample University'
    
    # The default layout.
    skin=u'waeuptheme-gray1.css'
    
    # The administrator e-mail account
    email = u'e-mail'
    
    @property
    def logger(self):
        """The application logger.

        Returns a standard logger object as provided by :mod:`logging`
        module from the standard library.
        
        Other components can use this logger to perform log entries
        into the 'main' logfile.

        The logger is initialized the first time, it is called.
        """
        sitename = self.__name__
        loggername = 'waeup.sirp.%s' % sitename
        logger = logging.getLogger(loggername)
        if not logger.handlers:
            logger = self._setupLogger(logger)
        return logger
        
    
    def __init__(self, name=name, skin=skin, **kw):
        super(University, self).__init__(**kw)
        self.name = name
        self.skin = skin
        self.setup()

    def setup(self):
        """Setup some hard-wired components.

        Create local datacenter, containers for users, students and
        the like.
        """
        self['users'] = UserContainer()
        self['datacenter'] = DataCenter()

        self['students'] = createObject(u'waeup.StudentContainer')
        self['hostels'] = createObject(u'waeup.HostelContainer')
        self._createPlugins()

    def _createPlugins(self):
        """Create instances of all plugins defined somewhere.
        """
        for name, plugin in getUtilitiesFor(IWAeUPSIRPPluggable):
            plugin.setup(self, name, self.logger)
        return

    def updatePlugins(self):
        """Lookup all plugins and call their `update()` method.
        """
        for name, plugin in getUtilitiesFor(IWAeUPSIRPPluggable):
            plugin.update(self, name, self.logger)
        return

    def _setupLogger(self, logger):
        """Setup general application logger.

        The logfile will be stored in the datacenter logs/ dir.
        """
        logdir = os.path.join(self['datacenter'].storage, 'logs')
        if not os.path.exists(logdir):
            os.mkdir(logdir)
        filename = os.path.join(logdir, 'application.log')

        # Create a rotating file handler logger for application.
        handler = logging.handlers.RotatingFileHandler(
            filename, maxBytes=5*1024**1, backupCount=7)
        formatter = logging.Formatter(
            '%(asctime)s - %(levelname)s - %(message)s')
        handler.setFormatter(formatter)
        
        # Don't send log msgs to ancestors. This stops displaying
        # logmessages on the commandline.
        logger.propagate = False
        logger.addHandler(handler)
        return logger

@grok.subscribe(IDataCenter, IDataCenterStorageMovedEvent)
def handle_storage_move(obj, event):
    """Event handler, in case datacenter storage moves.

    We initialize the application log again, then.
    """
    app = grok.getSite()
    if app is None:
        return
    if obj is not app['datacenter']:
        return
    logger = app.logger
    logger.warn('Log Dir moved. Closing.')
    handlers = logger.handlers
    for handler in handlers:
        logger.removeHandler(handler)
    app._setupLogger(logger)
    logger.warn('Log file moved. Opening.')
