from collections import defaultdict
import contextlib
import logging
import sys
import warnings
from ..fileio.adm.exceptions import AdmUnknownAttribute


class LimitedWarningPrint:
    """Utility to print a given number of warnings per line; to use, replace
    warnings.showwarning with self.showwarning.
    """

    def __init__(self, logger: logging.Logger, max_per_line=5):
        self.logger = logger
        self.max_per_line = max_per_line
        self.counts = defaultdict(lambda: 0)

    def showwarning(self, message, category, filename, lineno, file=None, line=None):
        self.counts[(filename, lineno)] += 1
        count = self.counts[(filename, lineno)]

        if count <= self.max_per_line:
            self.logger.warning(message)
        if count == self.max_per_line:
            self.logger.warning(
                "suppressing further messages like the above; use --debug to show more"
            )


@contextlib.contextmanager
def error_handler(logger: logging.Logger, debug: bool = False, strict: bool = False):
    """Context manager for use in CLIs which handles logging of exceptions and
    warnings.

    Parameters:
        logger: log to write to
        debug: should we be more verbose, printing full exceptions
        strict: turn unknown attribute warnings into errors
    """
    # debug: print every warning in full
    # no debug: just print message, stop after n
    if debug:

        def showwarning(message, category, filename, lineno, file=None, line=None):
            category = category.__name__
            msg = f"{filename}:{lineno}: {category}: {message}"
            logger.warning(msg)

    else:
        showwarning = LimitedWarningPrint(logger).showwarning

    try:
        with warnings.catch_warnings():
            warnings.showwarning = showwarning  # documentation says this is allowed
            if strict:
                warnings.filterwarnings("error", category=AdmUnknownAttribute)
            yield
    except Exception as error:
        if debug:
            raise
        else:
            logger.error(error)
            sys.exit(1)

from collections import defaultdict
import contextlib
import logging
import sys
import warnings
from ..fileio.adm.exceptions import AdmUnknownAttribute


class LimitedWarningPrint:
    """Utility to print a given number of warnings per line; to use, replace
    warnings.showwarning with self.showwarning.
    """

    def __init__(self, logger: logging.Logger, max_per_line=5):
        self.logger = logger
        self.max_per_line = max_per_line
        self.counts = defaultdict(lambda: 0)

    def showwarning(self, message, category, filename, lineno, file=None, line=None):
        self.counts[(filename, lineno)] += 1
        count = self.counts[(filename, lineno)]

        if count <= self.max_per_line:
            self.logger.warning(message)
        if count == self.max_per_line:
            self.logger.warning(
                "suppressing further messages like the above; use --debug to show more"
            )


@contextlib.contextmanager
def error_handler(logger: logging.Logger, debug: bool = False, strict: bool = False):
    """Context manager for use in CLIs which handles logging of exceptions and
    warnings.

    Parameters:
        logger: log to write to
        debug: should we be more verbose, printing full exceptions
        strict: turn unknown attribute warnings into errors
    """
    # debug: print every warning in full
    # no debug: just print message, stop after n
    if debug:

        def showwarning(message, category, filename, lineno, file=None, line=None):
            category = category.__name__
            msg = f"{filename}:{lineno}: {category}: {message}"
            logger.warning(msg)

    else:
        showwarning = LimitedWarningPrint(logger).showwarning

    try:
        with warnings.catch_warnings():
            warnings.showwarning = showwarning  # documentation says this is allowed
            if strict:
                warnings.filterwarnings("error", category=AdmUnknownAttribute)
            yield
    except Exception as error:
        if debug:
            raise
        else:
            logger.error(error)
            sys.exit(1)

Utility to print a given number of warnings per line; to use, replace     warnings.showwarning with self.showwarning. Context manager for use in CLIs which handles logging of exceptions and     warnings.      Parameters:         logger: log to write to         debug: should we be more verbose, printing full exceptions         strict: turn unknown attribute warnings into errors # debug: print every warning in full # no debug: just print message, stop after n # documentation says this is allowed