# Path: eulcommon/djangoextras/http/decorators.py
# def content_negotiation(formats, default_type='text/html'):
#     """
#     Provides basic content negotiation and returns a view method based on the
#     best match of content types as indicated in formats.
# 
#     :param formats: dictionary of content types and corresponding methods
#     :param default_type: string the decorated method is the return type for.
# 
#     Example usage::
# 
#         def rdf_view(request, arg):
#             return RDF_RESPONSE
# 
#         @content_negotiation({'application/rdf+xml': rdf_view})
#         def html_view(request, arg):
#             return HTML_RESPONSE
# 
#     The above example would return the rdf_view on a request type of
#     ``application/rdf+xml`` and the normal view for anything else.
# 
#     Any :class:`django.http.HttpResponse` returned by the view method chosen
#     by content negotiation will have a 'Vary: Accept' HTTP header added.
# 
#     **NOTE:** Some web browsers do content negotiation poorly, requesting
#     ``application/xml`` when what they really want is ``application/xhtml+xml`` or
#     ``text/html``.  When this type of Accept request is detected, the default type
#     will be returned rather than the best match that would be determined by parsing
#     the Accept string properly (since in some cases the best match is
#     ``application/xml``, which could return non-html content inappropriate for
#     display in a web browser).
#     """    
#     def _decorator(view_method):
#         @wraps(view_method)
#         def _wrapped(request, *args, **kwargs):
#             # Changed this to be a value passed as a method argument defaulting
#             # to text/html instead so it's more flexible.
#             # default_type = 'text/html'  # If not specificied assume HTML request.
# 
#             # Add text/html for the original method if not already included.
#             if default_type not in formats:
#                 formats[default_type] = view_method
# 
#             try:
#                 req_type = request.META['HTTP_ACCEPT']
#                 
#                 # If this request is coming from a browser like that, just
#                 # give them our default type instead of honoring the actual best match
#                 # (see note above for more detail)
#                 if '*/*' in req_type:
#                     req_type = default_type
#                     
#             except KeyError:
#                 req_type = default_type
# 
#             # Get the best match for the content type requested.
#             content_type = mimeparse.best_match(formats.keys(),
#                                                 req_type)
#                                                 
#             # Return the view matching content type or the original view
#             # if no match.
#             if not content_type or content_type not in formats:
#                 response = view_method(request, *args, **kwargs)
#             else:
#                 response = formats[content_type](request, *args, **kwargs)
# 
#             # set a Vary header to indicate content may vary based on Accept header            
#             if isinstance(response, HttpResponse):    # views should return HttpResponse objects, but check to be sure
#                 # note: using the same utility method used by django's vary_on_headers decorator
#                 patch_vary_headers(response, ['Accept'])
#             return response
#         return _wrapped
#     return _decorator


from unittest import TestCase
from django.http import HttpResponse, HttpRequest
from eulcommon.djangoextras.http import content_negotiation

def xml_view(request):
    return HttpResponse("XML")

def json_view(request):
    return HttpResponse("JSON")

class ContentNegotiationTest(TestCase):
    # known browser accept headers - taken from https://developer.mozilla.org/en/Content_negotiation
    FIREFOX = 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
    CHROME = 'application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5'
    # same Accept header used by both Safari and Google Chrome
    IE8 = 'image/jpeg, application/x-ms-application, image/gif, application/xaml+xml, image/pjpeg, application/x-ms-xbap, application/x-shockwave-flash, application/msword, */*'

    def setUp(self):
        self.request = HttpRequest()

        # add content negotiation to test view defined above for testing
        decorator = content_negotiation({'application/xml': xml_view})
        self.negotiated_view = decorator(html_view)

    def test_default(self):
        # no accept header specified - should use default view
        response = self.negotiated_view(self.request)
        self.assertEqual("HTML", response.content)
        self.assertEqual('Accept', response['vary'],
            "response should have a 'Vary: Accept' header")

    def test_custom_default(self):
        # no accept header, should return user specified default view.

