"""quixote.errors

Exception classes used by Quixote
"""

class PublishError (Exception):
    """PublishError exceptions are raised due to some problem with the
    data provided by the client and are raised during the publishing
    process.  Quixote will abort the current request and return an error
    to the client.  The error returned to the client is controlled by the
    format method.

    The formatting done by the Quixote versions of these exceptions is
    very simple.  Applications will probably wish to raise application
    specific subclasses which do more sophisticated formatting.
    """

    def format (self, request):
        """format(request : HTTPRequest) -> string

        Called by Quixote to return a response to the user.
        """
        raise NotImplementedError


class TraversalError (PublishError):
    """Raised when a URL attempts to traverse to a bogus or non- existent
    Python namespace (from quixote.publish or from __getname__ methods).
    There are a number of reasons why this can happen, so these exceptions
    should have a clear and explicit message explaining the problem.
    However, that can reveal valuable information to attackers, so the
    'format()' method here will hide that useful information if the
    configuration variable SECURE_ERRORS is true.
    """

    # XXX it should be possible to make publish raise an application
    # specific subclass of this exception

    def __init__ (self, path, msg=None):
        self.path = path
        self.msg = msg # an optional, more detailed message

    def __str__ (self):
        if self.msg:
            return "%s: %s" % (self.path, self.msg)
        else:
            return self.path

    def format (self, request):
        from cgi import escape
        from quixote.config import config
        request.response.setStatus(404)
        page = "<html><body>%s</body></htm>" # this should go in a template
        if not config.secure_errors:
            msg = 'Resource "%s" not found: %s' % (self.path, self.msg)
        else:
            msg = 'Resource "%s" not found.' % self.path
        return page % escape(msg)


class QueryError (PublishError):
    """Should be raised raised if bad data provided in the query part of a
    URL or in the content of a POST request.  What constitutes bad data is
    solely application dependent (eg: letters in a form field when the
    application expects a number).

    The formatting done by this exception is very simple.  Applications
    will probably wish to raise subclasses which do more sophisticated
    formatting.
    """

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

    def format (self, request):
        request.response.setHeader("Content-Type", "text/plain")
        return self.msg


class AccessError (PublishError):
    """Should be raised raised if the client does not have access to the
    requested resource.  Usually applications will raise this error from
    an __access__ method.
    """

    def __init__ (self, msg=None):
        self.msg = msg or "access denied"
    
    def __str__ (self):
        return self.msg

    def format (self, request):
        request.response.setHeader("Content-Type", "text/plain")
        request.response.setStatus(403) # Forbidden, is this the right status?
        return self.msg
    

