"""Logging related classes and functions."""

import gzip
import logging


class CompressedFileHandler(logging.FileHandler):
  """Compressed file handler for logging."""

  def __init__(self, filename, mode='a', encoding='utf-8'):
    """Initializes a compressed file logging handler.

    Args:
      filename (str): name of the log file.
      mode (Optional[str]): file access mode.
      encoding (Optional[str]): encoding of the log lines.
    """
    if 't' not in mode and encoding:
      mode = f'{mode:s}t'
    super().__init__(filename, mode=mode, encoding=encoding, delay=True)

  def _open(self):
    """Opens the compressed log file.

    Returns
      file: file-like object of the resulting stream.
    """
    return gzip.open(self.baseFilename, mode=self.mode, encoding=self.encoding)


def ConfigureLogging(
    debug_output=False, filename=None, mode='w', quiet_mode=False):
  """Configures the logging root logger.

  Args:
    debug_output (Optional[bool]): True if the logging should include debug
        output.
    filename (Optional[str]): log filename.
    mode (Optional[str]): log file access mode.
    quiet_mode (Optional[bool]): True if the logging should not include
        information output. Note that debug_output takes precedence over
        quiet_mode.
  """
  # Remove all possible log handlers. The log handlers cannot be reconfigured
  # and therefore must be recreated.
  for handler in logging.root.handlers:
    logging.root.removeHandler(handler)

  logger = logging.getLogger()

  if filename and filename.endswith('.gz'):
    handler = CompressedFileHandler(filename, mode=mode)
  elif filename:
    handler = logging.FileHandler(filename, mode=mode)
  else:
    handler = logging.StreamHandler()

  format_string = (
      '%(asctime)s [%(levelname)s] (%(processName)-10s) PID:%(process)d '
      '<%(module)s> %(message)s')

  formatter = logging.Formatter(format_string)
  handler.setFormatter(formatter)

  if debug_output:
    level = logging.DEBUG
  elif quiet_mode:
    level = logging.WARNING
  else:
    level = logging.INFO

  logger.setLevel(level)
  handler.setLevel(level)

  logger.addHandler(handler)
