# w.c.s. - web application for online forms
# Copyright (C) 2005-2010  Entr'ouvert
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, see <http://www.gnu.org/licenses/>.

import logging
import os

from django.utils import six

from quixote import get_publisher, get_session, get_request
from quixote.logger import DefaultLogger


class ApplicationLogger(DefaultLogger):
    def log_internal_error(self, error_summary, error_msg, tech_id=None):
        self.log('exception caught')
        self.error_log.write(error_msg)
        if self.error_email:
            from .emails import email
            headers = {}
            if tech_id:
                headers['References'] = '<%s@%s>' % (tech_id, os.path.basename(get_publisher().app_dir))
            email(subject='[ERROR] %s' % error_summary,
                  mail_body=error_msg,
                  email_from=self.error_email,
                  email_rcpt=[self.error_email],
                  want_html=False,
                  fire_and_forget=True,
                  extra_headers=headers)


class BotFilter(logging.Filter):
    def filter(self, record):
        if record.levelno >= logging.ERROR:
            # always log errors
            return 1
        if self.is_bot():
            return 0
        return 1

    @classmethod
    def is_bot(cls):
        botfile = os.path.join(get_publisher().data_dir, 'webbots')
        if os.path.exists(botfile) and get_request():
            user_agent = get_request().get_environ('HTTP_USER_AGENT', '')
            for bot_ua_string in [x.strip() for x in open(botfile).readlines()]:
                if bot_ua_string in user_agent:
                    return True
        return False


class Formatter(logging.Formatter):
    def format(self, record):
        request = get_request()
        if request:
            record.address = request.get_environ('REMOTE_ADDR', '-')
            record.path = request.get_path()

            user = request.user
            if user:
                if isinstance(user, six.string_types + six.integer_types):
                    user_id = user
                else:
                    user_id = user.id
                    if type(user_id) is str and user_id.startswith('anonymous-'):
                        user_id = 'anonymous'
            else:
                user_id = 'unlogged'
                if BotFilter.is_bot():
                    user_id = 'bot'
            record.user_id = user_id
        else:
            record.address = '-'
            record.path = '-'
            record.user_id = 'unlogged'
        record.session_id = (get_request() and get_session() and \
                get_session().get_session_id()) or '[nosession]'

        return logging.Formatter.format(self, record) \
                .replace('\n', '\n ')


def parse_logstream(stream):
    '''
    Parse a stream of lines making a log file, each log line start with a
    non-blank character continue until the lines does not start with a blank
    character
    '''
    line = next(stream)
    while True:
        r = readline(line)
        try:
            # Skip badly formatted lines
            if r is None:
                line = next(stream)
                continue
            while True:
                line = next(stream)
                if line.startswith(' '):
                    # Append the line without the first blank
                    r['message'] = r['message'] + line[1:]
                    continue
                break
        except StopIteration:
            # Ont last line return the current one
            if r is not None:
                r['message'] = r['message'].strip()
                yield r
            break
        r['message'] = r['message'].strip()
        yield r

def readline(line):
    if not line:
        return None
    try:
        date, hour, level, ip, session_id, url, user_id, dash, message = line.split(' ', 8)
    except ValueError:
        try:
            date, hour, level, message = line.split(' ', 3)
        except ValueError:
            return None  # misformatted line
        del line
        return locals()
    if dash != '-':
        return None
    del line
    return locals()
