from cgi import escape

from AccessControl.SecurityInfo import ClassSecurityInfo
from Acquisition import Explicit
from Acquisition import aq_base
from App.class_init import InitializeClass
from App.special_dtml import DTMLFile
from Persistence import Persistent

from Products.CMFCore.Expression import Expression
from Products.CMFCore.utils import _checkPermission
from Products.DCWorkflow.Expression import StateChangeInfo
from Products.DCWorkflow.Expression import createExprContext
from Products.DCWorkflow.permissions import ManagePortal
from Products.DCWorkflow.utils import _dtmldir
# XXX(WORKFLOW) remove dependencies to DCWorkflow ^


class GuardableMixin(object):
  '''
  code of methods and functions taken from 
  Products.DCWorkflow-2.2.4 > Guard.py
  '''

  guard_expression = Expression('')
  guard_group = ()
  guard_permission = ()
  guard_role = ()

  security = ClassSecurityInfo()
  security.declareObjectProtected(ManagePortal)

  def checkGuard(self, security_manager, workflow, current_object, check_roles=True, **kw):
    """Checks conditions in this guard.
    """
    user_roles = None
    if workflow.manager_bypass:
      # Possibly bypass.
      user_roles = security_manager.getUser().getRolesInContext(current_object)
      if 'Manager' in user_roles:
        return True
    if self.guard_permission:
      for permission in self.guard_permission:
        if _checkPermission(permission, current_object):
          break
      else:
        return False
    if check_roles and self.guard_role:
      # Require at least one of the given roles.
      if user_roles is None:
        user_roles = security_manager.getUser()\
                       .getRolesInContext(current_object)
      for role in self.guard_role:
        if role in user_roles:
          break
      else:
        return False
    if self.guard_group:
      # Require at least one of the specified groups.
      user = security_manager.getUser()
      base = aq_base(user)
      if hasattr(base, 'getGroupsInContext'):
        user_groups = user.getGroupsInContext(current_object)
      elif hasattr(base, 'getGroups' ):
        user_groups = user.getGroups()
      else:
        user_groups = ()
      for group in self.guard_group:
        if group in user_groups:
          break
      else:
        return False
    if self.guard_expression and self.guard_expression.text:
      expression_context = createExprContext(StateChangeInfo(current_object,
                                                             workflow,
                                                             kwargs=kw))
      if not self.guard_expression(expression_context):
        return False
    return True

  security.declareProtected(ManagePortal, 'getSummary')
  def getSummary(self):
    # Perhaps ought to be in DTML.
    summary = []
    if self.guard_permission:
      summary.append('Requires permission:')
      summary.append(formatNameUnion(self.guard_permission))
    if self.guard_role:
      if summary:
        summary.append('<br/>')
      summary.append('Requires role:')
      summary.append(formatNameUnion(self.guard_role))
    if self.guard_group:
      if summary:
        summary.append('<br/>')
      summary.append('Requires group:')
      summary.append(formatNameUnion(self.guard_group))
    if self.guard_expression is not None:
      if summary:
        summary.append('<br/>')
      summary.append('Requires expr:')
      summary.append('<code>' + escape(self.guard_expression.text) + '</code>')
    return ' '.join(summary)

  def changeFromProperties(self, props):
    '''
    Returns True if changes were specified.
    '''
    if props is None:
      return False
    changed = False

    given_property = props.get('guard_permission', None)
    if given_property:
      changed = True
      permission_list = [permission.strip() for permission in
                         given_property.split(';')]
      self.guard_permission = tuple(permission_list)

    given_property = props.get('guard_role', None)
    if given_property:
      changed = True
      role_list = [role.strip() for role in given_property.split(';')]
      self.guard_role = tuple(role_list)

    given_property = props.get('guard_group', None)
    if given_property:
      changed = True
      group_list = [ group.strip() for group in given_property.split(';') ]
      self.guard_group = tuple(group_list)

    given_property = props.get('guard_expression', None)
    if given_property:
      changed = True
      self.guard_expression = Expression(given_property)

    return changed

  security.declareProtected(ManagePortal, 'setGuardExpression')
  def setGuardExpression(self, text):
    self.guard_expression = Expression(text)

  security.declareProtected(ManagePortal, 'getGuardExpression')
  def getGuardExpression(self):
    if self.guard_expression is None:
      return Expression('')
    return self.guard_expression

def formatNameUnion(names):
  escaped = ['<code>' + escape(name) + '</code>' for name in names]
  if len(escaped) == 2:
    return ' or '.join(escaped)
  elif len(escaped) > 2:
    escaped[-1] = ' or ' + escaped[-1]
  return '; '.join(escaped)