# Path: eulcommon/djangoextras/http/decorators.py
# def content_negotiation(formats, default_type='text/html'):
#     """
#     Provides basic content negotiation and returns a view method based on the
#     best match of content types as indicated in formats.
# 
#     :param formats: dictionary of content types and corresponding methods
#     :param default_type: string the decorated method is the return type for.
# 
#     Example usage::
# 
#         def rdf_view(request, arg):
#             return RDF_RESPONSE
# 
#         @content_negotiation({'application/rdf+xml': rdf_view})
#         def html_view(request, arg):
#             return HTML_RESPONSE
# 
#     The above example would return the rdf_view on a request type of
#     ``application/rdf+xml`` and the normal view for anything else.
# 
#     Any :class:`django.http.HttpResponse` returned by the view method chosen
#     by content negotiation will have a 'Vary: Accept' HTTP header added.
# 
#     **NOTE:** Some web browsers do content negotiation poorly, requesting
#     ``application/xml`` when what they really want is ``application/xhtml+xml`` or
#     ``text/html``.  When this type of Accept request is detected, the default type
#     will be returned rather than the best match that would be determined by parsing
#     the Accept string properly (since in some cases the best match is
#     ``application/xml``, which could return non-html content inappropriate for
#     display in a web browser).
#     """    
#     def _decorator(view_method):
#         @wraps(view_method)
#         def _wrapped(request, *args, **kwargs):
#             # Changed this to be a value passed as a method argument defaulting
#             # to text/html instead so it's more flexible.
#             # default_type = 'text/html'  # If not specificied assume HTML request.
# 
#             # Add text/html for the original method if not already included.
#             if default_type not in formats:
#                 formats[default_type] = view_method
# 
#             try:
#                 req_type = request.META['HTTP_ACCEPT']
#                 
#                 # If this request is coming from a browser like that, just
#                 # give them our default type instead of honoring the actual best match
#                 # (see note above for more detail)
#                 if '*/*' in req_type:
#                     req_type = default_type
#                     
#             except KeyError:
#                 req_type = default_type
# 
#             # Get the best match for the content type requested.
#             content_type = mimeparse.best_match(formats.keys(),
#                                                 req_type)
#                                                 
#             # Return the view matching content type or the original view
#             # if no match.
#             if not content_type or content_type not in formats:
#                 response = view_method(request, *args, **kwargs)
#             else:
#                 response = formats[content_type](request, *args, **kwargs)
# 
#             # set a Vary header to indicate content may vary based on Accept header            
#             if isinstance(response, HttpResponse):    # views should return HttpResponse objects, but check to be sure
#                 # note: using the same utility method used by django's vary_on_headers decorator
#                 patch_vary_headers(response, ['Accept'])
#             return response
#         return _wrapped
#     return _decorator


# Path: test/test_djangoextras/test_http.py
from unittest import TestCase
from django.http import HttpResponse, HttpRequest
from eulcommon.djangoextras.http import content_negotiation


def xml_view(request):
    return HttpResponse("XML")

def json_view(request):
    return HttpResponse("JSON")

class ContentNegotiationTest(TestCase):
    # known browser accept headers - taken from https://developer.mozilla.org/en/Content_negotiation
    FIREFOX = 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'
    CHROME = 'application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5'
    # same Accept header used by both Safari and Google Chrome
    IE8 = 'image/jpeg, application/x-ms-application, image/gif, application/xaml+xml, image/pjpeg, application/x-ms-xbap, application/x-shockwave-flash, application/msword, */*'

    def setUp(self):
        self.request = HttpRequest()

        # add content negotiation to test view defined above for testing
        decorator = content_negotiation({'application/xml': xml_view})
        self.negotiated_view = decorator(html_view)

    def test_default(self):
        # no accept header specified - should use default view
        response = self.negotiated_view(self.request)
        self.assertEqual("HTML", response.content)
        self.assertEqual('Accept', response['vary'],
            "response should have a 'Vary: Accept' header")

    def test_custom_default(self):
        # no accept header, should return user specified default view.

        decorator = content_negotiation({'application/xml': xml_view, 'text/html': html_view}, default_type="application/json")