from django.conf import settings
from django.conf.urls.defaults import url
from django.contrib.auth.models import Group
from guardian.shortcuts import assign
from ldt.ldt_utils.models import Project
from ldt.api.ldt.authentication import SessionAuthentication, MultiAuthentication, ApiKeyAuthentication
from ldt.api.ldt.serializers.cinelabserializer import CinelabSerializer
from ldt.api.ldt.resources import ContentResource
from ldt.api.ldt.resources.user import UserResource
from ldt.security import protect_models, unprotect_models
from ldt.security.permissionchecker import check_object_perm_for_user
from tastypie import fields, http
from tastypie.authorization import Authorization
from tastypie.exceptions import BadRequest
from tastypie.resources import Bundle, ModelResource, ALL
from tastypie.utils import dict_strip_unicode_keys


class ProjectResource(ModelResource):
    contents = fields.ManyToManyField(ContentResource, 'contents')
    owner = fields.ForeignKey(UserResource, 'owner')
    class Meta:
        allowed_methods = ['get', 'post', 'put']
        authorization = Authorization() # BE CAREFUL WITH THAT, it's unsecure
        authentication = MultiAuthentication(ApiKeyAuthentication(), SessionAuthentication())
        resource_name = 'projects'
        queryset = Project.objects.all()
        serializer = CinelabSerializer()
        filtering = {
            'state' : ALL,
            'ldt_id' : ALL,
            'title' : ALL
        }
        # In the future version :
        # detail_uri_name = 'ldt_id'
    
    
    def get_object_list(self, request):
        return Project.safe_objects.all()
    
    def override_urls(self):
        # WARNING : in tastypie <= 1.0, override_urls is used instead of prepend_urls. From 1.0.0, prepend_urls will be prefered and override_urls deprecated 
        return [
            url(r"^(?P<resource_name>%s)/(?P<ldt_id>[\w\d_.-]+)/$" % self._meta.resource_name, self.wrap_view('dispatch_detail'), name="api_dispatch_detail"),
        ]
    
    def get_resource_uri(self, bundle_or_obj):
        kwargs = {
            'resource_name': self._meta.resource_name,
            'api_name': self._meta.api_name
        }
        if isinstance(bundle_or_obj, Bundle):
            kwargs['ldt_id'] = bundle_or_obj.obj.ldt_id
        else:
            kwargs['ldt_id'] = bundle_or_obj.ldt_id
        return self._build_reverse_url("api_dispatch_detail", kwargs=kwargs)
        
    # Create a new project. Used with post_detail and with no ldt_id in the url
    def obj_create(self, bundle, request=None, **kwargs):
        unprotect_models()
        bundle = super(ProjectResource, self).obj_create(bundle, request)
        # Assign permission for the owner
        assign('view_project', request.user, bundle.obj)
        assign('change_project', request.user, bundle.obj)
        # Since the project is published by default, we assign permission for the everyone group
        everyone = Group.objects.get(name=settings.PUBLIC_GROUP_NAME)
        assign('ldt_utils.view_project', everyone, bundle.obj)
        protect_models()
        return bundle
    
    
    # Prevent for put_list and delete all objects.
    def obj_delete_list(self, request=None, **kwargs):
        raise BadRequest("PUT with a list of projects is forbidden.")
    
    
    # Updates an existing project. Used with post_detail and with a ldt_id in the url
    def post_detail(self, request, **kwargs):
        # Inspired by put_detail but we only update an object. We can not create one.
        """
        Since always_return_data is not set to True, 
        the request returns accepted (202) if the project is well updated
        and Not Found (404) if the id in url or datas were incorrect.
        """
        deserialized = self.deserialize(request, request.raw_post_data, format=request.META.get('CONTENT_TYPE', 'application/json'))
        deserialized = self.alter_deserialized_detail_data(request, deserialized)
        bundle = self.build_bundle(data=dict_strip_unicode_keys(deserialized), request=request)
        self.is_valid(bundle, request)
        try:
            # We have to check if the user can change the project BEFORE calling obj_update
            proj = Project.objects.get(ldt_id=bundle.data['ldt_id'])
            if check_object_perm_for_user(proj, "change_project", request.user):
                # Even if the user has the guardian right to change the project, 
                # tastypie's save_m2m will raise an error. So we unprotect just for this saving.
                unprotect_models()
                updated_bundle = self.obj_update(bundle, request=request, **self.remove_api_resource_names(kwargs))
                protect_models()
            else:
                raise BadRequest("User has no right to change the project.")
            
            if not self._meta.always_return_data:
                return http.HttpAccepted()
            else:
                updated_bundle = self.full_dehydrate(updated_bundle)
                updated_bundle = self.alter_detail_data_to_serialize(request, updated_bundle)
                return self.create_response(request, updated_bundle, response_class=http.HttpAccepted)
        except Exception as e:
            return http.HttpNotFound("Object does not exist or Datas are not correct.\nError = " + str(e) + "\n")
        return http.HttpResponse("fuuuuu")
    
    