# -*- coding: utf-8 -*-

import json
from collections import OrderedDict

from django.shortcuts import get_object_or_404
from django.forms.models import modelform_factory
from django.views.decorators.csrf import csrf_exempt

from django_snooze.utils import json_response
from django_snooze.fields import field


class ModelResource(object):
    """
    This is the base model resource, it takes a model and will create an API
    object.
    """

    def __init__(self, model):
        """
        This inspects all the model's meta information and process it to
        extract all the information we need.

        Arguments:
            - model (required): The model to inspect.
        """
        self.model = model
        self.app = model._meta.app_label
        self.model_name = model._meta.model_name
        self.query_url_re = self.get_query_url_re()
        self.schema_url_re = self.get_schema_url_re()
        self.pk_url_re = self.get_pk_url_re()
        self.new_url_re = self.get_new_url_re()
        self.query_reverse_name = self.get_query_reverse_name()
        self.schema_reverse_name = self.get_schema_reverse_name()
        self.pk_reverse_name = self.get_pk_reverse_name()
        self.new_reverse_name = self.get_new_reverse_name()
        self.fields = self.get_fields()
        self.fields_dict = self.get_fields_dict()
        self.queryset = self.get_queryset()
        self.form = self.get_form()

    def get_url_re_base(self):
        """
        Method to get the URL base regular expression.
        """
        return r'^{}/{}/'.format(self.app, self.model_name)

    def get_query_url_re(self):
        """
        Method to get the query URL regular expression.
        """
        return self.get_url_re_base() + r'$'

    def get_pk_url_re(self):
        """Constructs the primary key regular expression.

        :returns: A regular expression string.

        """
        # TODO: Detect different kinds of primary key than plain old integers.
        return self.get_url_re_base() + r'(?P<pk>\d+)/$'

    def get_schema_url_re(self):
        """
        Method to get the schema URL regular expression.
        """
        return self.get_url_re_base() + r'schema/$'

    def get_new_url_re(self):
        """Constructs the regular expression for the 'new' URL.

        :returns: A regular expression string.

        """
        return self.get_url_re_base() + r'new/$'

    def get_query_reverse_name(self):
        """
        Method to get the name for the query URL.
        """
        return '{}-{}'.format(self.app, self.model_name)

    def get_schema_reverse_name(self):
        """
        Method to get the name for the schema URL.
        """
        return '{}-{}-schema'.format(self.app, self.model_name)

    def get_pk_reverse_name(self):
        """Generates a reverse lookup name for the pk URL.

        :returns: A reverse lookup string.

        """
        return '{}-{}-pk'.format(self.app, self.model_name)

    def get_new_reverse_name(self):
        """Generates a reverse lookup name for the new URL.

        :returns: A reverse lookup string.

        """
        return '{}-{}-new'.format(self.app, self.model_name)

    def get_fields(self):
        """
        Gets all the fields of the model.
        """
        fields = [getattr(field, x.__class__.__name__)(x)
                  for x in self.model._meta.fields]

        return fields

    def get_fields_dict(self):
        """Adds all fields to a dictionary, keyed by name.

        :returns: A dictionary of fields.

        """
        return {x.name: x for x in self.fields}

    def get_queryset(self):
        """Gets the queryset of the model.

        :returns: The queryset

        """
        # TODO: Change this to detect it in the meta class of the model.
        return self.model.objects.all()

    def get_form(self):
        """Gets a modelform of the current model, to be used for creation and
        editing.

        :returns: A ModelForm

        """
        return modelform_factory(self.model)

    def view(self, request):
        """
        View handler.
        """
        # Set self.request so that we don't have to pass it around all the time
        self.request = request
        if request.method == 'GET':
            content = self.get()
        elif request.method == 'POST':
            content = self.post()
        else:
            return json_response({'error': 'Bad request'}, status_code=400)
        return json_response(content)

    def get(self):
        """Handle a GET request.

        :returns: A json serialisable object.

        """
        content = {}
        objects = []

        # TODO: Make this faster?
        for obj in self.queryset:
            obj_dict = self.obj_to_json(obj)
            objects.append(obj_dict)

        content['objects'] = objects
        return content

    def pk_view(self, request, pk):
        """Shows the requested object.

        :param request: The current request object.
        :param pk: The primary key for the request object.
        :returns: A HTTPResponse object.

        """
        obj = get_object_or_404(self.queryset, pk=pk)
        return json_response(self.obj_to_json(obj))

    def obj_to_json(self, obj):
        """Convert an object to a json serialisable object.

        :param obj: The object to serialise.
        :returns: A serialisable object.

        """
        obj_dict = {}
        for obj_field in self.fields:
            obj_dict[obj_field.name] = obj_field.to_json(
                getattr(obj, obj_field.name)
            )
        return obj_dict

    def schema_view(self, request):
        """
        Schema handler.
        """
        schema = OrderedDict()
        for f in self.fields:
            schema[f.name] = f.schema_info()
        return json_response(schema)

    @csrf_exempt
    def new_view(self, request):
        """Add a new object, we do this by accepting a JSON post.

        :param request: A Django request object.
        :returns: An HttpResponse object.

        """
        if (
            request.method == 'POST'
            and 'application/json' in request.META['CONTENT_TYPE']
        ):
            data = json.loads(request.body)
            form = self.form(initial=data)
            if form.is_valid():
                form.save()
                response = {'Status': 'success'}
            else:
                response = form.errors
        else:
            response = {'Status': 'Bad request'}

        return json_response(response)

    def __unicode__(self):
        return '{}-{}'.format(self.app, self.model_name)

@@ -6265,15 +6265,12 @@
 orm(
-initial
+data
 =dat
@@ -6381,16 +6381,50 @@
 ccess'%7D%0A
+                status_code = 201%0A
         
@@ -6472,16 +6472,50 @@
 .errors%0A
+                status_code = 400%0A
         
@@ -6568,16 +6568,46 @@
 equest'%7D
+%0A            status_code = 400
 %0A%0A      
@@ -6637,16 +6637,41 @@
 response
+, status_code=status_code
 )%0A%0A    d

Fix the new_view.