from django.conf import settings
from django.db.models import Manager
from django.contrib.auth.models import Group
from django.contrib.contenttypes.models import ContentType
from guardian.shortcuts import assign, remove_perm, get_objects_for_user
from guardian.core import ObjectPermissionChecker

def protect_models(user):
    for cls in get_models_to_protect():
            protect_model(cls, user)
    
def unprotect_models():
    for cls in get_models_to_protect():
            unprotect_model(cls)

def get_models_to_protect():        
    to_protect = []
        
    for cls_name in settings.USE_GROUP_PERMISSIONS:
        cls_type = ContentType.objects.get(app_label="ldt_utils", model=cls_name.lower())
        to_protect.append(cls_type.model_class())
    return to_protect

def protect_model(cls, user):
    cls.base_objects = cls.objects
    cls.objects = SafeManager(cls, user)
    
    cls.base_save = cls.save
    cls.save = save_security(user, cls.__name__.lower())(cls.save)
    
def unprotect_model(cls):    
    if hasattr(cls, 'base_objects'):
        cls.objects = cls.base_objects
        cls.save = cls.base_save
        del cls.base_objects    
        del cls.base_save

class SafeManager(Manager):
    
    def __init__(self, cls, user=None):
        super(SafeManager, self).__init__()
        self.model_name = cls.__name__.lower()
        self.model = cls  
        if user:
            self.check_perm_for(user)
        else:
            self.user = None
            self.checker = None     
    
    def check_perm_for(self, user):
        self.user = user
        self.checker = ObjectPermissionChecker(self.user)
        
    def stop_checking(self):
        self.user = None
        self.checker = None
      
    def has_user(self):
        return self.user != None        
      
    def get_query_set(self):
        if not self.has_user():
            raise AttributeError("A user has to be chosen to check permissions.")
        
        user_objects = get_objects_for_user(self.user, 'ldt_utils.view_%s' % self.model_name)
            
        return user_objects    
    
def save_security(user, cls_name):
    def wrapper(func):
        def wrapped(self, *args, **kwargs):
            
            if self.pk and not user.has_perm('change_%s' % cls_name, self):
                raise AttributeError('User %s is not allowed to change object %s' % (user, self))
            
            return func(self, *args, **kwargs)
        return wrapped
    
    return wrapper

def assign_project_to_groups(project, permissions):
    for elem in permissions:
        group = Group.objects.get(id=elem['group'])
        if elem['share']:
            assign('view_project', group, project)
            if elem['perms'] == 'write':
                assign('change_project', group, project)
        else:
            remove_perm('view_project', group, project)
            remove_perm('change_project', group, project) 