from django import forms

class FieldAccessLevel:
    '''Represents an access level for a form.'''
    def __init__(self, rule, enable=None, exclude=None):
        self.rule = rule
        self.enable = enable
        self.exclude = exclude

class FieldAccessForm(forms.ModelForm):
    '''This class will grant or deny access to individual fields according
    to simple rules.

    Example:
    
    class MyForm(FieldAccessForm):
        class FieldAccess:
            staff = FieldAccessLevel(lambda u, i: u.is_staff,
                enable = ('field1', 'field2'),
                exclude = ('field3',))
    '''
    def __init__(self, request_user, *args, **kwargs):
        super(FieldAccessForm, self).__init__(*args,**kwargs)
        if request_user.is_superuser:
            # superuser has full access to all fields
            return
        instance = kwargs.get('instance',None)
        # get available access levels
        access_levels = list()
        for FieldAccess in (getattr(self, 'FieldAccess', None), 
                            getattr(self.Meta.model, 'FieldAccess', None)):
            if not FieldAccess: continue
            for attr in dir(FieldAccess):
                if attr.startswith('_'): continue
                access_levels += [getattr(FieldAccess, attr)]
        # for any access level which the user falls under, retrieve the field
        # access data for those levels
        enable = None
        exclude = None
        for level in access_levels:
            if not level.rule(request_user, instance): continue
            if level.enable:
                if enable: enable += level.enable
                else: enable = level.enable
            if level.exclude:
                if exclude: exclude += level.exclude
                else: exclude = level.exclude
        # disable all fields except those in enable or exclude
        for fieldname, field in self.fields.items():
            if exclude and fieldname in exclude:
                self.fields.pop(fieldname)
            elif not enable or fieldname not in enable:
                field.widget.attrs['readonly'] = 'readonly'
                field.widget.attrs['disabled'] = 'disabled'
                field.disabled = True
                field.value = getattr(instance, fieldname, '')