# (c) 2005 Ian Bicking and contributors; written for Paste (http://pythonpaste.org)
# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php

"""
Error handler middleware
"""
import sys
import traceback
import cgi
try:
    from cStringIO import StringIO
except ImportError:
    from StringIO import StringIO
from paste.exceptions import formatter, collector, reporter
from paste import wsgilib
from paste import request

__all__ = ['ErrorMiddleware', 'handle_exception']

class _NoDefault(object):
    def __repr__(self):
        return '<NoDefault>'
NoDefault = _NoDefault()

class ErrorMiddleware(object):

    """
    Error handling middleware
    
    Usage::

        error_catching_wsgi_app = ErrorMiddleware(wsgi_app)

    Settings:

      ``debug``:
          If true, then tracebacks will be shown in the browser.

      ``error_email``:
          an email address (or list of addresses) to send exception 
          reports to

      ``error_log``:
          a filename to append tracebacks to

      ``show_exceptions_in_wsgi_errors``:
          If true, then errors will be printed to ``wsgi.errors`` 
          (frequently a server error log, or stderr).

      ``from_address``, ``smtp_server``, ``error_subject_prefix``, ``smtp_username``, ``smtp_password``, ``smtp_use_tls``:
          variables to control the emailed exception reports

      ``error_message``:
          When debug mode is off, the error message to show to users.

      ``xmlhttp_key``:
          When this key (default ``_``) is in the request GET variables
          (not POST!), expect that this is an XMLHttpRequest, and the
          response should be more minimal; it should not be a complete
          HTML page.

    Environment Configuration:
    
      ``paste.throw_errors``:
          If this setting in the request environment is true, then this
          middleware is disabled. This can be useful in a testing situation
          where you don't want errors to be caught and transformed.

      ``paste.expected_exceptions``:
          When this middleware encounters an exception listed in this
          environment variable and when the ``start_response`` has not 
          yet occurred, the exception will be re-raised instead of being
          caught.  This should generally be set by middleware that may 
          (but probably shouldn't be) installed above this middleware, 
          and wants to get certain exceptions.  Exceptions raised after
          ``start_response`` have been called are always caught since
          by definition they are no longer expected.

    """

    def __init__(self, application, global_conf=None,
                 debug=NoDefault,
                 error_email=None,
                 error_log=None,
                 show_exceptions_in_wsgi_errors=NoDefault,
                 from_address=None,
                 smtp_server=None,
                 smtp_username=None,
                 smtp_password=None,
                 smtp_use_tls=False,
                 error_subject_prefix=None,
                 error_message=None,
                 xmlhttp_key=None):
        from paste.util import converters
        self.application = application
        # @@: global_conf should be handled elsewhere in a separate
        # function for the entry point
        if global_conf is None:
            global_conf = {}
        if debug is NoDefault:
            debug = converters.asbool(global_conf.get('debug'))
        if show_exceptions_in_wsgi_errors is NoDefault:
            show_exceptions_in_wsgi_errors = converters.asbool(global_conf.get('show_exceptions_in_wsgi_errors'))
        self.debug_mode = converters.asbool(debug)