import sys
import os
import codecs
import time
import socket
import quixote
from quixote.sendmail import sendmail

class DefaultLogger:
    """
    This is the default logger object used by the Quixote publisher.  It
    controls access log and error log behavior.  You may provide your own
    object if you wish to have different behavior.

    Instance attributes:

      access_log : file | None
        file to which every access will be logged.  If None then access
        is not logged.
      error_log : file
        file to which application errors (exceptions caught by Quixote,
        as well as anything printed to stderr by application code) will
        be logged.  Set to sys.stderr by default.
      error_email : string | None
        if set then internal server errors will cause messages to be sent to
        this address
    """

    DEFAULT_CHARSET = None # defaults to quixote.DEFAULT_CHARSET

    def __init__(self, access_log=None, error_log=None, error_email=None):
        if access_log:
            self.access_log = self._open_log(access_log)
        else:
            self.access_log = None
        if error_log is None:
            self.error_log = sys.stderr
        else:
            self.error_log = self._open_log(error_log)
        self.error_email = error_email
        sys.stdout = self.error_log # print is handy for debugging

    def _open_log(self, filename):
        charset = self.DEFAULT_CHARSET or quixote.DEFAULT_CHARSET
        if charset == 'iso-8859-1':
            return open(filename, 'ab', 1)
        else:
            return codecs.open(filename, 'ab',
                               encoding=charset,
                               buffering=1)

    def log(self, msg):
        """
        Write an message to the error log with a time stamp.
        """
        timestamp = time.strftime("%Y-%m-%d %H:%M:%S",
                                  time.localtime(time.time()))
        self.error_log.write("[%s] %s%s" % (timestamp, msg, os.linesep))

    def log_internal_error(self, error_summary, error_msg):
        """(error_summary: str, error_msg: str)

        error_summary is a single line summary of the internal error, suitable
        for an email subject.  error_msg is a multi-line plaintext message
        describing the error in detail.
        """
        self.log("exception caught")
        self.error_log.write(error_msg)
        if self.error_email:
            sendmail('Quixote Traceback (%s)' % error_summary,
                     error_msg, [self.error_email],
                     from_addr=(self.error_email, socket.gethostname()))

    def log_request(self, request, start_time):
        """Log a request in the access_log file.
        """
        if self.access_log is None:
            return
        if request.session:
            user = request.session.user or "-"
        else:
            user = "-"
        now = time.time()
        seconds = now - start_time
        timestamp = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(now))

        request_uri = request.get_path()
        query = request.get_query()
        if query:
            request_uri += "?" + query
        proto = request.get_environ('SERVER_PROTOCOL')
        self.access_log.write('%s %s %s %d "%s %s %s" %s %r %0.2fsec%s' %
                               (request.get_environ('REMOTE_ADDR'),
                                user,
                                timestamp,
                                os.getpid(),
                                request.get_method(),
                                request_uri,
                                proto,
                                request.response.status_code,
                                request.get_environ('HTTP_USER_AGENT', ''),
                                seconds,
                                os.linesep,
                               ))
