# coding: utf-8
# pylint: disable=C301,C0103,W0201

# Copyright 2015 by Leipzig University Library, http://ub.uni-leipzig.de
#                   The Finc Authors, http://finc.info
#                   Martin Czygan, <martin.czygan@uni-leipzig.de>
#
# This file is part of some open source application.
#
# Some open source application 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 3 of the License, or (at your option) any later version.
#
# Some open source application 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 Foobar.  If not, see <http://www.gnu.org/licenses/>.
#
# @license GPL-3.0+ <http://spdx.org/licenses/GPL-3.0+>

"""
Provides a basic benchmark decorator. Usage:

    @timed
    def run():
        print('Running...')

Just logs the output. Could be extended to send this information to some
service if available.
"""

import functools
import logging
from builtins import object
from timeit import default_timer

logger = logging.getLogger('gluish')


class bcolors(object):
    HEADER = '\033[95m'
    OKBLUE = '\033[94m'
    OKGREEN = '\033[92m'
    WARNING = '\033[93m'
    FAIL = '\033[91m'
    ENDC = '\033[0m'
    BOLD = '\033[1m'
    UNDERLINE = '\033[4m'


def red(s):
    return bcolors.FAIL + s + bcolors.ENDC


def yellow(s):
    return bcolors.WARNING + s + bcolors.ENDC


def green(s):
    return bcolors.OKGREEN + s + bcolors.ENDC


class Timer(object):
    """
    A timer as a context manager, slight visual language.
    """

    def __init__(self, green=10, yellow=60):
        """
        Indicate runtimes with colors, green < 10s, yellow < 60s.
        """
        # measures wall clock time, not CPU time!
        # On Unix systems, it corresponds to time.time
        # On Windows systems, it corresponds to time.clock
        self.timer = default_timer

        self.green = green
        self.yellow = yellow

    def __enter__(self):
        self.start = self.timer()
        return self

    def __exit__(self, exc_type, exc_value, exc_traceback):
        self.end = self.timer()
        self.elapsed_s = self.end - self.start
        self.elapsed_ms = self.elapsed_s * 1000


def timed(method):
    """
    A @timed decorator.
    """
    @functools.wraps(method)
    def _timed(*args, **kwargs):
        """
        Benchmark decorator.
        """
        with Timer() as timer:
            result = method(*args, **kwargs)
        klass = args[0].__class__.__name__
        fun = method.__name__

        msg = '[%s.%s] %0.5f' % (klass, fun, timer.elapsed_s)
        if timer.elapsed_s <= timer.green:
            logger.debug(green(msg))
        elif timer.elapsed_s <= timer.yellow:
            logger.debug(yellow(msg))
        else:
            logger.debug(red(msg))
        return result
    return _timed
