import httplib2
from django.http import HttpResponse, HttpResponseRedirect, parse_cookie
from django.test.client import *

class TestHandler(BaseHandler):
    def __call__(self, environ):
        from django.core import signals

        if self._request_middleware is None:
            self.load_middleware()

        signals.request_started.send(sender=self.__class__)
        try:
            headers = {'Content-type': 'application/x-www-form-urlencoded'}
            http = httplib2.Http()
            request = WSGIRequest(environ)
            if request.COOKIES:
                headers.update({'Cookie': environ['HTTP_COOKIE']})
            request_body = getattr(request, request.method)
            resp, content = http.request(request.META["PATH_INFO"],
                                         method=request.method,
                                         body=request_body.urlencode(),
                                         headers=headers)
            if resp.status in [301, 302, 303, 307]:
                response = HttpResponseRedirect(resp['location'])
            else:
                response = HttpResponse(content=content,
                                        mimetype=None,
                                        status=resp.status,
                                        content_type=resp['content-type'])
            if resp.get('set-cookie'):
                for (key, val) in parse_cookie(resp['set-cookie']).items():
                    response.set_cookie(key, val)

            for middleware_method in self._response_middleware:
                response = middleware_method(request, response)
            response = self.apply_response_fixes(request, response)
        finally:
            signals.request_finished.disconnect(close_connection)
            signals.request_finished.send(sender=self.__class__)
            signals.request_finished.connect(close_connection)
        return response

class TestClient(Client):
    def __init__(self, **defaults):
        super(TestClient, self).__init__(**defaults)
        self.handler = TestHandler()

    def _handle_redirects(self, response):
        response.redirect_chain = []
        while response.status_code in (301, 302, 303, 307):
            url = response['Location']
            scheme, netloc, path, query, fragment = urlsplit(url)

            redirect_chain = response.redirect_chain
            redirect_chain.append((url, response.status_code))

            response = self.get(url, QueryDict(query), follow=False)
            response.redirect_chain = redirect_chain

            if response.redirect_chain[-1] in response.redirect_chain[0:-1]:
                break
        return response

    def get(self, path, data={}, follow=False, **extra):
        extra.update({'PATH_INFO': path})
        return super(TestClient, self).get(path, data=data, follow=follow, **extra)

    def post(self, path, data={}, content_type=MULTIPART_CONTENT, follow=False, **extra):
        extra.update({'PATH_INFO': path})
        return super(TestClient, self).post(path, data=data, content_type=content_type, follow=follow, **extra)

    def put(self, path, data={}, content_type=MULTIPART_CONTENT, follow=False, **extra):
        extra.update({'PATH_INFO': path})
        return super(TestClient, self).put(path, data=data, content_type=content_type, follow=follow, **extra)

    def head(self, path, data={}, follow=False, **extra):
        extra.update({'PATH_INFO': path})
        return super(TestClient, self).head(path, data=data, follow=follow, **extra)

    def options(self, path, data={}, follow=False, **extra):
        extra.update({'PATH_INFO': path})
        return super(TestClient, self).options(path, data=data, follow=follow, **extra)

    def delete(self, path, follow=False, **extra):
        extra.update({'PATH_INFO': path})
        return super(TestClient, self).delete(path, follow=follow, **extra)