# Copyright (C) 2009 Bruno Tarquini <btarquini AT gmail.com>
#
# This file is part of Gajim.
#
# Gajim 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; version 3 only.
#
# Gajim 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 Gajim. If not, see <http://www.gnu.org/licenses/>.

import logging
import os
import sys
import time
from datetime import datetime

from gajim.common import app
from gajim.common import configpaths
from gajim.common.i18n import _

def parseLogLevel(arg):
    """
    Either numeric value or level name from logging module
    """
    if arg.isdigit():
        return int(arg)
    if arg.isupper() and hasattr(logging, arg):
        return getattr(logging, arg)
    print(_('%s is not a valid loglevel') % repr(arg), file=sys.stderr)
    return 0

def parseLogTarget(arg):
    """
    [gajim.]c.x.y  ->  gajim.c.x.y
    .other_logger  ->  other_logger
    <None>         ->  gajim
    """
    arg = arg.lower()
    if not arg:
        return 'gajim'
    if arg.startswith('.'):
        return arg[1:]
    if arg.startswith('gajim'):
        return arg
    return 'gajim.' + arg

def parseAndSetLogLevels(arg):
    """
    [=]LOGLEVEL     ->  gajim=LOGLEVEL
    gajim=LOGLEVEL  ->  gajim=LOGLEVEL
    .other=10       ->  other=10
    .=10            ->  <nothing>
    c.x.y=c.z=20    ->  gajim.c.x.y=20
                        gajim.c.z=20
    gajim=10,c.x=20 ->  gajim=10
                        gajim.c.x=20
    """
    for directive in arg.split(','):
        directive = directive.strip()
        if not directive:
            continue
        if '=' not in directive:
            directive = '=' + directive
        targets, level = directive.rsplit('=', 1)
        level = parseLogLevel(level.strip())
        for target in targets.split('='):
            target = parseLogTarget(target.strip())
            if target:
                logging.getLogger(target).setLevel(level)
                print("Logger %s level set to %d" % (target, level),
                      file=sys.stderr)


class colors:
    # pylint: disable=C0326
    NONE         = chr(27) + "[0m"
    BLACk        = chr(27) + "[30m"
    RED          = chr(27) + "[31m"
    GREEN        = chr(27) + "[32m"
    BROWN        = chr(27) + "[33m"
    BLUE         = chr(27) + "[34m"
    MAGENTA      = chr(27) + "[35m"
    CYAN         = chr(27) + "[36m"
    LIGHT_GRAY   = chr(27) + "[37m"
    DARK_GRAY    = chr(27) + "[30;1m"
    BRIGHT_RED   = chr(27) + "[31;1m"
    BRIGHT_GREEN = chr(27) + "[32;1m"
    YELLOW       = chr(27) + "[33;1m"
    BRIGHT_BLUE  = chr(27) + "[34;1m"
    PURPLE       = chr(27) + "[35;1m"
    BRIGHT_CYAN  = chr(27) + "[36;1m"
    WHITE        = chr(27) + "[37;1m"

def colorize(text, color):
    return color + text + colors.NONE

class FancyFormatter(logging.Formatter):
    """
    An eye-candy formatter with colors
    """
    colors_mapping = {
        'DEBUG': colors.BLUE,
        'INFO': colors.GREEN,
        'WARNING': colors.BROWN,
        'ERROR': colors.RED,
        'CRITICAL': colors.BRIGHT_RED,
    }

    def __init__(self, fmt, datefmt=None, use_color=False):
        logging.Formatter.__init__(self, fmt, datefmt)
        self.use_color = use_color

    def formatTime(self, record, datefmt=None):
        f = logging.Formatter.formatTime(self, record, datefmt)
        if self.use_color:
            f = colorize(f, colors.DARK_GRAY)
        return f

    def format(self, record):
        level = record.levelname
        record.levelname = '(%s)' % level[0]

        if self.use_color:
            c = FancyFormatter.colors_mapping.get(level, '')
            record.levelname = colorize(record.levelname, c)
            record.name = '%-25s' % colorize(record.name, colors.CYAN)
        else:
            record.name = '%-25s|' % record.name

        return logging.Formatter.format(self, record)


def init():
    """
    Iinitialize the logging system
    """

    if app.get_debug_mode():
        _cleanup_debug_logs()
        _redirect_output()

    use_color = False
    if os.name != 'nt':
        use_color = sys.stderr.isatty()

    consoleloghandler = logging.StreamHandler()
    consoleloghandler.setFormatter(
        FancyFormatter(
            '%(asctime)s %(levelname)s %(name)-35s %(message)s',
            '%x %H:%M:%S',
            use_color
        )
    )

    root_log = logging.getLogger('gajim')
    root_log.setLevel(logging.WARNING)
    root_log.addHandler(consoleloghandler)
    root_log.propagate = False

    root_log = logging.getLogger('nbxmpp')
    root_log.setLevel(logging.WARNING)
    root_log.addHandler(consoleloghandler)
    root_log.propagate = False

    root_log = logging.getLogger('gnupg')
    root_log.setLevel(logging.WARNING)
    root_log.addHandler(consoleloghandler)
    root_log.propagate = False

    # GAJIM_DEBUG is set only on Windows when using Gajim-Debug.exe
    # Gajim-Debug.exe shows a command line prompt and we want to redirect
    # log output to it
    if app.get_debug_mode() or os.environ.get('GAJIM_DEBUG', False):
        set_verbose()

def set_loglevels(loglevels_string):
    parseAndSetLogLevels(loglevels_string)

def set_verbose():
    parseAndSetLogLevels('gajim=DEBUG')
    parseAndSetLogLevels('.nbxmpp=INFO')

def set_quiet():
    parseAndSetLogLevels('gajim=CRITICAL')
    parseAndSetLogLevels('.nbxmpp=CRITICAL')


def _redirect_output():
    debug_folder = configpaths.get('DEBUG')
    date = datetime.today().strftime('%d%m%Y-%H%M%S')
    filename = '%s-debug.log' % date
    fd = open(debug_folder / filename, 'a')
    sys.stderr = sys.stdout = fd


def _cleanup_debug_logs():
    debug_folder = configpaths.get('DEBUG')
    debug_files = list(debug_folder.glob('*-debug.log*'))
    now = time.time()
    for file in debug_files:
        # Delete everything older than 3 days
        if file.stat().st_ctime < now - 259200:
            file.unlink()



# tests
if __name__ == '__main__':
    init()

    set_loglevels('gajim.c=DEBUG,INFO')

    log = logging.getLogger('gajim')
    log.debug('debug')
    log.info('info')
    log.warning('warn')
    log.error('error')
    log.critical('critical')

    log = logging.getLogger('gajim.c.x.dispatcher')
    log.debug('debug')
    log.info('info')
    log.warning('warn')
    log.error('error')
    log.critical('critical')
