from django.core.handlers import wsgi, modpython

class FlushableWrapper:

    def __init__(self, wrapped):
        self.wrapped = wrapped

    def flush(self):
        pass

    def __getattr__(self, name):
        return getattr(self.wrapped, name)

class CgitbUncaughtExceptionMixin:

    """If settings.DEBUG is True, handle uncaught exceptions by showing a cgitb
    traceback display rather than a Django traceback display.  (The false
    settings.DEBUG case is unchanged over the default Django behaviour -- try
    to show a friendly 'Whoops, something went wrong' message.)

    """

    def get_technical_error_response(self, request, is404=False, exception=None):
        from django.views import debug
        if is404:
            return debug.technical_404_response(request, exception)
        else:
            import cgitb
            from django.http import HttpResponse
            response = FlushableWrapper(HttpResponse())
            hook = cgitb.Hook(file=response).handle()
            return response
class CgitbUncaughtExceptionWsgiHandler(CgitbUncaughtExceptionMixin, wsgi.WSGIHandler):
    pass
class CgitbUncaughtExceptionModPythonHandler(CgitbUncaughtExceptionMixin, modpython.ModPythonHandler):
    pass

class PlainUncaughtExceptionMixin:

    """As for CgitbUncaughtExceptionMixin, but plain traceback inside
    <pre></pre> tags instead of the pretty cgitb display.

    """

    def get_technical_error_response(self, request, is404=False, exception=None):
        from django.views import debug
        if is404:
            return debug.technical_404_response(request, exception)
        else:
            from django.http import HttpResponse
            import traceback
            doc = ''.join(traceback.format_exception(*sys.exc_info()))
            response = HttpResponse()
            response.write('<pre>%s</pre>' % doc)
            return response
class PlainUncaughtExceptionWsgiHandler(PlainUncaughtExceptionMixin, wsgi.WSGIHandler):
    pass
class PlainUncaughtExceptionModPythonHandler(PlainUncaughtExceptionMixin, modpython.ModPythonHandler):
    pass


# These install* functions don't monkeypatch the mod_python handler (the wsgi
# monkeypatch is unavoidable) since it's better to install it in httpd.conf:

# PythonHandler rldjango.common.tracebackhandlers.CgitbUncaughtExceptionModPythonHandler
# or
# PythonHandler rldjango.common.tracebackhandlers.PlainUncaughtExceptionModPythonHandler

# If for some reason that's no good, monkeypatch would be done this way:
##     def handler(req):
##         return CgitbUncaughtExceptionModPythonHandler()(req)
##     modpython.handler = handler

def installCgitbHandlers():
    """Monkeypatch development server to use cgitb instead of Django's built-in tracback display.

    This only has any effect when settings.DEBUG is true.
    """
    wsgi.WSGIHandler = CgitbUncaughtExceptionWsgiHandler

def installPlainTracebackHandlers():
    """Monkeypatch development server to use module traceback instead of Django's built-in tracback display.

    This only has any effect when settings.DEBUG is true.
    """
    wsgi.WSGIHandler = PlainUncaughtExceptionWsgiHandler
