"""Define tensorpac logger.

See :
https://stackoverflow.com/questions/384076/how-can-i-color-python-logging-output
"""
import logging
import sys
import re

BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
RESET_SEQ = "\033[0m"
COLOR_SEQ = "\033[1;%dm"
BOLD_SEQ = "\033[1m"
COLORS = {
    'DEBUG': GREEN,
    'PROFILER': MAGENTA,
    'INFO': WHITE,
    'WARNING': YELLOW,
    'ERROR': RED,
    'CRITICAL': RED,
}
FORMAT = {'compact': "$BOLD%(levelname)s | %(message)s",
          'spacy': "$BOLD%(levelname)-19s$RESET | %(message)s",
          'tensorpac': "$BOLD%(name)s-%(levelname)-19s$RESET | %(message)s",
          'print': "%(message)s",
          }


def formatter_message(message, use_color=True):
    """Format the message."""
    return message.replace("$RESET", RESET_SEQ).replace("$BOLD", BOLD_SEQ)


class _Formatter(logging.Formatter):
    """Formatter."""

    def __init__(self, format_type='compact'):
        logging.Formatter.__init__(self, FORMAT[format_type])
        self._format_type = format_type

    def format(self, record):
        name = record.levelname
        msg = record.getMessage()
        # If * in msg, set it in RED :
        if '*' in msg:
            regexp = '\*.*?\*'
            re_search = re.search(regexp, msg).group()
            to_color = COLOR_SEQ % (30 + RED) + re_search + COLOR_SEQ % (
                30 + WHITE) + RESET_SEQ
            msg_color = re.sub(regexp, to_color, msg)
            msg_color += RESET_SEQ
            record.msg = msg_color
        # Set level color :
        levelname_color = COLOR_SEQ % (30 + COLORS[name]) + name + RESET_SEQ
        record.levelname = levelname_color
        if record.levelno == 20:
            logging.Formatter.__init__(self, FORMAT['print'])
        else:
            logging.Formatter.__init__(self, FORMAT[self._format_type])
        return formatter_message(logging.Formatter.format(self, record))


class _StreamHandler(logging.StreamHandler):
    """Stream handler allowing matching and recording."""

    def __init__(self):
        logging.StreamHandler.__init__(self, sys.stderr)
        self.setFormatter(_lf)
        self._str_pattern = None
        self.emit = self._tensorpac_emit

    def _tensorpac_emit(self, record, *args):
        msg = record.getMessage()
        test = self._match_pattern(record, msg)
        if test:
            record.msg = test
            return logging.StreamHandler.emit(self, record)
        else:
            return

    def _match_pattern(self, record, message):
        if isinstance(self._str_pattern, str):
            if re.search(self._str_pattern, message):
                sub = '*{}*'.format(self._str_pattern)
                return re.sub(self._str_pattern, sub, message)
            else:
                return ''
        else:
            return message


logger = logging.getLogger('tensorpac')
_lf = _Formatter()
_lh = _StreamHandler()  # needs _lf to exist
logger.addHandler(_lh)
PROFILER_LEVEL_NUM = 1
logging.addLevelName(PROFILER_LEVEL_NUM, "PROFILER")


def profiler_fcn(self, message, *args, **kws):
    # Yes, logger takes its '*args' as 'args'.
    if self.isEnabledFor(PROFILER_LEVEL_NUM):
        self._log(PROFILER_LEVEL_NUM, message, args, **kws)


logging.Logger.profiler = profiler_fcn
LOGGING_TYPES = dict(DEBUG=logging.DEBUG, INFO=logging.INFO,
                     WARNING=logging.WARNING, ERROR=logging.ERROR,
                     CRITICAL=logging.CRITICAL, PROFILER=PROFILER_LEVEL_NUM)


def set_log_level(verbose=None, match=None):
    """Convenience function for setting the logging level.

    This function comes from the PySurfer package. See :
    https://github.com/nipy/PySurfer/blob/master/surfer/utils.py

    Parameters
    ----------
    verbose : bool, str, int, or None
        The verbosity of messages to print. If a str, it can be either
        PROFILER, DEBUG, INFO, WARNING, ERROR, or CRITICAL.
    match : string | None
        Filter logs using a string pattern.
    """
    # if verbose is None:
    #     verbose = "INFO"
    logger = logging.getLogger('tensorpac')
    if isinstance(verbose, bool):
        verbose = 'INFO' if verbose else 'WARNING'
    if isinstance(verbose, str):
        if (verbose.upper() in LOGGING_TYPES):
            verbose = verbose.upper()
            verbose = LOGGING_TYPES[verbose]
            logger.setLevel(verbose)
        else:
            raise ValueError("verbose must be in "
                             "%s" % ', '.join(LOGGING_TYPES))
    if isinstance(match, str):
        _lh._str_pattern = match


def progress_bar(value, endvalue, bar_length=20, pre_st=None):
    """Progress bar."""
    percent = float(value) / endvalue
    arrow = '-' * int(round(percent * bar_length) - 1) + '>'
    spaces = ' ' * (bar_length - len(arrow))
    pre_st = '' if not isinstance(pre_st, str) else pre_st

    sys.stdout.write("\r{0} [{1}] {2}%".format(pre_st, arrow + spaces,
                                               int(round(percent * 100))))
    sys.stdout.flush()


def is_pandas_installed():
    """Test if pandas is installed."""
    try:
        import pandas  # noqa
    except:
        raise IOError("pandas not installed. See https://pandas.pydata.org/"
                      "pandas-docs/stable/install.html")


def is_statsmodels_installed():
    """Test if statsmodels is installed."""
    try:
        import statsmodels  # noqa
    except:
        raise IOError("statsmodels not installed. See http://www.statsmodels."
                      "org/stable/install.html")
