import logging
import pprint

debug_mode_enabled = False

_logger      = None
_log_handler = None


def log(level, *args, **kwargs):
    global debug_mode_enabled
    global _logger

    if not _logger:
        prepare_logger(logging.DEBUG if debug_mode_enabled else logging.ERROR)

    getattr(_logger, level)(*args, **kwargs)


def prepare_logger(level = logging.ERROR, use_fancy_format = False):
    global _logger
    global _log_handler

    if not _logger:
        _logger = logging.Logger('vireo')

    if not _log_handler:
        try:
            # Python 3
            formatter = logging.Formatter(
                '{asctime} | {name} | [{levelname}] {message}'
                if use_fancy_format
                else '{asctime} | [{levelname}] {message}',
                style='{'
            )
        except TypeError:
            # Python 2
            formatter = logging.Formatter(
                '$(name)a | [%(levelname)s] %(message)s'
                if use_fancy_format
                else '[%(levelname)s] %(message)s'
            )

        _log_handler = logging.StreamHandler()
        _log_handler.setFormatter(formatter)

        _logger.addHandler(_log_handler)

    _logger.setLevel(level)
    _log_handler.setLevel(level)

    return _logger

def fill_in_the_blank(main_dict, default_dict):
    for default_key, default_value in default_dict.items():
        if default_key in main_dict:
            continue

        main_dict[default_key] = default_value

    return main_dict

def inspect_object(obj):
    pprint.pprint(dehydrate_object(obj))

def dehydrate_object(obj, depth = 0, max_depth = 2):
    if depth > max_depth:
        return obj

    if callable(obj):
        return obj

    if isinstance(obj, (int, str, bytes, float, bool)):
        return obj

    if isinstance(obj, (list, tuple)):
        return [
            dehydrate_object(item, depth + 1)
            for item in obj
            if not callable(item)
        ]

    if isinstance(obj, dict):
        return {
            k: dehydrate_object(v, depth + 1)
            for k, v in obj.items()
            if not callable(v)
        }

    dehydrated_object = {
        '_class': '.'.join([type(obj).__module__, type(obj).__name__])
    }

    for property_name in dir(obj):
        if property_name[0] == '_':
            continue

        property_value = getattr(obj, property_name)

        dehydrated_object[property_name] = dehydrate_object(property_value, depth + 1)

    return dehydrated_object
