# -*- coding: utf-8 -*-
# Copyright (C) 2016, Simone Marsili (simo.marsili@gmail.com)
# License: BSD 3 clause
"""Utility functions."""

from __future__ import (absolute_import, division,
                        print_function, unicode_literals)
from builtins import (  # pylint: disable=redefined-builtin, unused-import
    bytes, dict, int, list, object, range, str,
    ascii, chr, hex, input, next, oct, open,
    pow, round, super,
    filter, map, zip)
import logging
import functools

__all__ = [
    'generic_open',
    'is_command',
]


def generic_open(source):
    """Returns a file object from a path or a file descriptor or a file object.
    File won't be closed.
    (Adapted from svmlight_format.py).

    Parameters
    ----------
    source : {str, int, file-like}
        (Path to) file/file descriptor/file object.
        If `source` has ".gz" or ".bz2" extension, decompress.

    Returns
    -------
    file: file-like

    """
    import os
    import io
    import six
    import codecs

    if hasattr(source, 'read'):
        return source
    if isinstance(source, int):  # file descriptor
        try:
            return io.open(source, 'r', closefd=False)
        except OSError:
            raise OSError('Cant open file file descriptor %s', source)
    elif not isinstance(source, six.string_types):
        raise TypeError('Expected {str, int, file-like}, '
                        'got %s' % type(source))

    _, ext = os.path.splitext(source)
    try:
        if ext == '.gz':
            import gzip
            # return io.TextIOWrapper(gzip.open(source, 'r'))
            return codecs.getreader('utf-8')(gzip.open(source, 'r'))
        elif ext == '.bz2':
            from bz2 import BZ2File
            # return io.TextIOWrapper(BZ2File(source, 'r'))
            return codecs.getreader('utf-8')(BZ2File(source, 'r'))
        else:
            return open(source, 'r')
    except IOError:
        raise IOError('File: %s not found', source)


def is_command(cmds):
    """Given one command returns its path, or None.
    Given a list of commands returns the first recoverable path, or None.
    """
    try:
        from shutil import which as which  # python3 only
    except ImportError:
        from distutils.spawn import find_executable as which

    if isinstance(cmds, str):
        return which(cmds)
    else:
        for cmd in cmds:
            path = which(cmd)
            if path is not None:
                return path
        return path


def open_tempfile():
    import tempfile
    tempfile = tempfile.NamedTemporaryFile
    kwargs = {'delete': True,
              'mode': 'r+'}
    return tempfile(**kwargs)


def timeit(func):
    """Timeit decorator."""
    @functools.wraps(func)
    def timed(*args, **kwargs):
        import time
        ts0 = time.time()
        result = func(*args, **kwargs)
        ts1 = time.time()
        logging.debug('%r: %2.4f secs', func, ts1 - ts0)
        return result
    return timed


def config_loggers():
    # set log messages
    # add_loglevel_notes()
    logging.basicConfig(
        # filename=logname,
        # filemode='a',
        format='%(module)-10s %(funcName)-20s: %(levelname)-8s %(message)s',
        datefmt='%H:%M:%S',
        # level=logging.DEBUG)
        level=logging.WARNING)
    # add_notes_handler()


def add_loglevel_notes():
    '''Add a loglevel "notes".'''
    logging.NOTES = 25
    logging.addLevelName(logging.NOTES, "NOTES")

    def notes(self, message, *args, **kws):
        if self.isEnabledFor(logging.NOTES):
            self._log(logging.NOTES, message, args, **kws)

    logging.Logger.notes = notes


def add_notes_handler():
    '''Add a loglevel "notes".'''
    # add a separate handler for notes
    handler = logging.FileHandler('skmsa.log')
    handler.setLevel(logging.NOTES)
    # set a very clean format
    formatter = logging.Formatter('%(message)s')
    handler.setFormatter(formatter)
    logging.getLogger('').addHandler(handler)


def get_version():
    import os
    import json
    path_to_version = os.path.join(os.path.dirname(__file__), 'version.json')
    with open(path_to_version, 'r') as f:
        version_data = json.load(f)
        try:
            return version_data['version']
        except KeyError:
            # no version number in version.json
            raise KeyError('check version file: no version number')
