# Copyright 2011 The Emscripten Authors.  All rights reserved.
# Emscripten is available under two separate licenses, the MIT license and the
# University of Illinois/NCSA Open Source License.  Both these licenses can be
# found in the LICENSE file.

"""Simple color-enabled diagnositics reporting functions.
"""

import ctypes
import logging
import os
import sys


WINDOWS = sys.platform.startswith('win')

logger = logging.getLogger('diagnostics')
color_enabled = sys.stderr.isatty()
tool_name = os.path.splitext(os.path.basename(sys.argv[0]))[0]

# diagnostic levels
WARN = 1
ERROR = 2
FATAL = 3

# available colors
RED = 1
GREEN = 2
YELLOW = 3
BLUE = 4
MAGENTA = 5
CYAN = 6
WHITE = 7

# color for use for each diagnostic level
level_colors = {
    WARN: MAGENTA,
    ERROR: RED,
}

level_prefixes = {
    WARN: 'warning: ',
    ERROR: 'error: ',
}

# Constants from the Windows API
STD_OUTPUT_HANDLE = -11


def output_color_windows(color):
  # TODO(sbc): This code is duplicated in colored_logger.py.  Refactor.
  # wincon.h
  FOREGROUND_BLACK     = 0x0000 # noqa
  FOREGROUND_BLUE      = 0x0001 # noqa
  FOREGROUND_GREEN     = 0x0002 # noqa
  FOREGROUND_CYAN      = 0x0003 # noqa
  FOREGROUND_RED       = 0x0004 # noqa
  FOREGROUND_MAGENTA   = 0x0005 # noqa
  FOREGROUND_YELLOW    = 0x0006 # noqa
  FOREGROUND_GREY      = 0x0007 # noqa

  color_map = {
    RED: FOREGROUND_RED,
    GREEN: FOREGROUND_GREEN,
    YELLOW: FOREGROUND_YELLOW,
    BLUE: FOREGROUND_BLUE,
    MAGENTA: FOREGROUND_MAGENTA,
    CYAN: FOREGROUND_CYAN,
    WHITE: FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED
  }

  sys.stderr.flush()
  hdl = ctypes.windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
  ctypes.windll.kernel32.SetConsoleTextAttribute(hdl, color_map[color])


def get_color_windows():
  SHORT = ctypes.c_short
  WORD = ctypes.c_ushort

  class COORD(ctypes.Structure):
    _fields_ = [
      ("X", SHORT),
      ("Y", SHORT)]

  class SMALL_RECT(ctypes.Structure):
    _fields_ = [
      ("Left", SHORT),
      ("Top", SHORT),
      ("Right", SHORT),
      ("Bottom", SHORT)]

  class CONSOLE_SCREEN_BUFFER_INFO(ctypes.Structure):
    _fields_ = [
      ("dwSize", COORD),
      ("dwCursorPosition", COORD),
      ("wAttributes", WORD),
      ("srWindow", SMALL_RECT),
      ("dwMaximumWindowSize", COORD)]

  hdl = ctypes.windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
  csbi = CONSOLE_SCREEN_BUFFER_INFO()
  ctypes.windll.kernel32.GetConsoleScreenBufferInfo(hdl, ctypes.byref(csbi))
  return csbi.wAttributes


def reset_color_windows():
  sys.stderr.flush()
  hdl = ctypes.windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)
  ctypes.windll.kernel32.SetConsoleTextAttribute(hdl, default_color)


def output_color(color):
  if WINDOWS:
    return output_color_windows(color)
  return '\033[3%sm' % color


def reset_color():
  if WINDOWS:
    return reset_color_windows()
  return '\033[0m'


def diag(level, msg, *args):
  # Format output message as:
  # <tool>: <level>: msg
  # With the `<level>:` part being colored accordingly.
  sys.stderr.write(tool_name + ': ')

  if color_enabled:
    output = output_color(level_colors[level])
    if output:
      sys.stderr.write(output)

  sys.stderr.write(level_prefixes[level])

  if color_enabled:
    output = reset_color()
    if output:
      sys.stderr.write(output)

  if args:
    msg = msg % args
  sys.stderr.write(str(msg))
  sys.stderr.write('\n')


def error(msg, *args):
  diag(ERROR, msg, *args)
  sys.exit(1)


def warn(msg, *args):
  diag(WARN, msg, *args)


class WarningManager:
  warnings = {}

  def add_warning(self, name, enabled=True, part_of_all=True, shared=False, error=False):
    self.warnings[name] = {
      'enabled': enabled,
      'part_of_all': part_of_all,
      # True for flags that are shared with the underlying clang driver
      'shared': shared,
      'error': error,
    }

  def capture_warnings(self, cmd_args):
    for i in range(len(cmd_args)):
      if cmd_args[i] == '-w':
        for warning in self.warnings.values():
          warning['enabled'] = False
        continue

      if not cmd_args[i].startswith('-W'):
        continue

      if cmd_args[i] == '-Wall':
        for warning in self.warnings.values():
          if warning['part_of_all']:
            warning['enabled'] = True
        continue

      if cmd_args[i] == '-Werror':
        for warning in self.warnings.values():
          warning['error'] = True
        continue

      if cmd_args[i].startswith('-Werror=') or cmd_args[i].startswith('-Wno-error='):
        warning_name = cmd_args[i].split('=', 1)[1]
        if warning_name in self.warnings:
          enabled = not cmd_args[i].startswith('-Wno-')
          self.warnings[warning_name]['error'] = enabled
          if enabled:
            self.warnings[warning_name]['enabled'] = True
          cmd_args[i] = ''
          continue

      warning_name = cmd_args[i].replace('-Wno-', '').replace('-W', '')
      enabled = not cmd_args[i].startswith('-Wno-')

      # special case pre-existing warn-absolute-paths
      if warning_name == 'warn-absolute-paths':
        self.warnings['absolute-paths']['enabled'] = enabled
        cmd_args[i] = ''
        continue

      if warning_name in self.warnings:
        self.warnings[warning_name]['enabled'] = enabled
        if not self.warnings[warning_name]['shared']:
          cmd_args[i] = ''
        continue

    return cmd_args

  def warning(self, warning_type, message, *args):
    warning_info = self.warnings[warning_type]
    msg = (message % args) + ' [-W' + warning_type.lower().replace('_', '-') + ']'
    if warning_info['enabled']:
      if warning_info['error']:
        error(msg + ' [-Werror]')
      else:
        warn(msg)
    else:
      logger.debug('disabled warning: ' + msg)


def add_warning(name, enabled=True, part_of_all=True, shared=False, error=False):
  manager.add_warning(name, enabled, part_of_all, shared, error)


def enable_warning(name, as_error=False):
  manager.warnings[name]['enabled'] = True
  if as_error:
    manager.warnings[name]['error'] = True


def disable_warning(name):
  manager.warnings[name]['enabled'] = False


def warning(warning_type, message, *args):
  manager.warning(warning_type, message, *args)


def capture_warnings(argv):
  return manager.capture_warnings(argv)


if WINDOWS:
  default_color = get_color_windows()

manager = WarningManager()
