# -*- coding: utf-8 -*-
#######################################################################################
#   Plinn - http://plinn.org                                                          #
#   Copyright (C) 2005-2007  Benoît PIN <benoit.pin@ensmp.fr>                         #
#                                                                                     #
#   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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.   #
#######################################################################################
"""


"""

from Globals import InitializeClass
from AccessControl import ClassSecurityInfo
from Products.CMFCore.permissions import View, AccessContentsInformation
from Products.CMFCore.utils import getToolByName
from Products.GroupUserFolder.GroupsToolPermissions import ViewGroups, AddGroups, DeleteGroups
from Products.GroupUserFolder.GroupsTool import GroupsTool as BaseTool
from sets import Set
from OFS.SimpleItem import SimpleItem
from OFS.Cache import Cacheable

#Cache view names
CACHE_ROOT_GROUPS = 'getRootGroups'
CACHE_GROUPS_OF_GROUP = 'getGroupsOfGroup'
CACHE_USER_NAMES_OF_GROUP= 'getUserNamesOfGroup'


class GroupsTool(BaseTool, Cacheable) :
	""" Groups tool that behave like Membership tool """
	
	meta_type = 'Plinn Groups Tool'
	
	security = ClassSecurityInfo()
	
	manage_options = BaseTool.manage_options + Cacheable.manage_options
	
	security.declareProtected(AddGroups, 'getGroupWorkspacesCreationFlag')


	def _getUserNamesOfGroup(self, prefixed_group, no_recurse = 1) :
		aclu = self.aq_inner.acl_users
		allUsers = aclu.getPureUsers()
		usersDict = {}
		
		# make a dictionary of users indexed by group
		for user in allUsers :
			for group in user.getGroups(no_recurse = no_recurse) :
				if not usersDict.has_key(group) :
					usersDict[group] = [user.id, ]
				else :
					usersDict[group].append(user.id)
		return usersDict



	security.declareProtected(ViewGroups, 'getUserNamesOfGroup')
	def getUserNamesOfGroup(self, prefixed_group, no_recurse = 1) :
		""" Return users of groups"""
		
		if self.ZCacheable_isCachingEnabled() :
			usersDict = self.ZCacheable_get(view_name=CACHE_USER_NAMES_OF_GROUP,
											keywords={'no_recurse' : no_recurse},
											default=None)
			if usersDict is None :
				# load cache
				usersDict = self._getUserNamesOfGroup(prefixed_group, no_recurse = no_recurse)
				self.ZCacheable_set(usersDict,
									view_name=CACHE_USER_NAMES_OF_GROUP,
									keywords={'no_recurse' : no_recurse})
		else :
			usersDict = self._getUserNamesOfGroup(prefixed_group, no_recurse = no_recurse)

		return usersDict.get(prefixed_group, [])
		

	def _getGroupsOfGroup(self, prefixed_group) :
		aclu = self.aq_inner.acl_users
		
		allGroups = aclu.getGroups()
		groupsDict = {}
		
		# make a dictionary of users indexed by group
		for group in allGroups :
			for superGroup in group.getGroups(no_recurse=1) :
				if not groupsDict.has_key(superGroup) :
					groupsDict[superGroup] = [group.id, ]
				else :
					groupsDict[superGroup].append(group.id)

		return groupsDict
	

	
	security.declareProtected(ViewGroups, 'getGroupsOfGroup')
	def getGroupsOfGroup(self, prefixed_group) :
		""" Return groups of group """
		if self.ZCacheable_isCachingEnabled() :
			groupsDict = self.ZCacheable_get(view_name=CACHE_GROUPS_OF_GROUP, default=None)
			
			if groupsDict is None :
				# load cache
				groupsDict = self._getGroupsOfGroup(prefixed_group)
				self.ZCacheable_set(groupsDict, view_name=CACHE_GROUPS_OF_GROUP)
		else :
			groupsDict = self._getGroupsOfGroup(prefixed_group)
		
		return groupsDict.get(prefixed_group, [])
	
	security.declareProtected(ViewGroups, 'getGroups')
	def getGroups(self, groups) :
		""" Return wrapped groups """
		wGroups = [ self.getGroupById(group) for group in groups ]
		wGroups = filter(None, wGroups)
		
		wGroups.sort(_sortGroup)
		return wGroups
	
	security.declareProtected(ViewGroups, 'getOtherGroups')
	def getOtherGroups(self, groups) :
		""" Return other wrapped groups """
		aclu = self.aq_inner.acl_users
		prefix = aclu.getGroupPrefix()
		allGroupIds = aclu.getGroupNames()

		
		prefixed = 0
		wGroups = []
		if groups :
			if groups[0].startswith(prefix) :
				prefixed = 1

		
			if prefixed :
				prefixLength = len(prefix)
				groups = [ group[prefixLength:] for group in groups ]
	
			for groupId in allGroupIds :
				if groupId not in groups :
					wGroups.append(self.getGroupById(groupId))
		
		else :
			for groupId in allGroupIds :
				wGroups.append(self.getGroupById(groupId))
		
		
		wGroups.sort(_sortGroup)
		return wGroups
		
	
	def _getRootGroups(self) :
		top_level_list = []
		aclu = self.acl_users
		allGroups = aclu.getGroups()
		groupPrefix = aclu.getGroupPrefix()
		
		for group in allGroups :
			if not group.getGroups(no_recurse = 1) :
				top_level_list.append(groupPrefix+group.id)
		return top_level_list

	security.declareProtected(ViewGroups, 'getRootGroups')
	def getRootGroups(self) :
		""" return top level groups """
		if self.ZCacheable_isCachingEnabled() :
			rootGroups = self.ZCacheable_get(view_name=CACHE_ROOT_GROUPS, default=None)
			
			if rootGroups is None :
				rootGroups = self._getRootGroups()
				self.ZCacheable_set(rootGroups, view_name=CACHE_ROOT_GROUPS)
		else :
			rootGroups = self._getRootGroups()

		return rootGroups
		
		
	security.declareProtected(ViewGroups, 'getGroupsWithLocalRole')
	def getGroupsWithLocalRole(self, object, role) :
		""" Return Groups with local role """

		aclu = self.aq_inner.acl_users
		prefix = aclu.getGroupPrefix()
		allGroupNames = aclu.getGroupNames()
		usersAndGroupsWithLocalRole = object.users_with_local_role(role)
		
		return [ gn for gn in usersAndGroupsWithLocalRole if gn.startswith(prefix) ]

	
	security.declareProtected(AddGroups, 'addGroup')
	def addGroup(self, groupName, **mapping):
		""" Create a group, and a group workspace if the toggle is on,
			with the supplied id, roles, and domains.
		"""
		self.acl_users.changeOrCreateGroups(new_groups = [groupName, ])
			
		group = self.getGroupById(groupName)
		group.setGroupProperties(mapping)

		if mapping.get('createArea', None) :
			self.createGrouparea(self.acl_users.getGroupPrefix()+groupName)
		
		if self.ZCacheable_isCachingEnabled() :
			self.ZCacheable_set(None, view_name=CACHE_ROOT_GROUPS)


	security.declareProtected(AddGroups, 'createGrouparea')
	def createGrouparea(self, id):
		"""Create a space in the portal for the given group, much like member home
		folders."""
		
		ttool = getToolByName(self, 'portal_types')
		ti = ttool.getTypeInfo(self.getGroupWorkspaceContainerType())
		
		utool = getToolByName(self, 'portal_url')
		portal = utool.getPortalObject()
		workspaces = self.getGroupWorkspacesFolder()
		if workspaces is None :
			portalOwner = portal.getOwner()
			aclu = self.aq_inner.acl_users
			portalOwner = portalOwner.__of__(aclu)
			workspaces = ti._constructInstance(portal,
											   self.getGroupWorkspacesFolderId(),
											   title=self.getGroupWorkspacesFolderTitle())
			workspaces.manage_delLocalRoles(workspaces.users_with_local_role('Owner'))
			workspaces.changeOwnership(portalOwner)
			ti._finishConstruction(workspaces)


		
		# construct without security check
		group = self.getGroupById(id)
		area = ti._constructInstance(workspaces, id, title=group.getProperty('title', ''))
		
		area.manage_delLocalRoles(area.users_with_local_role('Owner'))
		self.setGroupOwnership(group, area)
		
		ti._finishConstruction(area)


	security.declareProtected(DeleteGroups, 'removeGroups')
	def removeGroups(self, ids, keep_workspaces=0) :
		""" remove the groups and invalidate cache """
		BaseTool.removeGroups(self, ids, keep_workspaces=keep_workspaces)
		if self.ZCacheable_isCachingEnabled() :
			self.ZCacheable_set(None, view_name=CACHE_ROOT_GROUPS)
			self.ZCacheable_set(None, view_name=CACHE_GROUPS_OF_GROUP)
	
	security.declareProtected(ViewGroups, 'getExplAndImplGroupsByUserId')
	def getExplAndImplGroupsByUserId(self, userid) :
		""" Return a dictionary with implicit and explicit wrapped groups """
		aclu = self.aq_inner.acl_users
		user = aclu.getUser(userid)
		if user :
			expl = Set(self.aq_inner.acl_users.getUser(userid).getGroups(no_recurse = 1) or [])
			implDbl = Set(self.aq_inner.acl_users.getUser(userid).getGroups(no_recurse = 0) or [])
			impl = implDbl.difference(expl)
		# wrap
		expl = [self.getGroupById(gid) for gid in expl]
		impl = [self.getGroupById(gid) for gid in impl]
		expl.sort(_sortGroup)
		impl.sort(_sortGroup)
		return {'explicit' : expl,
				'implicit' : impl}
	
InitializeClass(GroupsTool)

	
def _sortGroup(a, b) :
	return cmp(a.id.lower(), b.id.lower())
