##############################################################################
#
# Copyright (c) 2006 Lovely Systems and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""Sample generator to create principals

$Id$
"""
__docformat__ = "reStructuredText"

import zope.interface
import zope.component
import zope.event
import zope.schema
import zope.lifecycleevent
from zope.interface import implements
from zope.security.proxy import removeSecurityProxy
from zope.app.security.interfaces import IAuthentication
from zope.app.authentication import principalfolder
from zope.app.component import hooks

from z3c.sampledata.interfaces import ISampleDataPlugin

from z3c.sampledata import _


class IPrincipalDataSource(zope.interface.Interface):
    """A marker interface for principal data source adapters"""

def defaultPrincipalDataFactory(object):
     return [['batlogg', 'Jodok Batlogg', 'bJB'],
             ['jukart', 'Juergen Kartnaller', 'jJK'],
             ['dobee', 'Bernd Dorn', 'dBD'],
             ['srichter', 'Stephan Richter', 'sSR'],
             ['byzo', 'Michael Breidenbruecker', 'bMB'],
             ['oli', 'Oliver Ruhm', 'oOR']]


class ISamplePrincipalParameters(zope.interface.Interface):
    """The parameters for the sample principal generator."""

    minPrincipals = zope.schema.Int(
            title = _(u'Min principals'),
            description = _(u'Create at least this number of pricipals from'
                            u' the principals file.\n'
                            u'This has higher priority than maxPricipals.\n'
                            u'-1 : create all principals from the datasource.'
                           ),
            required = False,
            default = -1,
            )

    maxPrincipals = zope.schema.Int(
            title = _(u'Max principals'),
            description = _(u'The maximum number of principals to create.\n'
                            u'Uses the first principals from the datasource.'
                           ),
            required = False,
            default = -1,
            )

    pauLocation = zope.schema.TextLine(
            title = _(u'PAU location'),
            description = _(u'Path to the PAU inside the site manager.'),
            required = False,
            default = u'default/pau',
            )

    passwordManager = zope.schema.TextLine(
            title = _(u'Password Manager'),
            description = _(u'The password manager to use.'),
            required = False,
            default = u'SHA1',
            )


class SamplePrincipals(object):
    """Create principals inside a site manager.
    
    context : site
    return  : pau in which the principals where created
    """

    implements(ISampleDataPlugin)

    dependencies = []
    schema = ISamplePrincipalParameters

    maxPrincipals = None
    minPrincipals = None

    def generate(self, context, param={}, dataSource=[], seed=None):
        """Generate sample pricipals"""
        if 'omit' in param or context is None:
            return None
        self.minPrincipals = int(param['minPrincipals'])
        if self.minPrincipals<0:
            self.minPrincipals = None
        self.maxPrincipals = int(param['maxPrincipals'])
        if self.maxPrincipals<0:
            self.maxPrincipals = None
        originalSite = hooks.getSite()
        hooks.setSite(context)
        sm = zope.component.getSiteManager(context)
        self.pau = self._getPAU(sm, param)
        self.passwordManagerName = param['passwordManager']

        numCreated = 0
        self.logins = []
        if dataSource:
            for info in dataSource:
                if (    self.maxPrincipals is not None
                    and numCreated>=self.maxPrincipals):
                    break
                login = unicode(info[0])
                if login in self.logins:
                    # ignore duplicate principals
                    continue
                self._createPrincipal(context, info)
                numCreated+=1

        if (    self.minPrincipals is not None
            and numCreated<self.minPrincipals):
            for i in range(self.minPrincipals-numCreated):
                info = self._createDummyPrincipalInfo(context, i)
                self._createPrincipal(context, info)

        hooks.setSite(originalSite)

        return self.pau

    def _getPAU(self, sm, param):
        pau = sm
        for loc in param['pauLocation'].split('/'):
            pau = pau[loc]
        return pau


    def _createPrincipal(self, site, info):
        login = unicode(info[0])
        self.logins.append(login)
        if login in self.pau['members']:
            return
        name = unicode(info[1])
        password = unicode(info[2])
        principal = principalfolder.InternalPrincipal(
                            login,
                            password,
                            name,
                            passwordManagerName=self.passwordManagerName)
        zope.event.notify(
            zope.lifecycleevent.ObjectCreatedEvent(principal))
        self.pau['members'][login] = principal

    def _createDummyPrincipalInfo(self, site, i):
        return ['login%i'%i, 'name%i'%i, '%i'%i]

