from django.http import HttpResponseBadRequest

from functools import wraps
from inspect import getargspec
from django.http import HttpResponse
from simplejson import loads as json_decode, dumps as json_encode
from common.util import stringify_keys
from django.db import transaction

#https://djangosnippets.org/snippets/771/
def ajax_required(f):
    def wrap(request, *args, **kwargs):
        if not request.is_ajax():
            return HttpResponseBadRequest()
        return f(request, *args, **kwargs)
    wrap.__doc__=f.__doc__
    wrap.__name__=f.__name__
    return wrap

class AjaxError(Exception):
    pass

def json_decode_fallback(value):
    try:
        return json_decode(value)
    except ValueError:
        return value

def ajax(login_required=False, method=None, encode_result=True):
    def decorator(fun):
        @wraps(fun)
        def ajax_view(request, *args, **kwargs):
            request_params = None
            if method == 'post':
                request_params = request.POST
            elif method == 'get':
                request_params = request.GET
            fun_params, xx, fun_kwargs, xxxx = getargspec(fun)
            if request_params:
                request_params = dict((key, json_decode_fallback(value))
                                      for key, value in request_params.items()
                                      if fun_kwargs or key in fun_params)
                kwargs.update(stringify_keys(request_params))
            res = None
            if login_required and not request.user.is_authenticated:
                res = {'result': 'logout'}
            if not res:
                try:
                    res = fun(request, *args, **kwargs)
                except AjaxError as e:
                    res = {'result': e.args[0]}
                    transaction.rollback()
            if encode_result:
                if 'result' not in res:
                    res['result'] = 'ok'
                return HttpResponse(json_encode(res))
            else:
                return res
        return ajax_view
    return decorator