from __future__ import print_function, division, absolute_import
from fontTools.misc.py23 import *
from fontTools.misc.loggingTools import (
    LevelFormatter,
    Timer,
    configLogger,
    ChannelsFilter,
    LogMixin,
)
import logging
import textwrap
import time
import re
import pytest


def logger_name_generator():
    basename = "fontTools.test#"
    num = 1
    while True:
        yield basename+str(num)
        num += 1

unique_logger_name = logger_name_generator()


@pytest.fixture
def logger():
    log = logging.getLogger(next(unique_logger_name))
    configLogger(logger=log, level="DEBUG", stream=StringIO())
    return log


def test_LevelFormatter():
    stream = StringIO()
    handler = logging.StreamHandler(stream)
    formatter = LevelFormatter(
        fmt={
            '*':     '[%(levelname)s] %(message)s',
            'DEBUG': '%(name)s [%(levelname)s] %(message)s',
            'INFO':  '%(message)s',
        })
    handler.setFormatter(formatter)
    name = next(unique_logger_name)
    log = logging.getLogger(name)
    log.setLevel(logging.DEBUG)
    log.addHandler(handler)

    log.debug("this uses a custom format string")
    log.info("this also uses a custom format string")
    log.warning("this one uses the default format string")

    assert stream.getvalue() == textwrap.dedent("""\
        %s [DEBUG] this uses a custom format string
        this also uses a custom format string
        [WARNING] this one uses the default format string
        """ % name)


class TimerTest(object):

    def test_split(self):
        timer = Timer()
        time.sleep(0.01)
        fist_lap =  timer.split()
        assert timer.elapsed == fist_lap
        time.sleep(0.1)
        second_lap = timer.split()
        assert second_lap > fist_lap
        assert timer.elapsed == second_lap

    def test_time(self):
        timer = Timer()
        time.sleep(0.01)
        overall_time = timer.time()
        assert overall_time > 0

    def test_context_manager(self):
        with Timer() as t:
            time.sleep(0.01)
        assert t.elapsed > 0

    def test_using_logger(self, logger):
        with Timer(logger, 'do something'):
            time.sleep(0.01)

        assert re.match(
            r"Took [0-9]\.[0-9]{3}s to do something",
            logger.handlers[0].stream.getvalue())

    def test_using_logger_calling_instance(self, logger):
        timer = Timer(logger)
        with timer():
            time.sleep(0.01)

        assert re.match(
            r"elapsed time: [0-9]\.[0-9]{3}s",
            logger.handlers[0].stream.getvalue())

        # do it again but with custom level
        with timer('redo it', level=logging.WARNING):
            time.sleep(0.02)

        assert re.search(
            r"WARNING: Took [0-9]\.[0-9]{3}s to redo it",
            logger.handlers[0].stream.getvalue())

    def test_function_decorator(self, logger):
        timer = Timer(logger)

        @timer()
        def test1():
            time.sleep(0.01)
        @timer('run test 2', level=logging.INFO)
        def test2():
            time.sleep(0.02)

        test1()

        assert re.match(
            r"Took [0-9]\.[0-9]{3}s to run 'test1'",
            logger.handlers[0].stream.getvalue())

        test2()

        assert re.search(
            r"Took [0-9]\.[0-9]{3}s to run test 2",
            logger.handlers[0].stream.getvalue())


def test_ChannelsFilter(logger):
    n = logger.name
    filtr = ChannelsFilter(n+".A.B", n+".C.D")
    handler = logger.handlers[0]
    handler.addFilter(filtr)
    stream = handler.stream

    logging.getLogger(n+".A.B").debug('this record passes through')
    assert 'this record passes through' in stream.getvalue()

    logging.getLogger(n+'.A.B.C').debug('records from children also pass')
    assert 'records from children also pass' in stream.getvalue()

    logging.getLogger(n+'.C.D').debug('this one as well')
    assert 'this one as well' in stream.getvalue()

    logging.getLogger(n+'.A.B.').debug('also this one')
    assert 'also this one' in stream.getvalue()

    before = stream.getvalue()
    logging.getLogger(n+'.A.F').debug('but this one does not!')
    assert before == stream.getvalue()

    logging.getLogger(n+'.C.DE').debug('neither this one!')
    assert before == stream.getvalue()


def test_LogMixin():

    class Base(object):
        pass

    class A(LogMixin, Base):
        pass

    class B(A):
        pass

    a = A()
    b = B()

    assert hasattr(a, 'log')
    assert hasattr(b, 'log')
    assert isinstance(a.log, logging.Logger)
    assert isinstance(b.log, logging.Logger)
    assert a.log.name == "loggingTools_test.A"
    assert b.log.name == "loggingTools_test.B"
